cam/
camera.rs

1
2//! A 3D camera.
3
4use vecmath::{
5    Vector3,
6    Matrix4,
7    vec3_normalized_sub,
8    vec3_cross,
9    vec3_dot,
10};
11use vecmath::col_mat4_mul as mul;
12use vecmath::traits::*;
13use quaternion::{Quaternion, rotate_vector};
14
15/// Computes a model view projection matrix.
16pub fn model_view_projection<T: Float + Copy>(
17    model: Matrix4<T>,
18    view: Matrix4<T>,
19    projection: Matrix4<T>
20) -> Matrix4<T> {
21    mul(mul(projection, view), model)
22}
23
24/// Models a camera with position and directions.
25#[derive(Clone, Debug, PartialEq, PartialOrd, Hash)]
26pub struct Camera<T=f32> {
27    /// The camera position.
28    pub position: Vector3<T>,
29    /// The up direction.
30    pub up: Vector3<T>,
31    /// The right direction.
32    pub right: Vector3<T>,
33    /// The forward direction.
34    pub forward: Vector3<T>
35}
36
37/// Models camera perspective settings.
38#[derive(Clone, Debug, PartialEq, PartialOrd, Hash)]
39pub struct CameraPerspective<T=f32> {
40    /// Field of view (in degrees).
41    pub fov: T,
42    /// The near clip distance.
43    pub near_clip: T,
44    /// The far clip distance.
45    pub far_clip: T,
46    /// The aspect ratio, usually set to 1.0.
47    pub aspect_ratio: T,
48}
49
50impl<T: Float + Copy> Camera<T> {
51    /// Constructs a new camera.
52    ///
53    /// Places the camera at [x, y, z], looking towards pozitive z.
54    pub fn new(position: Vector3<T>) -> Camera<T> {
55        let _0 = Zero::zero();
56        let _1 = One::one();
57        Camera {
58            position: position,
59            right:   [_1, _0, _0],
60            up:      [_0, _1, _0],
61            forward: [_0, _0, _1]
62        }
63    }
64
65    /// Computes an orthogonal matrix for the camera.
66    ///
67    /// This matrix can be used to transform coordinates to the screen.
68    pub fn orthogonal(&self) -> Matrix4<T> {
69        let p = self.position;
70        let r = self.right;
71        let u = self.up;
72        let f = self.forward;
73        let _0 = Zero::zero();
74        [
75            [r[0], u[0], f[0], _0],
76            [r[1], u[1], f[1], _0],
77            [r[2], u[2], f[2], _0],
78            [-vec3_dot(r, p), -vec3_dot(u, p), -vec3_dot(f, p), One::one()]
79        ]
80    }
81
82    /// Orients the camera to look at a point.
83    pub fn look_at(&mut self, point: Vector3<T>) {
84        self.forward = vec3_normalized_sub(point, self.position);
85        self.update_right();
86    }
87
88    /// Sets yaw and pitch angle of camera in radians.
89    pub fn set_yaw_pitch(&mut self, yaw: T, pitch: T) {
90        let (y_s, y_c, p_s, p_c) = (yaw.sin(), yaw.cos(), pitch.sin(), pitch.cos());
91        self.forward = [y_s * p_c, p_s, y_c * p_c];
92        self.up = [y_s * -p_s, p_c, y_c * -p_s];
93        self.update_right();
94    }
95
96    /// Sets forward, up, and right vectors from a Quaternion rotation
97    /// relative to the positive z-axis
98    pub fn set_rotation(&mut self, rotation: Quaternion<T>)
99    {
100        let _0: T = Zero::zero();
101        let _1: T = One::one();
102        let forward: Vector3<T> = [_0, _0, _1];
103        let up: Vector3<T> = [_0, _1, _0];
104        self.forward = rotate_vector(rotation, forward);
105        self.up = rotate_vector(rotation, up);
106        self.update_right();
107    }
108
109    fn update_right(&mut self) {
110        self.right = vec3_cross(self.up, self.forward);
111    }
112}
113
114impl<T: Float> CameraPerspective<T>
115    where f64: Cast<T>
116{
117    /// Computes a projection matrix for the camera perspective.
118    pub fn projection(&self) -> Matrix4<T> {
119        let _0: T = Zero::zero();
120        let _1: T = One::one();
121        let _2: T = _1 + _1;
122        let pi: T = Radians::_180();
123        let _360: T = Cast::cast(360.0f64);
124        let f = _1 / (self.fov * (pi / _360)).tan();
125        let (far, near) = (self.far_clip, self.near_clip);
126        [
127            [f / self.aspect_ratio, _0, _0, _0],
128            [_0, f, _0, _0],
129            [_0, _0, (far + near) / (near - far), -_1],
130            [_0, _0, (_2 * far * near) / (near - far), _0]
131        ]
132    }
133}