mmd_anim_runtime/runtime/
morph.rs1use glam::Quat;
2
3use crate::MorphIndex;
4
5use super::RuntimeInstance;
6
7impl RuntimeInstance {
8 pub fn expand_morphs(&mut self) {
14 self.expand_group_morphs();
15 self.apply_bone_morphs();
16 }
17
18 fn expand_group_morphs(&mut self) {
23 let spans = self.model.group_morph_spans();
24 let offsets = self.model.group_morph_offsets();
25 if spans.is_empty() || offsets.is_empty() {
26 return;
27 }
28 let mc = self.model.morph_count() as usize;
29 self.morph_scratch.expanded_weights.clear();
30 self.morph_scratch
31 .expanded_weights
32 .extend_from_slice(&self.pose.morph_weights()[..mc]);
33
34 for (morph_idx, &w) in self.pose.morph_weights()[..mc].iter().enumerate() {
35 if w == 0.0 {
36 continue;
37 }
38 expand_group_morph_weight(
39 morph_idx,
40 w,
41 spans,
42 offsets,
43 &mut self.morph_scratch.expanded_weights,
44 );
45 }
46 for (i, &w) in self.morph_scratch.expanded_weights.iter().enumerate() {
47 self.pose.set_morph_weight(MorphIndex(i as u32), w);
48 }
49 }
50
51 fn apply_bone_morphs(&mut self) {
54 let spans = self.model.bone_morph_spans();
55 let offsets = self.model.bone_morph_offsets();
56 if spans.is_empty() || offsets.is_empty() {
57 return;
58 }
59 for (morph_idx, span) in spans.iter().enumerate() {
60 let weight = self.pose.morph_weight(MorphIndex(morph_idx as u32));
61 if weight == 0.0 {
62 continue;
63 }
64 for i in span.start..span.start + span.count {
65 let off = &offsets[i as usize];
66 let pos = self.pose.local_position_offset(off.target_bone);
67 self.pose
68 .set_local_position_offset(off.target_bone, pos + off.position_offset * weight);
69 let rot = self.pose.local_rotation(off.target_bone);
70 let scaled = Quat::IDENTITY.slerp(off.rotation_offset, weight);
71 self.pose
72 .set_local_rotation(off.target_bone, (rot * scaled).normalize());
73 }
74 }
75 }
76
77 #[inline]
78 pub fn morph_weights(&self) -> &[f32] {
79 self.pose.morph_weights()
80 }
81}
82
83fn expand_group_morph_weight(
84 morph_idx: usize,
85 weight: f32,
86 spans: &[crate::MorphOffsetSpan],
87 offsets: &[crate::GroupMorphOffset],
88 expanded_weights: &mut [f32],
89) {
90 let span = spans[morph_idx];
91 for i in span.start..span.start + span.count {
92 let off = &offsets[i as usize];
93 let child = off.child_morph.as_usize();
94 let contribution = weight * off.ratio;
95 expanded_weights[child] += contribution;
96 if spans[child].count > 0 {
97 expand_group_morph_weight(child, contribution, spans, offsets, expanded_weights);
98 }
99 }
100}