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) {
25 let spans = self.model.group_morph_spans();
26 let offsets = self.model.group_morph_offsets();
27 if spans.is_empty() || offsets.is_empty() {
28 return;
29 }
30 let mc = self.model.morph_count() as usize;
31 self.morph_scratch.expanded_weights.clear();
32 self.morph_scratch
33 .expanded_weights
34 .extend_from_slice(&self.pose.morph_weights()[..mc]);
35
36 let expanded_weights = &mut self.morph_scratch.expanded_weights;
37 let group_stack = &mut self.morph_scratch.group_stack;
38 group_stack.clear();
39 for (morph_idx, &w) in self.pose.morph_weights()[..mc].iter().enumerate() {
40 if w == 0.0 {
41 continue;
42 }
43 group_stack.push(super::GroupMorphFrame {
44 morph_idx,
45 weight: w,
46 next_offset: 0,
47 });
48 while let Some(frame) = group_stack.last_mut() {
49 let span = spans[frame.morph_idx];
50 if frame.next_offset >= span.count {
51 group_stack.pop();
52 continue;
53 }
54
55 let offset_index = span.start as usize + frame.next_offset as usize;
56 frame.next_offset += 1;
57 let offset = offsets[offset_index];
58 let child = offset.child_morph.as_usize();
59 let contribution = frame.weight * offset.ratio;
60 expanded_weights[child] += contribution;
64 if spans[child].count > 0 {
65 group_stack.push(super::GroupMorphFrame {
66 morph_idx: child,
67 weight: contribution,
68 next_offset: 0,
69 });
70 }
71 }
72 }
73 for (i, &w) in expanded_weights.iter().enumerate() {
74 self.pose.set_morph_weight(MorphIndex(i as u32), w);
75 }
76 }
77
78 fn apply_bone_morphs(&mut self) {
81 let spans = self.model.bone_morph_spans();
82 let offsets = self.model.bone_morph_offsets();
83 if spans.is_empty() || offsets.is_empty() {
84 return;
85 }
86 for (morph_idx, span) in spans.iter().enumerate() {
87 let weight = self.pose.morph_weight(MorphIndex(morph_idx as u32));
88 if weight == 0.0 {
89 continue;
90 }
91 for i in span.start..span.start + span.count {
92 let off = &offsets[i as usize];
93 let pos = self.pose.local_position_offset(off.target_bone);
94 self.pose
95 .set_local_position_offset(off.target_bone, pos + off.position_offset * weight);
96 let rot = self.pose.local_rotation(off.target_bone);
97 let scaled = Quat::IDENTITY.slerp(off.rotation_offset, weight);
98 self.pose
99 .set_local_rotation(off.target_bone, (rot * scaled).normalize());
100 }
101 }
102 }
103
104 #[inline]
105 pub fn morph_weights(&self) -> &[f32] {
106 self.pose.morph_weights()
107 }
108}