API Reference · Animation

Animator

Namespace: Ava3D

public sealed class Animator

Plays clips over a node tree, one state at a time with a blend between the outgoing and the incoming.

The shape this is built around. An asset arrives with a handful of named clips of which one loops and the rest are gestures — Idle, Greet, LookAround is a literal example. That is a default state and a set of one-shots that return to it, so that is what the API says: set Animator.Default once, call Animator.CrossFade for a gesture, and the return trip happens without the caller tracking it.

Two states at a time, not N. A blend tree — several clips weighted by a parameter, layered masks, additive passes — is a character-controller feature, and building one into a viewport control would mean an API three times this size serving cases a viewport does not have. Two covers every transition between named states, which is what the files actually contain.

Constructors

MemberDescription
Animator(Node root, IEnumerable<AnimationClip> clips)

Builds an animator over root for clips.

Properties

MemberDescription
AnimationLayer Base { get; }

The layer everything on this class drives: Animator.Play, Animator.CrossFade, Animator.States and the rest are all this one.

It is separate from Animator.Layers because it is not optional and because it is always an override — a base layer that only added a difference would have nothing to add it to.

AnimationState Current { get; }

The state in the foreground of the base layer, or null when nothing is playing.

string Default { get; set; }

The state a finished one-shot returns to, and the one Animator.Advance starts from if nothing has been asked for yet. Null leaves the pose where the one-shot ended.

float FadeDuration { get; set; }

How long Animator.CrossFade takes when it is not told. 0.2 s.

bool IsPlaying { get; }

Whether anything is playing on the base layer.

IReadOnlyList<AnimationLayer> Layers { get; }

Every layer, base first, in the order they are combined.

Read-only because a layer has to be registered against the node table when it is made — see Animator.AddLayer, which is how one is added.

Vector3 RootMotion { get; }

How far Animator.RootMotionNode travelled during the last Animator.Advance, in that node's parent's space. Zero when root motion is off.

A delta, never a position, and every rule below follows from that:

A looping cycle reports the step across the seam rather than the metre back to the start — the wrap is detected and the two halves are added.A crossfade blends the two clips' deltas, weighted as the pose is. Blending their positions would put the character at the average of two places and then walk it out of there.Seeking reports nothing. Writing AnimationState.Time is a scrub, not a stride, and the first Animator.Advance after one starts measuring again from where it was put.

Node RootMotionNode { get; set; }

The joint whose translation is travel rather than pose. Null, which is off, and off is the default.

A clip that walks its root forward is two different things depending on what the caller wants. As a pose it slides the character across the scene and snaps it back at the end of the cycle; as travel it is a metre per stride that belongs to whatever is carrying the character. Naming a node here says the second: the animator stops writing that node's translation and reports what it would have been as Animator.RootMotion.

Off by default because it has to be. A character animated in place with a root that bobs is perfectly ordinary, and turning this on for it would set the whole thing bobbing across the floor — so the file cannot be allowed to decide, only the caller.

AnimationStateCollection States { get; }

The clips this animator can play, by name. The base layer's — see Animator.Base.

Events

MemberDescription
event EventHandler<AnimationEventArgs> Finished

Raised when a non-looping state reaches the end of its clip, on any layer, before the return to that layer's default.

Methods

MemberDescription
AnimationLayer AddLayer(string name, IEnumerable<AnimationClip> clips)

Adds a layer on top of the ones already there, with its own copy of the states for clips.

Its own copy, and that is the point: a clip playing on two layers has two playheads, two weights and two ideas about whether it loops. Sharing them would make a gesture layered over a walk cycle scrub the walk cycle.

void Advance(double seconds)

Moves every layer's playhead on by seconds and writes the resulting pose to the nodes.

The library owns no clock, deliberately.Ava3DView calls this from the compositor's frame callback so the ordinary case needs no code — but a recorder rendering thirty frames a second of a scene the display is showing at 120, or a test pinning a pose, needs to say what time it is rather than be told. Both routes are the same method.

AnimationState CrossFade(string name, Nullable<float> seconds = default)

Blends the base layer into a state over seconds, or Animator.FadeDuration when that is null.

Asking for the state already playing is a no-op rather than a restart: a button pressed twice should not stutter the gesture it is already showing.

AnimationState Play(string name)

Starts a state on the base layer immediately, with no blend.

void Queue(string name)

Plays a state after the current one finishes, instead of returning to Animator.Default.

void Stop()

Stops every layer and leaves the pose where it is.

See also