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