blender_armature/
coordinate_system.rs1use crate::{BlenderArmature, Bone};
2
3#[derive(Debug, Eq, PartialEq, Copy, Clone, Serialize, Deserialize)]
8pub struct CoordinateSystem {
9 up: Axis,
10 hand: Hand,
11}
12
13impl CoordinateSystem {
14 #[allow(missing_docs)]
15 pub fn new(up: Axis, hand: Hand) -> Self {
16 CoordinateSystem { up, hand }
17 }
18}
19
20#[allow(missing_docs)]
21#[derive(Debug, Eq, PartialEq, Copy, Clone, Serialize, Deserialize)]
22pub enum Axis {
23 X,
24 Y,
25 Z,
26}
27
28#[derive(Debug, Eq, PartialEq, Copy, Clone, Serialize, Deserialize)]
32pub enum Hand {
33 Right,
35 Left,
37}
38
39impl Default for CoordinateSystem {
41 fn default() -> Self {
42 CoordinateSystem {
43 up: Axis::Z,
44 hand: Hand::Right,
45 }
46 }
47}
48
49impl BlenderArmature {
50 pub fn change_coordinate_system(&mut self, system: CoordinateSystem) {
56 if self.coordinate_system == system {
57 return;
58 }
59
60 match (
61 (self.coordinate_system.hand, self.coordinate_system.up),
62 (system.hand, system.up),
63 ) {
64 ((Hand::Right, Axis::Z), (Hand::Right, Axis::Y)) => {
65 for bone in self.inverse_bind_poses.iter_mut() {
66 *bone = dual_quat_z_up_right_to_y_up_right(*bone);
67 }
68
69 for (_action_name, action) in self.bone_space_actions.iter_mut() {
70 for (bone_idx, keyframes) in action.keyframes_mut() {
71 for bone_keyframe in keyframes.iter_mut() {
72 let bone = bone_keyframe.bone();
73 bone_keyframe.set_bone(dual_quat_z_up_right_to_y_up_right(bone));
74 }
75 }
76 }
77 }
78 _ => unimplemented!(),
79 }
80
81 self.coordinate_system = system;
82 }
83}
84
85fn dual_quat_z_up_right_to_y_up_right(bone: Bone) -> Bone {
86 match bone {
87 Bone::Matrix(_) => unimplemented!(),
88 Bone::DualQuat(mut dq) => {
89 let rot_y = dq.real.j;
90 let rot_z = dq.real.k;
91
92 dq.real.j = rot_z;
93 dq.real.k = -rot_y;
94
95 let trans_y = dq.dual.j;
96 let trans_z = dq.dual.k;
97
98 dq.dual.j = trans_z;
99 dq.dual.k = -trans_y;
100
101 Bone::DualQuat(dq)
102 }
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109 use crate::interpolate::tests::dq_to_bone;
110 use crate::test_util::{action_name, action_with_keyframes, BONE_IDX};
111 use crate::{Action, BlenderArmature, BoneKeyframe, Keyframe};
112 use std::collections::HashMap;
113
114 #[test]
117 fn convert_dual_quaternions_z_up_right_to_y_up_right() {
118 let mut arm = BlenderArmature::default();
119
120 let expected_bone = dq_to_bone([0., 1., 3., -2., 4., 5., 7., -6.]);
121
122 let bone = dq_to_bone([0., 1., 2., 3., 4., 5., 6., 7.]);
123 arm.inverse_bind_poses = vec![bone.clone()];
124
125 let keyframes = vec![BoneKeyframe::new(0, bone)];
126
127 arm.bone_space_actions = action_with_keyframes(keyframes);
128
129 arm.change_coordinate_system(CoordinateSystem::new(Axis::Y, Hand::Right));
130
131 assert_eq!(&arm.inverse_bind_poses[0], &expected_bone);
132 assert_eq!(
133 &arm.bone_space_actions[&action_name()].bone_keyframes()[&BONE_IDX][0].bone(),
134 &expected_bone
135 );
136 }
137
138 #[test]
141 fn does_not_change_if_coordinate_system_same() {
142 let mut arm = BlenderArmature::default();
143 arm.change_coordinate_system(CoordinateSystem::new(Axis::Y, Hand::Right));
144
145 let expected_bone = dq_to_bone([0., 1., 2., 3., 4., 5., 6., 7.]);
146
147 let bone = dq_to_bone([0., 1., 2., 3., 4., 5., 6., 7.]);
148 arm.inverse_bind_poses = vec![bone];
149
150 let keyframes = vec![BoneKeyframe::new(0, bone)];
151
152 arm.bone_space_actions = action_with_keyframes(keyframes);
153
154 arm.change_coordinate_system(CoordinateSystem::new(Axis::Y, Hand::Right));
155
156 assert_eq!(&arm.inverse_bind_poses[0], &expected_bone);
157 assert_eq!(
158 &arm.bone_space_actions[&action_name()].bone_keyframes()[&BONE_IDX][0].bone(),
159 &expected_bone
160 );
161 }
162}