mod3d_base/
bone.rs

1//a Imports
2use geo_nd::matrix;
3
4use crate::{Mat4, Transformation};
5
6//a Bone
7//tp Bone
8/// Each bone has a transformation with respect to its parent that is
9/// a translation (its origin relative to its parent origin), scale
10/// (in each direction, although a common scale for each coordinates
11/// is best), and an orientation of its contents provided by a
12/// quaternion (as a rotation).
13///
14/// A point in this bone's space is then translate(rotate(scale(pt)))
15/// in its parent's space. The bone's children start with this
16/// transformation too.
17///
18/// From this the bone has a local bone-to-parent transform matrix
19/// and it has a local parent-to-bone transform matrix
20///
21/// At rest (where a mesh is skinned) there are two rest matrix variants
22/// Hence bone_relative = ptb * parent_relative
23///
24/// The skinned mesh has points that are parent relative, so
25/// animated_parent_relative(t) = btp(t) * ptb * parent_relative(skinned)
26///
27/// For a chain of bones Root -> A -> B -> C:
28///  bone_relative = C.ptb * B.ptb * A.ptb * mesh
29///  root = A.btp * B.btp * C.btp * C_bone_relative
30///  animated(t) = A.btp(t) * B.btp(t) * C.btp(t) * C.ptb * B.ptb * A.ptb * mesh
31#[derive(Debug)]
32pub struct Bone {
33    /// rest transform - translation, scale, rotation
34    pub transformation: Transformation,
35    /// The parent-to-bone mapping Matrix at rest; updated when the
36    /// transformation is changed
37    pub(crate) ptb: Mat4,
38    /// The mesh-to-bone mapping Matrix at rest, derived from the
39    /// hierarchy root; updated when any transformation is changed in
40    /// the hierarchy at this bone or above
41    pub(crate) mtb: Mat4,
42    ///  Index into matrix array to put this bones animated mtm
43    pub matrix_index: usize,
44}
45
46//ip Bone
47impl Bone {
48    //fp new
49    /// Create a new bone with a given rest
50    pub fn new(transformation: Transformation, matrix_index: usize) -> Self {
51        let ptb = [0.; 16];
52        let mtb = [0.; 16];
53        Self {
54            transformation,
55            matrix_index,
56            ptb,
57            mtb,
58        }
59    }
60
61    //mp borrow_transformation
62    /// Borrow the transformation
63    pub fn borrow_transformation(&self) -> &Transformation {
64        &self.transformation
65    }
66
67    //mp set_transformation
68    /// Set the transformation of the bone
69    pub fn set_transformation(mut self, transformation: Transformation) -> Self {
70        self.transformation = transformation;
71        self
72    }
73
74    //mp derive_matrices
75    /// Derive matrices for the bone given a parent mesh-to-bone [Mat4]
76    pub fn derive_matrices(&mut self, is_root: bool, parent_mtb: &Mat4) -> &Mat4 {
77        self.ptb = self.transformation.mat4_inverse();
78        if is_root {
79            self.mtb = self.ptb;
80        } else {
81            self.mtb = matrix::multiply4(&self.ptb, parent_mtb);
82        }
83        &self.mtb
84    }
85
86    //mp borrow_mtb
87    /// Borrow the mtb Matrix (for test mainly)
88    pub fn borrow_mtb(&self) -> &Mat4 {
89        &self.mtb
90    }
91
92    //mp borrow_ptb
93    /// Borrow the ptb Matrix (for test mainly)
94    pub fn borrow_ptb(&self) -> &Mat4 {
95        &self.ptb
96    }
97}
98
99//ip Display for Bone
100impl std::fmt::Display for Bone {
101    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
102        write!(
103            f,
104            "Bone {} : {} : mtb={:?}",
105            self.matrix_index, self.transformation, self.mtb
106        )
107    }
108}
109
110//ip DefaultIndentedDisplay for Bone
111impl indent_display::DefaultIndentedDisplay for Bone {}