use super::*;
pub(super) fn parse_skeletons(
document: &gltf::Document,
buffers: &[gltf::buffer::Data],
node_parents: &std::collections::HashMap<usize, usize>,
nodes_by_index: &[gltf::Node],
) -> Vec<SkeletonHierarchy> {
document
.skins()
.map(|skin| {
let reader = skin.reader(|b| Some(&buffers[b.index()]));
let identity_mat = [
[1.0, 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.],
];
let ibm: Vec<[[f32; 4]; 4]> = reader
.read_inverse_bind_matrices()
.map(|v| v.collect())
.unwrap_or_else(|| vec![identity_mat; skin.joints().count()]);
let node_to_bone: std::collections::HashMap<usize, usize> = skin
.joints()
.enumerate()
.map(|(bone_idx, node)| (node.index(), bone_idx))
.collect();
let joints: Vec<SkeletonJoint> = skin
.joints()
.enumerate()
.map(|(bone_idx, joint_node)| {
let inverse_bind_matrix = ibm
.get(bone_idx)
.map(gizmo_math::Mat4::from_cols_array_2d)
.unwrap_or(gizmo_math::Mat4::IDENTITY);
let parent_index = node_parents
.get(&joint_node.index())
.and_then(|p| node_to_bone.get(p).copied());
let (t, r, s) = joint_node.transform().decomposed();
let bind_translation = Vec3::new(t[0], t[1], t[2]);
let bind_rotation = Quat::from_array(r);
let bind_scale = Vec3::new(s[0], s[1], s[2]);
let local_bind_transform = gizmo_math::Mat4::from_translation(bind_translation)
* gizmo_math::Mat4::from_quat(bind_rotation)
* gizmo_math::Mat4::from_scale(bind_scale);
SkeletonJoint {
name: joint_node.name().unwrap_or("bone").to_string(),
node_index: joint_node.index(),
inverse_bind_matrix,
parent_index,
local_bind_transform,
bind_translation,
bind_rotation,
bind_scale,
}
})
.collect();
let root_transform =
compute_armature_root_transform(&skin, node_parents, &node_to_bone, nodes_by_index);
SkeletonHierarchy {
joints,
root_transform,
}
})
.collect()
}
fn compute_armature_root_transform(
skin: &gltf::Skin,
node_parents: &std::collections::HashMap<usize, usize>,
node_to_bone: &std::collections::HashMap<usize, usize>,
nodes_by_index: &[gltf::Node],
) -> gizmo_math::Mat4 {
let mut root_transform = gizmo_math::Mat4::IDENTITY;
let first_joint = match skin.joints().next() {
Some(j) => j,
None => return root_transform,
};
let mut current_idx = first_joint.index();
let mut ancestor_transforms: Vec<gizmo_math::Mat4> = Vec::new();
while let Some(&parent_idx) = node_parents.get(¤t_idx) {
if node_to_bone.contains_key(&parent_idx) {
break;
}
if let Some(parent_node) = nodes_by_index.get(parent_idx) {
let (t, r, s) = parent_node.transform().decomposed();
let mat = gizmo_math::Mat4::from_translation(Vec3::new(t[0], t[1], t[2]))
* gizmo_math::Mat4::from_quat(Quat::from_array(r))
* gizmo_math::Mat4::from_scale(Vec3::new(s[0], s[1], s[2]));
ancestor_transforms.push(mat);
}
current_idx = parent_idx;
}
for mat in ancestor_transforms.into_iter().rev() {
root_transform *= mat;
}
root_transform
}