mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Smoother and terrain-aware camera
Former-commit-id: 46b4e90d03792c9efb7d6b728c0d0cd60b1f5058
This commit is contained in:
parent
aa9c01af35
commit
647d1dcc9c
@ -38,22 +38,28 @@ impl<'a, V: ReadVol, F: RayUntil<V::Vox>> Ray<'a, V, F> {
|
|||||||
|
|
||||||
let mut dist = 0.0;
|
let mut dist = 0.0;
|
||||||
let dir = (self.to - self.from).normalized();
|
let dir = (self.to - self.from).normalized();
|
||||||
|
let max = (self.to - self.from).magnitude();
|
||||||
|
|
||||||
let mut pos = self.from;
|
let mut pos = self.from;
|
||||||
let mut ipos = pos.map(|e| e as i32);
|
let mut ipos = pos.map(|e| e.floor() as i32);
|
||||||
|
|
||||||
for _ in 0..self.max_iter {
|
for _ in 0..self.max_iter {
|
||||||
pos = self.from + dir * dist;
|
pos = self.from + dir * dist;
|
||||||
ipos = pos.map(|e| e as i32);
|
ipos = pos.map(|e| e.floor() as i32);
|
||||||
|
|
||||||
match self.vol.get(ipos).map(|vox| (vox, (self.until)(vox))) {
|
match self.vol.get(ipos).map(|vox| (vox, (self.until)(vox))) {
|
||||||
Ok((vox, true)) => return (dist, Ok(Some(vox))),
|
Ok((vox, true)) => return (dist, Ok(Some(vox))),
|
||||||
Ok((_, false)) => {}
|
Ok((_, false)) => {},
|
||||||
Err(err) => return (dist, Err(err)),
|
Err(err) => return (dist, Err(err)),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allow one iteration above max
|
||||||
|
if dist > max {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
let deltas =
|
let deltas =
|
||||||
(dir.map(|e| if e < 0.0 { 0.0 } else { 1.0 }) - pos.map(|e| e.fract())) / dir;
|
(dir.map(|e| if e < 0.0 { 0.0 } else { 1.0 }) - pos.map(|e| e.abs().fract())) / dir;
|
||||||
|
|
||||||
dist += deltas.reduce(f32::min).max(PLANCK);
|
dist += deltas.reduce(f32::min).max(PLANCK);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
use client::Client;
|
||||||
|
|
||||||
|
use common::vol::{ReadVol, SampleVol};
|
||||||
|
|
||||||
// Standard
|
// Standard
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
@ -7,31 +11,59 @@ use vek::*;
|
|||||||
const NEAR_PLANE: f32 = 0.1;
|
const NEAR_PLANE: f32 = 0.1;
|
||||||
const FAR_PLANE: f32 = 10000.0;
|
const FAR_PLANE: f32 = 10000.0;
|
||||||
|
|
||||||
|
const INTERP_TIME: f32 = 0.2;
|
||||||
|
|
||||||
pub struct Camera {
|
pub struct Camera {
|
||||||
|
tgt_focus: Vec3<f32>,
|
||||||
focus: Vec3<f32>,
|
focus: Vec3<f32>,
|
||||||
ori: Vec3<f32>,
|
ori: Vec3<f32>,
|
||||||
|
tgt_dist: f32,
|
||||||
dist: f32,
|
dist: f32,
|
||||||
fov: f32,
|
fov: f32,
|
||||||
aspect: f32,
|
aspect: f32,
|
||||||
|
|
||||||
|
last_time: Option<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Camera {
|
impl Camera {
|
||||||
/// Create a new `Camera` with default parameters.
|
/// Create a new `Camera` with default parameters.
|
||||||
pub fn new(aspect: f32) -> Self {
|
pub fn new(aspect: f32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
tgt_focus: Vec3::unit_z() * 10.0,
|
||||||
focus: Vec3::unit_z() * 10.0,
|
focus: Vec3::unit_z() * 10.0,
|
||||||
ori: Vec3::zero(),
|
ori: Vec3::zero(),
|
||||||
|
tgt_dist: 10.0,
|
||||||
dist: 10.0,
|
dist: 10.0,
|
||||||
fov: 1.3,
|
fov: 1.3,
|
||||||
aspect,
|
aspect,
|
||||||
|
last_time: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute the transformation matrices (view matrix and projection matrix) and position of the
|
/// Compute the transformation matrices (view matrix and projection matrix) and position of the
|
||||||
/// camera.
|
/// camera.
|
||||||
pub fn compute_dependents(&self) -> (Mat4<f32>, Mat4<f32>, Vec3<f32>) {
|
pub fn compute_dependents(&self, client: &Client) -> (Mat4<f32>, Mat4<f32>, Vec3<f32>) {
|
||||||
|
let dist = {
|
||||||
|
let (start, end) = (
|
||||||
|
self.focus,
|
||||||
|
self.focus
|
||||||
|
+ (Vec3::new(
|
||||||
|
-f32::sin(self.ori.x) * f32::cos(self.ori.y),
|
||||||
|
-f32::cos(self.ori.x) * f32::cos(self.ori.y),
|
||||||
|
f32::sin(self.ori.y),
|
||||||
|
) * self.dist),
|
||||||
|
);
|
||||||
|
|
||||||
|
match client.state().terrain().ray(start, end).cast() {
|
||||||
|
(d, Ok(Some(_))) => f32::min(d - 1.0, self.dist),
|
||||||
|
(_, Ok(None)) => self.dist,
|
||||||
|
(_, Err(_)) => self.dist,
|
||||||
|
}.max(0.0)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
let view_mat = Mat4::<f32>::identity()
|
let view_mat = Mat4::<f32>::identity()
|
||||||
* Mat4::translation_3d(-Vec3::unit_z() * self.dist)
|
* Mat4::translation_3d(-Vec3::unit_z() * dist)
|
||||||
* Mat4::rotation_z(self.ori.z)
|
* Mat4::rotation_z(self.ori.z)
|
||||||
* Mat4::rotation_x(self.ori.y)
|
* Mat4::rotation_x(self.ori.y)
|
||||||
* Mat4::rotation_y(self.ori.x)
|
* Mat4::rotation_y(self.ori.x)
|
||||||
@ -59,16 +91,28 @@ impl Camera {
|
|||||||
/// Zoom the camera by the given delta, limiting the input accordingly.
|
/// Zoom the camera by the given delta, limiting the input accordingly.
|
||||||
pub fn zoom_by(&mut self, delta: f32) {
|
pub fn zoom_by(&mut self, delta: f32) {
|
||||||
// Clamp camera dist to the 0 <= x <= infinity range
|
// Clamp camera dist to the 0 <= x <= infinity range
|
||||||
self.dist = (self.dist + delta).max(0.0);
|
self.tgt_dist = (self.tgt_dist + delta).max(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&mut self, time: f64) {
|
||||||
|
// This is horribly frame time dependent, but so is most of the game
|
||||||
|
let delta = self.last_time.replace(time).map_or(0.0, |t| time - t);
|
||||||
|
if (self.dist - self.tgt_dist).abs() > 0.01 {
|
||||||
|
self.dist = f32::lerp(self.dist, self.tgt_dist, (delta as f32) / INTERP_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.focus - self.tgt_focus).magnitude() > 0.01 {
|
||||||
|
self.focus = Vec3::lerp(self.focus, self.tgt_focus, (delta as f32) / INTERP_TIME);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the focus position of the camera.
|
/// Get the focus position of the camera.
|
||||||
pub fn get_focus_pos(&self) -> Vec3<f32> {
|
pub fn get_focus_pos(&self) -> Vec3<f32> {
|
||||||
self.focus
|
self.tgt_focus
|
||||||
}
|
}
|
||||||
/// Set the focus position of the camera.
|
/// Set the focus position of the camera.
|
||||||
pub fn set_focus_pos(&mut self, focus: Vec3<f32>) {
|
pub fn set_focus_pos(&mut self, focus: Vec3<f32>) {
|
||||||
self.focus = focus;
|
self.tgt_focus = focus;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the aspect ratio of the camera.
|
/// Get the aspect ratio of the camera.
|
||||||
|
@ -103,10 +103,13 @@ impl Scene {
|
|||||||
.unwrap_or(Vec3::zero());
|
.unwrap_or(Vec3::zero());
|
||||||
|
|
||||||
// Alter camera position to match player
|
// Alter camera position to match player
|
||||||
self.camera.set_focus_pos(player_pos + Vec3::unit_z() * 1.5);
|
self.camera.set_focus_pos(player_pos + Vec3::unit_z() * 3.5);
|
||||||
|
|
||||||
|
// Tick camera for interpolation
|
||||||
|
self.camera.update(client.state().get_time());
|
||||||
|
|
||||||
// Compute camera matrices
|
// Compute camera matrices
|
||||||
let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents();
|
let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents(client);
|
||||||
|
|
||||||
// Update global constants
|
// Update global constants
|
||||||
renderer
|
renderer
|
||||||
|
Loading…
Reference in New Issue
Block a user