[go: up one dir, main page]

gltf/scene/
mod.rs

1#[cfg(feature = "extensions")]
2use serde_json::{Map, Value};
3
4use crate::math::*;
5use crate::{Camera, Document, Mesh, Skin};
6
7/// Iterators.
8pub mod iter;
9
10/// The transform for a `Node`.
11#[derive(Clone, Debug)]
12pub enum Transform {
13    /// 4x4 transformation matrix in column-major order.
14    Matrix {
15        /// 4x4 matrix.
16        matrix: [[f32; 4]; 4],
17    },
18
19    /// Decomposed TRS properties.
20    Decomposed {
21        /// `[x, y, z]` vector.
22        translation: [f32; 3],
23
24        /// `[x, y, z, w]` quaternion, where `w` is the scalar.
25        rotation: [f32; 4],
26
27        /// `[x, y, z]` vector.
28        scale: [f32; 3],
29    },
30}
31
32impl Transform {
33    /// Returns the matrix representation of this transform.
34    ///
35    /// If the transform is `Decomposed`, then the matrix is generated with the
36    /// equation `matrix = translation * rotation * scale`.
37    pub fn matrix(self) -> [[f32; 4]; 4] {
38        match self {
39            Transform::Matrix { matrix } => matrix,
40            Transform::Decomposed {
41                translation: t,
42                rotation: r,
43                scale: s,
44            } => {
45                let t = Matrix4::from_translation(Vector3::new(t[0], t[1], t[2]));
46                let r = Matrix4::from_quaternion(Quaternion::new(r[3], r[0], r[1], r[2]));
47                let s = Matrix4::from_nonuniform_scale(s[0], s[1], s[2]);
48                (t * r * s).as_array()
49            }
50        }
51    }
52
53    /// Returns a decomposed representation of this transform.
54    ///
55    /// If the transform is `Matrix`, then the decomposition is extracted from the
56    /// matrix.
57    pub fn decomposed(self) -> ([f32; 3], [f32; 4], [f32; 3]) {
58        match self {
59            Transform::Matrix { matrix: m } => {
60                let translation = [m[3][0], m[3][1], m[3][2]];
61                #[rustfmt::skip]
62                let mut i = Matrix3::new(
63                    m[0][0], m[0][1], m[0][2],
64                    m[1][0], m[1][1], m[1][2],
65                    m[2][0], m[2][1], m[2][2],
66                );
67                let sx = i.x.magnitude();
68                let sy = i.y.magnitude();
69                let sz = i.determinant().signum() * i.z.magnitude();
70                let scale = [sx, sy, sz];
71                i.x.multiply(1.0 / sx);
72                i.y.multiply(1.0 / sy);
73                i.z.multiply(1.0 / sz);
74                let r = Quaternion::from_matrix(i);
75                let rotation = [r.v.x, r.v.y, r.v.z, r.s];
76                (translation, rotation, scale)
77            }
78            Transform::Decomposed {
79                translation,
80                rotation,
81                scale,
82            } => (translation, rotation, scale),
83        }
84    }
85}
86
87/// A node in the node hierarchy.
88///
89/// When a node contains a skin, all its meshes contain `JOINTS_0` and `WEIGHTS_0`
90/// attributes.
91#[derive(Clone, Debug)]
92pub struct Node<'a> {
93    /// The parent `Document` struct.
94    document: &'a Document,
95
96    /// The corresponding JSON index.
97    index: usize,
98
99    /// The corresponding JSON struct.
100    json: &'a json::scene::Node,
101}
102
103/// The root nodes of a scene.
104#[derive(Clone, Debug)]
105pub struct Scene<'a> {
106    /// The parent `Document` struct.
107    #[allow(dead_code)]
108    document: &'a Document,
109
110    /// The corresponding JSON index.
111    index: usize,
112
113    /// The corresponding JSON struct.
114    json: &'a json::scene::Scene,
115}
116
117impl<'a> Node<'a> {
118    /// Constructs a `Node`.
119    pub(crate) fn new(document: &'a Document, index: usize, json: &'a json::scene::Node) -> Self {
120        Self {
121            document,
122            index,
123            json,
124        }
125    }
126
127    /// Returns the internal JSON index.
128    pub fn index(&self) -> usize {
129        self.index
130    }
131
132    /// Returns the camera referenced by this node.
133    pub fn camera(&self) -> Option<Camera<'a>> {
134        self.json
135            .camera
136            .as_ref()
137            .map(|index| self.document.cameras().nth(index.value()).unwrap())
138    }
139
140    /// Returns an `Iterator` that visits the node's children.
141    pub fn children(&self) -> iter::Children<'a> {
142        iter::Children {
143            document: self.document,
144            iter: self.json.children.as_ref().map_or([].iter(), |x| x.iter()),
145        }
146    }
147
148    /// Returns extension data unknown to this crate version.
149    #[cfg(feature = "extensions")]
150    #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
151    pub fn extensions(&self) -> Option<&Map<String, Value>> {
152        let ext = self.json.extensions.as_ref()?;
153        Some(&ext.others)
154    }
155
156    /// Queries extension data unknown to this crate version.
157    #[cfg(feature = "extensions")]
158    #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
159    pub fn extension_value(&self, ext_name: &str) -> Option<&Value> {
160        let ext = self.json.extensions.as_ref()?;
161        ext.others.get(ext_name)
162    }
163
164    /// Optional application specific data.
165    pub fn extras(&self) -> &'a json::Extras {
166        &self.json.extras
167    }
168
169    /// Returns the light at this node as defined by the `KHR_lights_punctual` extension.
170    #[cfg(feature = "KHR_lights_punctual")]
171    #[cfg_attr(docsrs, doc(cfg(feature = "KHR_lights_punctual")))]
172    pub fn light(&self) -> Option<crate::khr_lights_punctual::Light<'a>> {
173        if let Some(extensions) = self.json.extensions.as_ref() {
174            if let Some(khr_lights_punctual) = extensions.khr_lights_punctual.as_ref() {
175                let mut lights = self.document.lights().unwrap();
176                Some(lights.nth(khr_lights_punctual.light.value()).unwrap())
177            } else {
178                None
179            }
180        } else {
181            None
182        }
183    }
184
185    /// Returns the mesh referenced by this node.
186    pub fn mesh(&self) -> Option<Mesh<'a>> {
187        self.json
188            .mesh
189            .as_ref()
190            .map(|index| self.document.meshes().nth(index.value()).unwrap())
191    }
192
193    /// Optional user-defined name for this object.
194    #[cfg(feature = "names")]
195    pub fn name(&self) -> Option<&'a str> {
196        self.json.name.as_deref()
197    }
198
199    /// Returns the node's transform.
200    pub fn transform(&self) -> Transform {
201        if let Some(m) = self.json.matrix {
202            Transform::Matrix {
203                matrix: [
204                    [m[0], m[1], m[2], m[3]],
205                    [m[4], m[5], m[6], m[7]],
206                    [m[8], m[9], m[10], m[11]],
207                    [m[12], m[13], m[14], m[15]],
208                ],
209            }
210        } else {
211            Transform::Decomposed {
212                translation: self.json.translation.unwrap_or([0.0, 0.0, 0.0]),
213                rotation: self.json.rotation.unwrap_or_default().0,
214                scale: self.json.scale.unwrap_or([1.0, 1.0, 1.0]),
215            }
216        }
217    }
218
219    /// Returns the skin referenced by this node.
220    pub fn skin(&self) -> Option<Skin<'a>> {
221        self.json
222            .skin
223            .as_ref()
224            .map(|index| self.document.skins().nth(index.value()).unwrap())
225    }
226
227    /// Returns the weights of the instantiated morph target.
228    pub fn weights(&self) -> Option<&'a [f32]> {
229        self.json.weights.as_deref()
230    }
231}
232
233impl<'a> Scene<'a> {
234    /// Constructs a `Scene`.
235    pub(crate) fn new(document: &'a Document, index: usize, json: &'a json::scene::Scene) -> Self {
236        Self {
237            document,
238            index,
239            json,
240        }
241    }
242
243    /// Returns the internal JSON index.
244    pub fn index(&self) -> usize {
245        self.index
246    }
247
248    /// Returns extension data unknown to this crate version.
249    #[cfg(feature = "extensions")]
250    #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
251    pub fn extensions(&self) -> Option<&Map<String, Value>> {
252        let ext = self.json.extensions.as_ref()?;
253        Some(&ext.others)
254    }
255
256    /// Queries extension data unknown to this crate version.
257    #[cfg(feature = "extensions")]
258    #[cfg_attr(docsrs, doc(cfg(feature = "extensions")))]
259    pub fn extension_value(&self, ext_name: &str) -> Option<&Value> {
260        let ext = self.json.extensions.as_ref()?;
261        ext.others.get(ext_name)
262    }
263
264    /// Optional application specific data.
265    pub fn extras(&self) -> &'a json::Extras {
266        &self.json.extras
267    }
268
269    /// Optional user-defined name for this object.
270    #[cfg(feature = "names")]
271    pub fn name(&self) -> Option<&'a str> {
272        self.json.name.as_deref()
273    }
274
275    /// Returns an `Iterator` that visits each root node of the scene.
276    pub fn nodes(&self) -> iter::Nodes<'a> {
277        iter::Nodes {
278            document: self.document,
279            iter: self.json.nodes.iter(),
280        }
281    }
282}
283
284#[cfg(test)]
285mod tests {
286    use crate::math::*;
287    use crate::scene::Transform;
288    use std::f32::consts::PI;
289
290    fn rotate(x: f32, y: f32, z: f32, r: f32) -> [f32; 4] {
291        let r = Quaternion::from_axis_angle(Vector3::new(x, y, z).normalize(), r);
292        [r.v.x, r.v.y, r.v.z, r.s]
293    }
294
295    fn test_decompose(translation: [f32; 3], rotation: [f32; 4], scale: [f32; 3]) {
296        let matrix = Transform::Decomposed {
297            translation,
298            rotation,
299            scale,
300        }
301        .matrix();
302        let (translation, rotation, scale) = Transform::Matrix { matrix }.decomposed();
303        let check = Transform::Decomposed {
304            translation,
305            rotation,
306            scale,
307        }
308        .matrix();
309        assert_relative_eq!(
310            Matrix4::from_array(check),
311            Matrix4::from_array(matrix),
312            epsilon = 0.05
313        );
314    }
315
316    fn test_decompose_rotation(rotation: [f32; 4]) {
317        let translation = [1.0, -2.0, 3.0];
318        let scale = [1.0, 1.0, 1.0];
319        test_decompose(translation, rotation, scale);
320    }
321
322    fn test_decompose_scale(scale: [f32; 3]) {
323        let translation = [1.0, 2.0, 3.0];
324        let rotation = rotate(1.0, 0.0, 0.0, PI / 2.0);
325        test_decompose(translation, rotation, scale);
326    }
327
328    fn test_decompose_translation(translation: [f32; 3]) {
329        let rotation = [0.0, 0.0, 0.0, 1.0];
330        let scale = [1.0, 1.0, 1.0];
331        test_decompose(translation, rotation, scale);
332    }
333
334    #[test]
335    fn decompose_identity() {
336        let translation = [0.0, 0.0, 0.0];
337        let rotation = [0.0, 0.0, 0.0, 1.0];
338        let scale = [1.0, 1.0, 1.0];
339        test_decompose(translation, rotation, scale);
340    }
341
342    #[test]
343    fn decompose_translation_unit_x() {
344        let translation = [1.0, 0.0, 0.0];
345        test_decompose_translation(translation);
346    }
347
348    #[test]
349    fn decompose_translation_unit_y() {
350        let translation = [0.0, 1.0, 0.0];
351        test_decompose_translation(translation);
352    }
353
354    #[test]
355    fn decompose_translation_unit_z() {
356        let translation = [0.0, 0.0, 1.0];
357        test_decompose_translation(translation);
358    }
359
360    #[test]
361    fn decompose_translation_random0() {
362        let translation = [1.0, -1.0, 1.0];
363        test_decompose_translation(translation);
364    }
365
366    #[test]
367    fn decompose_translation_random1() {
368        let translation = [-1.0, -1.0, -1.0];
369        test_decompose_translation(translation);
370    }
371
372    #[test]
373    fn decompose_translation_random2() {
374        let translation = [-10.0, 100000.0, -0.0001];
375        test_decompose_translation(translation);
376    }
377
378    #[test]
379    fn decompose_rotation_xaxis() {
380        let rotation = rotate(1.0, 0.0, 0.0, PI / 2.0);
381        test_decompose_rotation(rotation);
382    }
383
384    #[test]
385    fn decompose_rotation_yaxis() {
386        let rotation = rotate(0.0, 1.0, 0.0, PI / 2.0);
387        test_decompose_rotation(rotation);
388    }
389
390    #[test]
391    fn decompose_rotation_zaxis() {
392        let rotation = rotate(0.0, 0.0, 1.0, PI / 2.0);
393        test_decompose_rotation(rotation);
394    }
395
396    #[test]
397    fn decompose_rotation_negative_xaxis() {
398        let rotation = rotate(-1.0, 0.0, 0.0, PI / 2.0);
399        test_decompose_rotation(rotation);
400    }
401
402    #[test]
403    fn decompose_rotation_negative_yaxis() {
404        let rotation = rotate(0.0, -1.0, 0.0, PI / 2.0);
405        test_decompose_rotation(rotation);
406    }
407
408    #[test]
409    fn decompose_rotation_negative_zaxis() {
410        let rotation = rotate(0.0, 0.0, -1.0, PI / 2.0);
411        test_decompose_rotation(rotation);
412    }
413
414    #[test]
415    fn decompose_rotation_eighth_turn() {
416        let rotation = rotate(1.0, 0.0, 0.0, PI / 4.0);
417        test_decompose_rotation(rotation);
418    }
419
420    #[test]
421    fn decompose_rotation_negative_quarter_turn() {
422        let rotation = rotate(0.0, 1.0, 0.0, -PI / 2.0);
423        test_decompose_rotation(rotation);
424    }
425
426    #[test]
427    fn decompose_rotation_half_turn() {
428        let rotation = rotate(0.0, 0.0, 1.0, PI);
429        test_decompose_rotation(rotation);
430    }
431
432    #[test]
433    fn decompose_rotation_zero_turn_xaxis() {
434        let rotation = rotate(1.0, 0.0, 0.0, 0.0);
435        test_decompose_rotation(rotation);
436    }
437
438    #[test]
439    fn decompose_rotation_zero_turn_yaxis() {
440        let rotation = rotate(0.0, 1.0, 0.0, 0.0);
441        test_decompose_rotation(rotation);
442    }
443
444    #[test]
445    fn decompose_rotation_zero_turn_zaxis() {
446        let rotation = rotate(0.0, 0.0, 1.0, 0.0);
447        test_decompose_rotation(rotation);
448    }
449
450    #[test]
451    fn decompose_rotation_full_turn() {
452        let rotation = rotate(1.0, 0.0, 0.0, 2.0 * PI);
453        test_decompose_rotation(rotation);
454    }
455
456    #[test]
457    fn decompose_rotation_random0() {
458        let rotation = rotate(1.0, 1.0, 1.0, PI / 3.0);
459        test_decompose_rotation(rotation);
460    }
461
462    #[test]
463    fn decompose_rotation_random1() {
464        let rotation = rotate(1.0, -1.0, 1.0, -PI / 6.0);
465        test_decompose_rotation(rotation);
466    }
467
468    #[test]
469    fn decompose_uniform_scale_up() {
470        let scale = [100.0, 100.0, 100.0];
471        test_decompose_scale(scale);
472    }
473
474    #[test]
475    fn decompose_uniform_scale_down() {
476        let scale = [0.01, 0.01, 0.01];
477        test_decompose_scale(scale);
478    }
479
480    #[test]
481    fn decompose_xscale_up() {
482        let scale = [100.0, 1.0, 1.0];
483        test_decompose_scale(scale);
484    }
485
486    #[test]
487    fn decompose_xscale_down() {
488        let scale = [0.001, 1.0, 1.0];
489        test_decompose_scale(scale);
490    }
491
492    #[test]
493    fn decompose_yscale_up() {
494        let scale = [1.0, 100.0, 1.0];
495        test_decompose_scale(scale);
496    }
497
498    #[test]
499    fn decompose_yscale_down() {
500        let scale = [1.0, 0.001, 1.0];
501        test_decompose_scale(scale);
502    }
503
504    #[test]
505    fn decompose_zscale_up() {
506        let scale = [1.0, 1.0, 100.0];
507        test_decompose_scale(scale);
508    }
509
510    #[test]
511    fn decompose_zscale_down() {
512        let scale = [1.0, 1.0, 0.001];
513        test_decompose_scale(scale);
514    }
515
516    #[test]
517    fn decompose_negative_xscale_unit() {
518        let scale = [-1.0, 1.0, 1.0];
519        test_decompose_scale(scale);
520    }
521
522    #[test]
523    fn decompose_negative_xscale_up() {
524        let scale = [-10.0, 1.0, 1.0];
525        test_decompose_scale(scale);
526    }
527
528    #[test]
529    fn decompose_negative_xscale_down() {
530        let scale = [-0.1, 1.0, 1.0];
531        test_decompose_scale(scale);
532    }
533
534    #[test]
535    fn decompose_negative_yscale_unit() {
536        let scale = [1.0, -1.0, 1.0];
537        test_decompose_scale(scale);
538    }
539
540    #[test]
541    fn decompose_negative_yscale_up() {
542        let scale = [1.0, -10.0, 1.0];
543        test_decompose_scale(scale);
544    }
545
546    #[test]
547    fn decompose_negative_yscale_down() {
548        let scale = [1.0, -0.1, 1.0];
549        test_decompose_scale(scale);
550    }
551
552    #[test]
553    fn decompose_negative_zscale_unit() {
554        let scale = [1.0, 1.0, -1.0];
555        test_decompose_scale(scale);
556    }
557
558    #[test]
559    fn decompose_negative_zscale_up() {
560        let scale = [1.0, 1.0, -10.0];
561        test_decompose_scale(scale);
562    }
563
564    #[test]
565    fn decompose_negative_zscale_down() {
566        let scale = [1.0, 1.0, -0.1];
567        test_decompose_scale(scale);
568    }
569
570    #[test]
571    fn decompose_nonuniform_scale_up_sml() {
572        let scale = [10.0, 100.0, 1000.0];
573        test_decompose_scale(scale);
574    }
575
576    #[test]
577    fn decompose_nonuniform_scale_up_mls() {
578        let scale = [100.0, 1000.0, 10.0];
579        test_decompose_scale(scale);
580    }
581
582    #[test]
583    fn decompose_nonuniform_scale_up_lsm() {
584        let scale = [1000.0, 10.0, 100.0];
585        test_decompose_scale(scale);
586    }
587
588    #[test]
589    fn decompose_nonuniform_scale_down_sml() {
590        let scale = [0.01, 0.001, 0.0001];
591        test_decompose_scale(scale);
592    }
593
594    #[test]
595    fn decompose_nonuniform_scale_down_mls() {
596        let scale = [0.001, 0.0001, 0.01];
597        test_decompose_scale(scale);
598    }
599
600    #[test]
601    fn decompose_nonuniform_scale_down_lsm() {
602        let scale = [0.0001, 0.01, 0.01];
603        test_decompose_scale(scale);
604    }
605
606    #[test]
607    fn decompose_nonuniform_scale_unit_ls() {
608        let scale = [1.0, 100000.0, 0.000001];
609        test_decompose_scale(scale);
610    }
611
612    #[test]
613    fn decompose_nonuniform_scale_ms_negative_unit() {
614        let scale = [10.0, 0.1, -1.0];
615        test_decompose_scale(scale);
616    }
617
618    #[test]
619    fn decompose_nonuniform_scale_ms_negative_up() {
620        let scale = [10.0, 0.1, -10.0];
621        test_decompose_scale(scale);
622    }
623
624    #[test]
625    fn decompose_nonuniform_scale_ms_negative_down() {
626        let scale = [10.0, 0.1, -0.1];
627        test_decompose_scale(scale);
628    }
629}