public sealed class AnimationSystemRuns every animator once a frame, across the job scheduler, and puts root motion where it was asked to.
No guide page documents this yet — the page shows what the code says about itself.
As a system
- Phase
- Animation
- Reads
- AnimatorComponent
- Writes
- RootMotionResult LocalTransform
Remarks
In Animation, which the ECS defines as "after logic has decided what is playing" and before LateUpdate and the transform pass. That ordering is what makes root motion work: the delta is written to LocalTransform here, and TransformSystem in PreRender composes the world matrix from it afterwards.
Gather, evaluate in parallel, then publish. Evaluating an animator is a graph walk over a hundred joints and touches nothing outside that animator, which makes it the ideal shape for the scheduler — but it is reached through a managed component, so the ECS hands it over one entity at a time and the world must not be touched from a worker. The three phases separate those concerns: the gather reads the world on this thread and produces a flat array; the evaluation runs across the workers and reads nothing but the array; the publish writes transforms back on this thread. Nothing in the middle phase can see an Entity, which is what makes it safe rather than merely untested.
Below ParallelThreshold animators — or with no scheduler, which is what a test and a headless tool have — it runs inline. Scheduling three characters costs more than animating them.
One animator per entity. Two entities sharing an Animator was already wrong — it would be stepped twice a frame — and in parallel it is a data race. Nothing checks for it, the same way nothing checks that two entities do not share a transform.
Two queries rather than one and a test. Whether an entity has a LocalTransform is an archetype question, so asking it per entity would be paying per frame for something the archetype already answered. An animator on an entity with no transform is a legitimate thing — a UI rig, a test — and it simply does not get the root-motion branch.
Fields and properties (5)
public const int ParallelThresholdHow many animators there have to be before the scheduler is worth its overhead.
public SystemAccess Accesspublic int LastEvaluatedCountHow many animators the last run evaluated.
public IConstraintScheduler SchedulerWhat is solved together, and when in the frame.
public int LastStackCountHow many constraint stacks the last run found.
Methods (2)
public override JobHandle Update(in SystemContext context, JobHandle dependency)Runs the system.
public void Run(World world, float deltaTime, JobScheduler? jobs = null)Updates every animator in a world.
Used by (6)
- ConstraintStageBenchmarksVixen.Benchmarks.Animation
- CrowdBenchmarksVixen.Benchmarks.Animation
- AnimationSystemsVixen.Animation
- ConstraintStageTestsVixen.Animation.Tests
- EcsIntegrationTestsVixen.Animation.Tests
- GizmoTestsVixen.Animation.Tests