use crate::math::IDENTITY_MAT4;
use super::anim_mapper::AnimMapper;
use super::skinning::{rigid_skinning_transform, skin_normals_lbs, skin_points_lbs};
use super::types::{InfluenceInterpolation, ReadSkelBinding, SkinningMethod};
#[derive(Debug, Clone)]
pub struct SkinningResolver {
binding: ReadSkelBinding,
mapper: AnimMapper,
num_mesh_joints: usize,
geom_bind_transform: [f64; 16],
}
impl SkinningResolver {
pub fn new(binding: ReadSkelBinding, skeleton_joint_order: &[String]) -> Self {
let mapper = if binding.joint_subset.is_empty() {
AnimMapper::new(skeleton_joint_order, skeleton_joint_order)
} else {
AnimMapper::new(skeleton_joint_order, &binding.joint_subset)
};
let num_mesh_joints = if binding.joint_subset.is_empty() {
skeleton_joint_order.len()
} else {
binding.joint_subset.len()
};
let geom_bind_transform = binding.geom_bind_transform.unwrap_or(IDENTITY_MAT4);
Self {
binding,
mapper,
num_mesh_joints,
geom_bind_transform,
}
}
pub fn binding(&self) -> &ReadSkelBinding {
&self.binding
}
pub fn prim(&self) -> &str {
&self.binding.path
}
pub fn is_rigidly_deformed(&self) -> bool {
self.binding.interpolation == InfluenceInterpolation::Constant
}
pub fn num_influences_per_component(&self) -> usize {
self.binding.elements_per_element.max(1) as usize
}
pub fn has_joint_influences(&self) -> bool {
!self.binding.joint_indices.is_empty() && !self.binding.joint_weights.is_empty()
}
pub fn joint_order_len(&self) -> usize {
self.num_mesh_joints
}
pub fn geom_bind_transform(&self) -> &[f64; 16] {
&self.geom_bind_transform
}
pub fn skinning_method(&self) -> SkinningMethod {
self.binding.skinning_method
}
pub fn remap_skinning_xforms(&self, skel_skinning_xforms: &[[f64; 16]]) -> Vec<[f64; 16]> {
if self.mapper.is_identity() {
return skel_skinning_xforms.to_vec();
}
(0..self.mapper.target_len())
.map(|t| match self.mapper.source_index(t) {
Some(i) => skel_skinning_xforms[i],
None => IDENTITY_MAT4,
})
.collect()
}
pub fn compute_skinned_points(&self, points: &[[f32; 3]], skel_skinning_xforms: &[[f64; 16]]) -> Vec<[f32; 3]> {
assert!(
!self.is_rigidly_deformed(),
"compute_skinned_points called on rigidly-deformed binding"
);
let mesh_xforms = self.remap_skinning_xforms(skel_skinning_xforms);
skin_points_lbs(
points,
&self.binding.joint_indices,
&self.binding.joint_weights,
self.num_influences_per_component(),
&self.geom_bind_transform,
&mesh_xforms,
)
}
pub fn compute_skinned_normals(&self, normals: &[[f32; 3]], skel_skinning_xforms: &[[f64; 16]]) -> Vec<[f32; 3]> {
assert!(
!self.is_rigidly_deformed(),
"compute_skinned_normals called on rigidly-deformed binding"
);
let mesh_xforms = self.remap_skinning_xforms(skel_skinning_xforms);
skin_normals_lbs(
normals,
&self.binding.joint_indices,
&self.binding.joint_weights,
self.num_influences_per_component(),
&self.geom_bind_transform,
&mesh_xforms,
)
}
pub fn compute_rigid_transform(&self, skel_skinning_xforms: &[[f64; 16]]) -> [f64; 16] {
assert!(
self.is_rigidly_deformed(),
"compute_rigid_transform called on per-vertex binding"
);
let mesh_xforms = self.remap_skinning_xforms(skel_skinning_xforms);
rigid_skinning_transform(
&self.binding.joint_indices,
&self.binding.joint_weights,
self.num_influences_per_component(),
&self.geom_bind_transform,
&mesh_xforms,
)
}
}