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 {}