# 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.