Skip to main content

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}