# 4. Layers, Masks, Root Motion, and Events Part of [[Animation]]. Prev: [[3.Blend Trees]]. Next: [[5.Animation Rigging and Script IK]]. **Docs:** Manual 6000.5 — Avatar Mask window; How Root Motion works; Add events to animation clips. Layers: Animator window Layers tab (standard Mecanim). Deeper override stacks / sync timing → upcoming **Animation advanced** (not linked here). ## 4.1 Layers (fundamentals) Animator window → **Layers** → **+**. | Field | Role | |---|---| | **Weight** | 0..1 contribution. Script: `animator.SetLayerWeight(index, w)`. | | **Mask** | Avatar Mask — which body parts this layer may write. | | **Blending** | *Override* replaces masked bones; *Additive* adds deltas (requires good reference pose). | | **IK Pass** | Required on the layer if you use `OnAnimatorIK` for that layer index. | | **Sync** | Timing sync with another layer *(details → advanced)*. | **Base Layer (0):** full-body locomotion. **Layer 1:** upper-body (gesture, reload, aim) with a mask that enables Arms/Head only. ```csharp using UnityEngine; [RequireComponent(typeof(Animator))] public sealed class UpperBodyLayerWeight : MonoBehaviour { [SerializeField] int upperBodyLayer = 1; [SerializeField] float damp = 8f; float _target; Animator _anim; void Awake() => _anim = GetComponent<Animator>(); public void SetAiming(bool aiming) => _target = aiming ? 1f : 0f; void Update() { float w = _anim.GetLayerWeight(upperBodyLayer); w = Mathf.MoveTowards(w, _target, damp * Time.deltaTime); _anim.SetLayerWeight(upperBodyLayer, w); } } ``` ## 4.2 Avatar Masks (preview) **Create → Avatar Mask**. Two definition modes (Manual): 1. **Humanoid body map** — click body regions green (include) / red (exclude): Head, Arms, Hands, Legs, Root shadow. Toggle **IK** for hands/feet curves. 2. **Transform hierarchy** — assign a reference Avatar, **Import Skeleton**, tick bones. Assign the mask on the layer. Also usable on import and on Timeline Animation Override tracks ([[Timeline Basics]]). Benefits called out in docs: unused curves can reduce memory and CPU. For this fundamentals set: one upper-body mask is enough. Complex mask lattices and additive layer authoring → Animation advanced. ## 4.3 Root motion vs in-place ### Concepts (Manual — How Root Motion works) - **Body Transform** — mass center; Humanoid retargeting reference. Stored in the clip. - **Root Transform** — projection used to move the GameObject each frame when Apply Root Motion is on. - Clip Inspector: **Root Transform Rotation / Position (Y) / Position (XZ)** with **Bake Into Pose**, **Based Upon**, **Offset**. - Bake Into Pose on XZ → idle/in-place (no accumulated drift). - Bake Y Into Pose → animation does not change GameObject height; docs also describe relationship to `Animator.gravityWeight` (read-only) when Apply Root Motion is used with physics components. ### Two valid architectures **A. Root motion driven** 1. Clips authored with travel. 2. Animator **Apply Root Motion** = on. 3. Optionally implement `OnAnimatorMove` to combine with physics: ```csharp using UnityEngine; [RequireComponent(typeof(Animator))] public sealed class RootMotionToCharacterController : MonoBehaviour { [SerializeField] CharacterController controller; Animator _anim; void Awake() { _anim = GetComponent<Animator>(); if (controller == null) controller = GetComponent<CharacterController>(); } void OnAnimatorMove() { // Consumes animator delta; apply however your mover needs. Vector3 delta = _anim.deltaPosition; Quaternion rot = _anim.deltaRotation; if (controller != null && controller.enabled) controller.Move(delta); else transform.position += delta; transform.rotation *= rot; } } ``` **B. In-place + script movement** (common for responsive twin-stick / [[Surface-Walking with an Omnidirectional Player Movement]] / many [[Car Controller]] hybrids) 1. Bake XZ into pose on locomotion clips (or use in-place authored clips). 2. Apply Root Motion = off. 3. Movement code moves the Transform / CharacterController; Animator only plays pose from blend trees. Hybrid: root motion on for cinematic walks, off for gameplay — toggle `animator.applyRootMotion`. ## 4.4 Animation Events On an imported clip (Animation tab → **Events**) or in the Animation window: 1. Scrub to the frame (foot plant, muzzle flash). 2. **Add Event**. 3. **Function** = method name on a component attached to the *same GameObject that has the Animator* (or a parent that receives the message — prefer the Animator GO). 4. Optional parameter: **Float**, **Int**, **String**, or **Object** (Manual). ```csharp using UnityEngine; public sealed class FootstepEvents : MonoBehaviour { [SerializeField] AudioSource source; [SerializeField] AudioClip[] dirtSteps; // Function name must match the event exactly (no overload ambiguity). public void Footstep(float volume) { if (dirtSteps == null || dirtSteps.Length == 0 || source == null) return; var clip = dirtSteps[Random.Range(0, dirtSteps.Length)]; source.PlayOneShot(clip, Mathf.Clamp01(volume)); } } ``` Events fire from the playing clip; blended blend-tree weights do not "partially" call events in a documented blend-aware way you should rely on — put events on clips where a dominant weight is expected, or drive SFX from code using normalized state time. ## 4.5 Verified vs unverified **Verified:** Avatar Mask humanoid regions + transform mode + IK toggle (Manual); Root Transform / Bake Into Pose / gravityWeight documentation (Manual — How Root Motion works); Animation Event function + four parameter types (Manual); `OnAnimatorMove`, `Animator.deltaPosition` / `deltaRotation`, `applyRootMotion` as standard APIs; `SetLayerWeight` / `GetLayerWeight`. **Unverified:** additive layer reference-pose authoring details; Sync layer timing semantics (left for advanced); event behavior under heavy blend-tree mixing. **Not compiled:** scripts above.