unity_formats/animator/mod.rs
1//! Unity's Animator side as typed data: an Avatar (the skeleton Mecanim animates, and for a humanoid the compiled
2//! muscle axes and the HumanDescription it was built from), an AnimatorController (layers, state machines, states with
3//! their blend trees and transitions, parameters). Nothing here is
4//! evaluated: it is what the files hold, in Unity's frame (rotations as `[x, y, z, w]`), with the names Unity keeps
5//! only as CRC-32 hashes resolved through the object's own name table (`tos`) where it has one.
6
7mod read;
8
9use serde::Serialize;
10
11use crate::player::ObjRef;
12
13/// The hash Unity's Animator data names things by (a state, a layer, a parameter, a binding's path): the CRC-32 (the zlib one)
14/// of the name's bytes.
15pub fn name_hash(name: &str) -> u32 {
16 let mut crc = !0u32;
17 for byte in name.bytes() {
18 crc ^= u32::from(byte);
19 for _ in 0..8 {
20 crc = (crc >> 1) ^ (0xEDB8_8320 & 0u32.wrapping_sub(crc & 1));
21 }
22 }
23 !crc
24}
25
26/// A transform as Mecanim stores it (`xform`): translation, rotation as a quaternion `[x, y, z, w]` and scale.
27#[derive(Clone, Copy, Debug, PartialEq, Serialize)]
28pub struct Xform {
29 /// Translation.
30 pub t: [f32; 3],
31 /// Rotation, a quaternion `[x, y, z, w]`.
32 pub q: [f32; 4],
33 /// Scale.
34 pub s: [f32; 3],
35}
36
37/// One bone's muscle axes (`Axes`): its pre- and post-rotation, the sign of each axis, the limits of its rotation in
38/// radians, its length and its type.
39#[derive(Clone, Copy, Debug, PartialEq, Serialize)]
40pub struct AvatarAxes {
41 /// `m_PreQ`: the rotation applied before the bone's own.
42 pub pre_q: [f32; 4],
43 /// `m_PostQ`: the rotation applied after it.
44 pub post_q: [f32; 4],
45 /// `m_Sgn`: the sign of each axis.
46 pub sgn: [f32; 3],
47 /// `m_Min`: the lower limit of each axis, in radians.
48 pub min: [f32; 3],
49 /// `m_Max`: the upper limit of each axis, in radians.
50 pub max: [f32; 3],
51 /// `m_Length`.
52 pub length: f32,
53 /// `m_Type`.
54 pub kind: i64,
55}
56
57/// A skeleton (`Skeleton`): per node its parent (`-1` for a root) and its axes index (`-1` for none), the CRC-32 of
58/// each node's path, and the axes the nodes index.
59#[derive(Clone, Debug, Default, PartialEq, Serialize)]
60pub struct AvatarSkeleton {
61 /// Per node, its parent (`m_ParentId`, -1 for a root) and its axes index (`m_AxesId`, -1 for none).
62 pub nodes: Vec<(i64, i64)>,
63 /// `m_ID`: the CRC-32 of each node's path.
64 pub ids: Vec<u32>,
65 /// `m_AxesArray`: the axes the nodes index.
66 pub axes: Vec<AvatarAxes>,
67}
68
69/// A humanoid's compiled data (`Human`): the human skeleton with its pose and axes, which skeleton bone each human bone
70/// is (`bone_index`, `-1` for none), the proportions the retargeting uses.
71#[derive(Clone, Debug, PartialEq, Serialize)]
72pub struct AvatarHuman {
73 /// `m_RootX`.
74 pub root: Xform,
75 /// `m_Skeleton`: the human skeleton.
76 pub skeleton: AvatarSkeleton,
77 /// `m_SkeletonPose`: a transform for each node of the human skeleton.
78 pub pose: Vec<Xform>,
79 /// `m_LeftHand`'s `m_HandBoneIndex`.
80 pub left_hand: Vec<i64>,
81 /// `m_RightHand`'s `m_HandBoneIndex`.
82 pub right_hand: Vec<i64>,
83 /// `m_HumanBoneIndex`: which skeleton bone each human bone is, -1 for none.
84 pub bone_index: Vec<i64>,
85 /// `m_HumanBoneMass`.
86 pub bone_mass: Vec<f32>,
87 /// `m_Scale`.
88 pub scale: f32,
89 /// `m_ArmTwist`.
90 pub arm_twist: f32,
91 /// `m_ForeArmTwist`.
92 pub fore_arm_twist: f32,
93 /// `m_UpperLegTwist`.
94 pub upper_leg_twist: f32,
95 /// `m_LegTwist`.
96 pub leg_twist: f32,
97 /// `m_ArmStretch`.
98 pub arm_stretch: f32,
99 /// `m_LegStretch`.
100 pub leg_stretch: f32,
101 /// `m_FeetSpacing`.
102 pub feet_spacing: f32,
103 /// `m_HasLeftHand`.
104 pub has_left_hand: bool,
105 /// `m_HasRightHand`.
106 pub has_right_hand: bool,
107 /// `m_HasTDoF`.
108 pub has_translation_dof: bool,
109}
110
111/// One human bone of the HumanDescription: the skeleton bone it names, the human bone it is and its stated limits.
112#[derive(Clone, Debug, PartialEq, Serialize)]
113pub struct HumanBone {
114 /// `m_BoneName`: the skeleton bone.
115 pub bone_name: String,
116 /// `m_HumanName`: the human bone, as Unity names it.
117 pub human_name: String,
118 /// `m_Min`.
119 pub min: [f32; 3],
120 /// `m_Max`.
121 pub max: [f32; 3],
122 /// `m_Value`.
123 pub value: [f32; 3],
124 /// `m_Length`.
125 pub length: f32,
126 /// `m_Modified`.
127 pub modified: bool,
128}
129
130/// One bone of the HumanDescription's skeleton: its name, its parent's, and its local transform.
131#[derive(Clone, Debug, PartialEq, Serialize)]
132pub struct SkeletonBone {
133 /// `m_Name`.
134 pub name: String,
135 /// `m_ParentName`.
136 pub parent: String,
137 /// `m_Position`.
138 pub position: [f32; 3],
139 /// `m_Rotation`, a quaternion `[x, y, z, w]`.
140 pub rotation: [f32; 4],
141 /// `m_Scale`.
142 pub scale: [f32; 3],
143}
144
145/// What the avatar was built from (`HumanDescription`).
146#[derive(Clone, Debug, PartialEq, Serialize)]
147pub struct HumanDescription {
148 /// `m_Human`: the human bones.
149 pub human: Vec<HumanBone>,
150 /// `m_Skeleton`: the skeleton's bones.
151 pub skeleton: Vec<SkeletonBone>,
152 /// `m_ArmTwist`.
153 pub arm_twist: f32,
154 /// `m_ForeArmTwist`.
155 pub fore_arm_twist: f32,
156 /// `m_UpperLegTwist`.
157 pub upper_leg_twist: f32,
158 /// `m_LegTwist`.
159 pub leg_twist: f32,
160 /// `m_ArmStretch`.
161 pub arm_stretch: f32,
162 /// `m_LegStretch`.
163 pub leg_stretch: f32,
164 /// `m_FeetSpacing`.
165 pub feet_spacing: f32,
166 /// `m_GlobalScale`.
167 pub global_scale: f32,
168 /// `m_RootMotionBoneName`.
169 pub root_motion_bone_name: String,
170 /// `m_HasTranslationDoF`.
171 pub has_translation_dof: bool,
172 /// `m_HasExtraRoot`.
173 pub has_extra_root: bool,
174 /// `m_SkeletonHasParents`.
175 pub skeleton_has_parents: bool,
176}
177
178/// An Avatar object as stored: the skeleton Mecanim animates and, for a humanoid, its muscle axes.
179#[derive(Clone, Debug, PartialEq, Serialize)]
180pub struct UnityAvatar {
181 /// The Avatar object.
182 pub avatar: ObjRef,
183 /// `m_Name`.
184 pub name: String,
185 /// `m_AvatarSkeleton`: the nodes Mecanim animates.
186 pub skeleton: AvatarSkeleton,
187 /// The skeleton's pose (`m_AvatarSkeletonPose`) and its default pose (`m_DefaultPose`), a transform a node.
188 pub skeleton_pose: Vec<Xform>,
189 /// `m_DefaultPose`: a transform for each node.
190 pub default_pose: Vec<Xform>,
191 /// `m_SkeletonNameIDArray`.
192 pub skeleton_name_ids: Vec<u32>,
193 /// A humanoid's data; `None` for a generic avatar (its human skeleton is empty).
194 pub human: Option<AvatarHuman>,
195 /// Which avatar skeleton node each human skeleton node is (`m_HumanSkeletonIndexArray`) and the reverse.
196 pub human_skeleton_index: Vec<i64>,
197 /// `m_HumanSkeletonReverseIndexArray`.
198 pub human_skeleton_reverse: Vec<i64>,
199 /// `m_RootMotionBoneIndex`.
200 pub root_motion_bone_index: i64,
201 /// `m_RootMotionBoneX`.
202 pub root_motion_bone: Xform,
203 /// `m_RootMotionSkeleton`.
204 pub root_motion_skeleton: AvatarSkeleton,
205 /// Empty when the avatar stores no pose for its root motion nodes.
206 pub root_motion_pose: Vec<Xform>,
207 /// `m_RootMotionSkeletonIndexArray`.
208 pub root_motion_skeleton_index: Vec<i64>,
209 /// The CRC-32 of a path and the path (`m_TOS`).
210 pub tos: Vec<(u32, String)>,
211 /// `m_HumanDescription`.
212 pub description: HumanDescription,
213}
214
215/// A transition condition (`ConditionConstant`): its mode (1 true, 2 false, 3 greater, 4 less, 6 equals, 7 not equal,
216/// as Unity numbers them), the CRC-32 of its parameter's name, its threshold and, for an exit-time condition, the time.
217#[derive(Clone, Copy, Debug, PartialEq, Serialize)]
218pub struct Condition {
219 /// `m_ConditionMode`.
220 pub mode: i64,
221 /// `m_EventID`: the CRC-32 of the parameter's name.
222 pub parameter: u32,
223 /// `m_EventThreshold`.
224 pub threshold: f32,
225 /// `m_ExitTime`.
226 pub exit_time: f32,
227}
228
229/// What a destination at or above this is: a transition's `destination` (and a selector transition's) below it names a
230/// state of its machine, `SELECTOR_BASE + n` the selector node `n` (an entry or an exit).
231pub const SELECTOR_BASE: i64 = 30000;
232
233/// A transition (`TransitionConstant`) of a state or from any state.
234#[derive(Clone, Debug, PartialEq, Serialize)]
235pub struct Transition {
236 /// `m_ConditionConstantArray`.
237 pub conditions: Vec<Condition>,
238 /// A state, or [`SELECTOR_BASE`] plus a selector node.
239 pub destination: i64,
240 /// `m_FullPathID`.
241 pub full_path_id: u32,
242 /// `m_ID`.
243 pub id: u32,
244 /// `m_UserID`.
245 pub user_id: u32,
246 /// `m_TransitionDuration`.
247 pub duration: f32,
248 /// `m_TransitionOffset`.
249 pub offset: f32,
250 /// `m_ExitTime`.
251 pub exit_time: f32,
252 /// `m_HasExitTime`.
253 pub has_exit_time: bool,
254 /// `m_HasFixedDuration`.
255 pub has_fixed_duration: bool,
256 /// `m_InterruptionSource`.
257 pub interruption_source: i64,
258 /// `m_OrderedInterruption`.
259 pub ordered_interruption: bool,
260 /// `m_CanTransitionToSelf`.
261 pub can_transition_to_self: bool,
262}
263
264/// One node of a blend tree (`BlendTreeNodeConstant`): its kind (0 1D, 1 simple 2D, 2 freeform directional, 3 freeform
265/// cartesian, 4 direct, as Unity numbers them), the parameters it blends by, its children and thresholds or positions,
266/// and for a leaf the clip (`clip`: an index of the controller's clips, `u32::MAX` for none).
267#[derive(Clone, Debug, PartialEq, Serialize)]
268pub struct BlendNode {
269 /// `m_BlendType`.
270 pub blend_type: i64,
271 /// `m_BlendEventID`: the CRC-32 of the parameter the node blends by.
272 pub event_id: u32,
273 /// `m_BlendEventYID`: the second parameter, of a 2D node.
274 pub event_y_id: u32,
275 /// `m_ChildIndices`: the children's indices in the tree's nodes.
276 pub children: Vec<u32>,
277 /// `m_ChildThresholdArray` of the 1D data.
278 pub thresholds: Vec<f32>,
279 /// `m_ChildPositionArray` of the 2D data.
280 pub positions: Vec<[f32; 2]>,
281 /// `m_ChildMagnitudeArray` of the 2D data.
282 pub magnitudes: Vec<f32>,
283 /// `m_ChildPairVectorArray` of the 2D data.
284 pub pair_vectors: Vec<[f32; 2]>,
285 /// `m_ChildPairAvgMagInvArray` of the 2D data.
286 pub pair_avg_mag_inv: Vec<f32>,
287 /// `m_ChildNeighborListArray`: per child the indices of its neighbours in the 2D tree.
288 pub neighbors: Vec<Vec<u32>>,
289 /// `m_ChildBlendEventIDArray` of the direct data: the CRC-32 of each child's parameter.
290 pub direct_events: Vec<u32>,
291 /// `m_NormalizedBlendValues` of the direct data.
292 pub normalized_blend_values: bool,
293 /// `m_ClipID`.
294 pub clip: u32,
295 /// `m_Duration`.
296 pub duration: f32,
297 /// `m_CycleOffset`.
298 pub cycle_offset: f32,
299 /// `m_Mirror`.
300 pub mirror: bool,
301}
302
303/// A state (`StateConstant`): its transitions, its blend trees (one per motion set; a plain clip is a tree of one
304/// leaf), the CRC-32 of its name and path and the parameters that drive its speed, mirror, offset and time.
305#[derive(Clone, Debug, PartialEq, Serialize)]
306pub struct State {
307 /// `m_TransitionConstantArray`.
308 pub transitions: Vec<Transition>,
309 /// `m_BlendTreeConstantIndexArray`.
310 pub blend_tree_index: Vec<i64>,
311 /// `m_BlendTreeConstantArray`: each tree's nodes (`m_NodeArray`).
312 pub blend_trees: Vec<Vec<BlendNode>>,
313 /// `m_NameID`.
314 pub name_id: u32,
315 /// `m_PathID`.
316 pub path_id: u32,
317 /// `m_FullPathID`.
318 pub full_path_id: u32,
319 /// `m_TagID`.
320 pub tag_id: u32,
321 /// `m_SpeedParamID`.
322 pub speed_param: u32,
323 /// `m_MirrorParamID`.
324 pub mirror_param: u32,
325 /// `m_CycleOffsetParamID`.
326 pub cycle_offset_param: u32,
327 /// `m_TimeParamID`.
328 pub time_param: u32,
329 /// `m_Speed`.
330 pub speed: f32,
331 /// `m_CycleOffset`.
332 pub cycle_offset: f32,
333 /// `m_IKOnFeet`.
334 pub ik_on_feet: bool,
335 /// `m_WriteDefaultValues`.
336 pub write_default_values: bool,
337 /// `m_Loop`.
338 pub looping: bool,
339 /// `m_Mirror`.
340 pub mirror: bool,
341}
342
343/// What a selector transition's stored `m_Destination` holds when it leads nowhere (`0xFFFFFFFF`, an invalid index):
344/// [`SelectorTransition::destination`] is `None` for it.
345pub const NO_DESTINATION: u32 = u32::MAX;
346
347/// A transition out of an entry or exit selector (`SelectorTransitionConstant`).
348#[derive(Clone, Debug, PartialEq, Serialize)]
349pub struct SelectorTransition {
350 /// A state, or [`SELECTOR_BASE`] plus a selector node; `None` for [`NO_DESTINATION`]. In the files read it is the
351 /// one transition of the entry node of a state machine that has no states (a layer with nothing in it), and nowhere else.
352 pub destination: Option<u32>,
353 /// `m_ConditionConstantArray`.
354 pub conditions: Vec<Condition>,
355}
356
357/// An entry or exit node of a state machine (`SelectorStateConstant`).
358#[derive(Clone, Debug, PartialEq, Serialize)]
359pub struct SelectorState {
360 /// `m_TransitionConstantArray`.
361 pub transitions: Vec<SelectorTransition>,
362 /// `m_FullPathID`.
363 pub full_path_id: u32,
364 /// `m_IsEntry`: an entry node, else an exit.
365 pub is_entry: bool,
366}
367
368/// A state machine (`StateMachineConstant`).
369#[derive(Clone, Debug, PartialEq, Serialize)]
370pub struct StateMachine {
371 /// `m_StateConstantArray`.
372 pub states: Vec<State>,
373 /// `m_AnyStateTransitionConstantArray`.
374 pub any_state_transitions: Vec<Transition>,
375 /// `m_SelectorStateConstantArray`.
376 pub selectors: Vec<SelectorState>,
377 /// `m_DefaultState`.
378 pub default_state: i64,
379 /// `m_SynchronizedLayerCount`.
380 pub synchronized_layer_count: i64,
381}
382
383/// A layer (`LayerConstant`): the state machine it runs, the body and skeleton masks, how it blends in.
384#[derive(Clone, Debug, PartialEq, Serialize)]
385pub struct Layer {
386 /// `m_StateMachineIndex`: an index of the controller's state machines.
387 pub state_machine: i64,
388 /// `m_StateMachineSynchronizedLayerIndex`.
389 pub synchronized_layer: i64,
390 /// `m_BodyMask`'s three words.
391 pub body_mask: [u32; 3],
392 /// `m_SkeletonMask`: the CRC-32 of a path and its weight.
393 pub skeleton_mask: Vec<(u32, f32)>,
394 /// The CRC-32 of the layer's name.
395 pub binding: u32,
396 /// `m_LayerBlendingMode`.
397 pub blending_mode: i64,
398 /// `m_DefaultWeight`.
399 pub default_weight: f32,
400 /// `m_IKPass`.
401 pub ik_pass: bool,
402 /// `m_SyncedLayerAffectsTiming`.
403 pub synced_layer_affects_timing: bool,
404}
405
406/// A controller parameter (`ValueConstant`): the CRC-32 of its name, its kind (1 float, 3 int, 4 bool, 9 trigger, as
407/// Unity numbers them) and its place in the default values of that kind.
408#[derive(Clone, Copy, Debug, PartialEq, Serialize)]
409pub struct Parameter {
410 /// `m_ID`: the CRC-32 of the parameter's name.
411 pub id: u32,
412 /// `m_Type`.
413 pub kind: i64,
414 /// `m_Index`.
415 pub index: i64,
416}
417
418/// An AnimatorController object as stored (the compiled `ControllerConstant`).
419#[derive(Clone, Debug, PartialEq, Serialize)]
420pub struct UnityAnimatorController {
421 /// The AnimatorController object.
422 pub controller: ObjRef,
423 /// `m_Name`.
424 pub name: String,
425 /// `m_LayerArray`.
426 pub layers: Vec<Layer>,
427 /// `m_StateMachineArray`.
428 pub state_machines: Vec<StateMachine>,
429 /// `m_ValueArray`.
430 pub parameters: Vec<Parameter>,
431 /// `m_FloatValues` of the default values.
432 pub default_floats: Vec<f32>,
433 /// `m_IntValues` of the default values.
434 pub default_ints: Vec<i64>,
435 /// `m_BoolValues` of the default values.
436 pub default_bools: Vec<bool>,
437 /// The clips the blend trees' leaves index (`m_AnimationClips`): one slot per entry, `None` for a null pointer (a leaf's
438 /// index counts it).
439 pub clips: Vec<Option<ObjRef>>,
440 /// The scripts of the state machine behaviours (`m_StateMachineBehaviours`), by object.
441 pub behaviours: Vec<ObjRef>,
442 /// The CRC-32 of a name (a state, path, layer or parameter) and the name (`m_TOS`).
443 pub tos: Vec<(u32, String)>,
444}
445
446impl UnityAnimatorController {
447 /// The name a hash stands for in this controller's name table.
448 pub fn name_of(&self, hash: u32) -> Option<&str> {
449 self.tos.iter().find(|(h, _)| *h == hash).map(|(_, n)| n.as_str())
450 }
451}