easy_gltf/scene/
camera.rs

1use cgmath::*;
2use gltf::camera::Projection as GltfProjection;
3
4/// Contains camera properties.
5#[derive(Clone, Debug)]
6pub struct Camera {
7    #[cfg(feature = "names")]
8    /// Camera name. Requires the `names` feature.
9    pub name: Option<String>,
10
11    #[cfg(feature = "extras")]
12    /// Scene extra data. Requires the `extras` feature.
13    pub extras: gltf::json::extras::Extras,
14
15    /// Transform matrix (also called world to camera matrix)
16    pub transform: Matrix4<f32>,
17
18    /// Projection type and specific parameters
19    pub projection: Projection,
20
21    /// The distance to the far clipping plane.
22    ///
23    /// For perspective projection, this may be infinite.
24    pub zfar: f32,
25
26    /// The distance to the near clipping plane.
27    pub znear: f32,
28}
29
30/// Camera projections
31#[derive(Debug, Clone)]
32pub enum Projection {
33    /// Perspective projection
34    Perspective {
35        /// Y-axis FOV, in radians
36        yfov: Rad<f32>,
37        /// Aspect ratio, if specified
38        aspect_ratio: Option<f32>,
39    },
40    /// Orthographic projection
41    Orthographic {
42        /// Projection scale
43        scale: Vector2<f32>,
44    },
45}
46impl Default for Projection {
47    fn default() -> Self {
48        Self::Perspective {
49            yfov: Rad(0.399),
50            aspect_ratio: None,
51        }
52    }
53}
54
55impl Camera {
56    /// Position of the camera.
57    pub fn position(&self) -> Vector3<f32> {
58        Vector3::new(
59            self.transform[3][0],
60            self.transform[3][1],
61            self.transform[3][2],
62        )
63    }
64
65    /// Right vector of the camera.
66    pub fn right(&self) -> Vector3<f32> {
67        Vector3::new(
68            self.transform[0][0],
69            self.transform[0][1],
70            self.transform[0][2],
71        )
72        .normalize()
73    }
74
75    /// Up vector of the camera.
76    pub fn up(&self) -> Vector3<f32> {
77        Vector3::new(
78            self.transform[1][0],
79            self.transform[1][1],
80            self.transform[1][2],
81        )
82        .normalize()
83    }
84
85    /// Forward vector of the camera (backside direction).
86    pub fn forward(&self) -> Vector3<f32> {
87        Vector3::new(
88            self.transform[2][0],
89            self.transform[2][1],
90            self.transform[2][2],
91        )
92        .normalize()
93    }
94
95    /// Apply the transformation matrix on a vector.
96    ///
97    /// # Example
98    /// ```
99    /// # use easy_gltf::Camera;
100    /// # use cgmath::*;
101    /// # let cam = Camera::default();
102    /// let ray_dir = Vector3::new(1., 0., 0.);
103    /// let ray_dir = cam.apply_transform_vector(&ray_dir);
104    /// ```
105    pub fn apply_transform_vector(&self, pos: &Vector3<f32>) -> Vector3<f32> {
106        let pos = Vector4::new(pos[0], pos[1], pos[2], 0.);
107        (self.transform * pos).truncate()
108    }
109
110    pub(crate) fn load(gltf_cam: gltf::Camera, transform: &Matrix4<f32>) -> Self {
111        let mut cam = Self {
112            transform: *transform,
113            ..Default::default()
114        };
115
116        #[cfg(feature = "names")]
117        {
118            cam.name = gltf_cam.name().map(String::from);
119        }
120        #[cfg(feature = "extras")]
121        {
122            cam.extras = gltf_cam.extras().clone();
123        }
124
125        match gltf_cam.projection() {
126            GltfProjection::Orthographic(ortho) => {
127                cam.projection = Projection::Orthographic {
128                    scale: Vector2::new(ortho.xmag(), ortho.ymag()),
129                };
130                cam.zfar = ortho.zfar();
131                cam.znear = ortho.znear();
132            }
133            GltfProjection::Perspective(pers) => {
134                cam.projection = Projection::Perspective {
135                    yfov: Rad(pers.yfov()),
136                    aspect_ratio: pers.aspect_ratio(),
137                };
138                cam.zfar = pers.zfar().unwrap_or(f32::INFINITY);
139                cam.znear = pers.znear();
140            }
141        };
142        cam
143    }
144}
145
146impl Default for Camera {
147    fn default() -> Self {
148        Camera {
149            #[cfg(feature = "names")]
150            name: None,
151            #[cfg(feature = "extras")]
152            extras: None,
153            transform: Zero::zero(),
154            projection: Projection::default(),
155            zfar: f32::INFINITY,
156            znear: 0.,
157        }
158    }
159}