veloren/voxygen/src/scene/camera.rs

252 lines
7.8 KiB
Rust
Raw Normal View History

2019-06-26 10:50:55 +00:00
use common::vol::{ReadVol, Vox};
use std::f32::consts::PI;
2020-01-08 17:09:54 +00:00
use treeculler::Frustum;
use vek::*;
const NEAR_PLANE: f32 = 0.5;
2019-11-20 09:59:27 +00:00
const FAR_PLANE: f32 = 100000.0;
const FIRST_PERSON_INTERP_TIME: f32 = 0.1;
const THIRD_PERSON_INTERP_TIME: f32 = 0.1;
pub const MIN_ZOOM: f32 = 0.1;
2019-07-22 19:11:00 +00:00
// Possible TODO: Add more modes
#[derive(PartialEq, Clone, Copy, Eq, Hash)]
2019-07-22 19:11:00 +00:00
pub enum CameraMode {
2020-04-04 19:36:55 +00:00
FirstPerson = 0,
ThirdPerson = 1,
2019-07-22 19:11:00 +00:00
}
impl Default for CameraMode {
fn default() -> Self { Self::ThirdPerson }
}
#[derive(Clone)]
pub struct Dependents {
pub view_mat: Mat4<f32>,
pub proj_mat: Mat4<f32>,
pub cam_pos: Vec3<f32>,
}
pub struct Camera {
tgt_focus: Vec3<f32>,
focus: Vec3<f32>,
ori: Vec3<f32>,
2019-07-25 10:26:25 +00:00
tgt_dist: f32,
dist: f32,
fov: f32,
aspect: f32,
2019-07-22 19:11:00 +00:00
mode: CameraMode,
last_time: Option<f64>,
dependents: Dependents,
}
impl Camera {
/// Create a new `Camera` with default parameters.
2019-07-22 19:11:00 +00:00
pub fn new(aspect: f32, mode: CameraMode) -> Self {
Self {
tgt_focus: Vec3::unit_z() * 10.0,
focus: Vec3::unit_z() * 10.0,
ori: Vec3::zero(),
tgt_dist: 10.0,
dist: 10.0,
fov: 1.1,
aspect,
2019-07-22 19:11:00 +00:00
mode,
last_time: None,
dependents: Dependents {
view_mat: Mat4::identity(),
proj_mat: Mat4::identity(),
cam_pos: Vec3::zero(),
},
}
}
/// Compute the transformation matrices (view matrix and projection matrix)
/// and position of the camera.
pub fn compute_dependents(&mut self, terrain: &impl ReadVol) {
let dist = {
let (start, end) = (
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),
2019-06-26 10:50:55 +00:00
self.focus,
);
match terrain
.ray(start, end)
.ignore_error()
.max_iter(500)
2019-06-26 10:50:55 +00:00
.until(|b| b.is_empty())
.cast()
{
2019-06-26 10:50:55 +00:00
(d, Ok(Some(_))) => f32::min(self.dist - d - 0.03, self.dist),
(_, Ok(None)) => self.dist,
(_, Err(_)) => self.dist,
}
.max(0.0)
};
self.dependents.view_mat = Mat4::<f32>::identity()
* Mat4::translation_3d(-Vec3::unit_z() * dist)
* Mat4::rotation_z(self.ori.z)
* Mat4::rotation_x(self.ori.y)
* Mat4::rotation_y(self.ori.x)
* Mat4::rotation_3d(PI / 2.0, -Vec4::unit_x())
* Mat4::translation_3d(-self.focus);
self.dependents.proj_mat =
Mat4::perspective_rh_no(self.fov, self.aspect, NEAR_PLANE, FAR_PLANE);
// TODO: Make this more efficient.
self.dependents.cam_pos = Vec3::from(self.dependents.view_mat.inverted() * Vec4::unit_w());
}
pub fn frustum(&self) -> Frustum<f32> {
Frustum::from_modelview_projection(
(self.dependents.proj_mat * self.dependents.view_mat).into_col_arrays(),
)
}
pub fn dependents(&self) -> Dependents { self.dependents.clone() }
/// Rotate the camera about its focus by the given delta, limiting the input
/// accordingly.
pub fn rotate_by(&mut self, delta: Vec3<f32>) {
// Wrap camera yaw
self.ori.x = (self.ori.x + delta.x) % (2.0 * PI);
// Clamp camera pitch to the vertical limits
self.ori.y = (self.ori.y + delta.y).min(PI / 2.0).max(-PI / 2.0);
// Wrap camera roll
self.ori.z = (self.ori.z + delta.z) % (2.0 * PI);
}
/// Set the orientation of the camera about its focus.
pub fn set_orientation(&mut self, orientation: Vec3<f32>) {
// Wrap camera yaw
self.ori.x = orientation.x % (2.0 * PI);
// Clamp camera pitch to the vertical limits
self.ori.y = orientation.y.min(PI / 2.0).max(-PI / 2.0);
// Wrap camera roll
self.ori.z = orientation.z % (2.0 * PI);
}
/// Zoom the camera by the given delta, limiting the input accordingly.
pub fn zoom_by(&mut self, delta: f32) {
2019-07-25 10:26:25 +00:00
match self.mode {
CameraMode::ThirdPerson => {
// Clamp camera dist to the 2 <= x <= infinity range
self.tgt_dist = (self.tgt_dist + delta).max(2.0);
},
CameraMode::FirstPerson => {},
2019-07-25 10:26:25 +00:00
};
}
2019-08-13 17:54:13 +00:00
/// Zoom with the ability to switch between first and third-person mode.
pub fn zoom_switch(&mut self, delta: f32) {
if delta > 0_f32 || self.mode != CameraMode::FirstPerson {
let t = self.tgt_dist + delta;
match self.mode {
CameraMode::ThirdPerson => {
2019-10-09 19:28:05 +00:00
if t < 1_f32 {
2019-08-13 17:54:13 +00:00
self.set_mode(CameraMode::FirstPerson);
} else {
self.tgt_dist = t;
}
},
2019-08-13 17:54:13 +00:00
CameraMode::FirstPerson => {
self.set_mode(CameraMode::ThirdPerson);
self.tgt_dist = 1_f32;
},
2019-08-13 17:54:13 +00:00
}
}
}
2019-06-10 10:50:48 +00:00
/// Get the distance of the camera from the target
pub fn get_distance(&self) -> f32 { self.tgt_dist }
2019-06-10 10:50:48 +00:00
/// Set the distance of the camera from the target (i.e., zoom).
pub fn set_distance(&mut self, dist: f32) { self.tgt_dist = dist; }
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) / self.interp_time(),
);
}
if (self.focus - self.tgt_focus).magnitude() > 0.01 {
self.focus = Vec3::lerp(
self.focus,
self.tgt_focus,
(delta as f32) / self.interp_time(),
);
}
}
pub fn interp_time(&self) -> f32 {
match self.mode {
CameraMode::FirstPerson => FIRST_PERSON_INTERP_TIME,
CameraMode::ThirdPerson => THIRD_PERSON_INTERP_TIME,
}
}
/// Get the focus position of the camera.
pub fn get_focus_pos(&self) -> Vec3<f32> { self.focus }
/// Set the focus position of the camera.
pub fn set_focus_pos(&mut self, focus: Vec3<f32>) { self.tgt_focus = focus; }
2019-01-23 22:39:31 +00:00
/// Get the aspect ratio of the camera.
pub fn get_aspect_ratio(&self) -> f32 { self.aspect }
2019-01-23 22:39:31 +00:00
/// Set the aspect ratio of the camera.
pub fn set_aspect_ratio(&mut self, aspect: f32) {
self.aspect = if aspect.is_normal() { aspect } else { 1.0 };
}
/// Get the orientation of the camera.
pub fn get_orientation(&self) -> Vec3<f32> { self.ori }
/// Get the field of view of the camera in radians.
pub fn get_fov(&self) -> f32 { self.fov }
2019-07-22 19:11:00 +00:00
2019-08-05 16:37:52 +00:00
/// Set the field of view of the camera in radians.
pub fn set_fov(&mut self, fov: f32) { self.fov = fov; }
2019-08-05 16:37:52 +00:00
/// Set the FOV in degrees
pub fn set_fov_deg(&mut self, fov: u16) {
//Magic value comes from pi/180; no use recalculating.
2019-08-05 16:37:52 +00:00
self.set_fov((fov as f32) * 0.01745329)
}
2019-07-22 19:11:00 +00:00
/// Set the mode of the camera.
pub fn set_mode(&mut self, mode: CameraMode) {
2019-07-25 10:26:25 +00:00
if self.mode != mode {
self.mode = mode;
match self.mode {
CameraMode::ThirdPerson => {
self.zoom_by(5.0);
},
2019-07-25 10:26:25 +00:00
CameraMode::FirstPerson => {
self.set_distance(MIN_ZOOM);
},
2019-07-24 14:27:13 +00:00
}
2019-07-22 19:11:00 +00:00
}
}
2019-07-25 10:26:25 +00:00
/// Get the mode of the camera
pub fn get_mode(&self) -> CameraMode { self.mode }
}