use anyhow::Result;
use crate::gf;
use super::schema::Skeleton;
use super::skinning::{
compute_inverse_bind_transforms, compute_skinning_transforms as math_skin_xforms, joint_local_to_skel_space,
joint_skel_to_world,
};
use super::topology::Topology;
#[derive(Debug, Clone)]
pub struct SkeletonResolver {
joints: Vec<String>,
bind_transforms: Vec<gf::Matrix4d>,
rest_transforms: Vec<gf::Matrix4d>,
topology: Topology,
inverse_bind_transforms: Vec<gf::Matrix4d>,
}
impl SkeletonResolver {
pub fn from_skeleton(skeleton: &Skeleton) -> Result<Self> {
let joints = skeleton.joints()?;
let bind_transforms = skeleton.bind_transforms()?;
let rest_transforms = skeleton.rest_transforms()?;
let topology = Topology::from_joint_paths(&joints);
let inverse_bind_transforms = compute_inverse_bind_transforms(&bind_transforms);
Ok(Self {
joints,
bind_transforms,
rest_transforms,
topology,
inverse_bind_transforms,
})
}
pub fn joint_order(&self) -> &[String] {
&self.joints
}
pub fn topology(&self) -> &Topology {
&self.topology
}
pub fn joint_world_bind_transforms(&self) -> &[gf::Matrix4d] {
&self.bind_transforms
}
pub fn inverse_bind_transforms(&self) -> &[gf::Matrix4d] {
&self.inverse_bind_transforms
}
pub fn joint_local_to_skel_space(&self, local: &[gf::Matrix4d]) -> Vec<gf::Matrix4d> {
joint_local_to_skel_space(local, &self.topology)
}
pub fn joint_skel_to_world(&self, skel: &[gf::Matrix4d], skel_local_to_world: gf::Matrix4d) -> Vec<gf::Matrix4d> {
joint_skel_to_world(skel, skel_local_to_world)
}
pub fn compute_skinning_transforms_from_world(&self, joint_world: &[gf::Matrix4d]) -> Vec<gf::Matrix4d> {
math_skin_xforms(joint_world, &self.inverse_bind_transforms)
}
pub fn compute_skinning_transforms_from_local(
&self,
joint_local: &[gf::Matrix4d],
skel_local_to_world: gf::Matrix4d,
) -> Vec<gf::Matrix4d> {
let skel = self.joint_local_to_skel_space(joint_local);
let world = self.joint_skel_to_world(&skel, skel_local_to_world);
math_skin_xforms(&world, &self.inverse_bind_transforms)
}
pub fn rest_pose_local(&self) -> &[gf::Matrix4d] {
&self.rest_transforms
}
pub fn rest_pose_skel_space(&self) -> Vec<gf::Matrix4d> {
joint_local_to_skel_space(&self.rest_transforms, &self.topology)
}
}