Welcome to the Mesh Animator documentation page. Mesh Animator is a toolset for converting and fully animating characters, animated assets, or any other kind of skinned mesh.
Below you'll find resources on how to use Mesh Animator and all it's features. To report any bugs or for questions not covered in the documentation, please e-mail jschieck@gmail.com.
Setting up an animated character or mesh is very straightforward and can be done in a single step. After importing the .unitypackage, open the Mesh Animator creation window by selecting Assets/Create/Mesh Animator...
The following window will appear.
Accuracy = 0.001. Good for most animations. Use 0.0001 for even less compression.
Accuracy = 0.01. Good for larger models or models not viewed close up.
Accuracy = 0.1. A very low accuracy can be used to create animated models that look pixelated.
Once the settings are correct, click Generate Snapshots. This will bake the animations out into MeshAnimation assets.
**NOTE** - If your skinned mesh's pivot is not facing Y up, it's rotation may appear off until playback begins. This is because all weight information is lost during baking.
Once baking is complete, the following assets will be created.
Each animation will get a MeshAnimation asset and a MeshAnimator prefab will be created. Rebaking the same asset will update existing MeshAnimation files and create a new prefab, so it's good practice not to use the generated prefab as your main asset, but rather a child of a top level prefab.
MeshAnimation
The Mesh Animation is the asset that stores the animation info.
Mesh Animator
The Mesh Animator is the main script that animates and swaps frames during gameplay. It functions similarly to the legacy Animation component.
Mesh Animator functions much like the legacy Animation component. In it's simplest form, animations are played by calling the Play() method.
public MeshAnimator meshAnimator; void Start() { meshAnimator.Play("idle"); }
The Mesh Animator has a few callbacks that can be used.
public MeshAnimator meshAnimator; void Start() { // called when an animation completes meshAnimator.OnAnimationFinished += (anim) => { Debug.Log(anim + " finished."); }; // called when a new frame of animation is displayed meshAnimator.OnFrameUpdated += () => { Debug.Log("Animation frame changed."); }; // called when a MeshAnimator enters or leaves the screen meshAnimator.OnVisibilityChanged += (isVisible) => { Debug.Log(isVisible); }; }
With the convience of Mecanim's state machines, I've included an example MecanimMeshAnimatorController.cs script. This script looks at the current state of a Mecanim animator, and plays the appropriate animation on the Mesh Animator. State names MUST match the name of the MeshAnimation and blend trees are not supported.
Since running an animator with it's own controller when it's not needed is excessive and hurts performance, I've also included an example state machine that achieves the same as the Mecanim controller but much more efficiently.
using UnityEngine; using System.Collections; public class AnimatorStateMachine : MonoBehaviour { public MeshAnimator meshAnimator; public bool crossFade = false; void Start() { meshAnimator.Play(); meshAnimator.OnAnimationFinished += OnAnimationFinished; } void OnAnimationFinished(string anim) { string newAnim = string.Empty; switch (anim) { case "idle": newAnim = "run_forward"; break; case "run_forward": newAnim = "run_backward"; break; case "run_backward": newAnim = "run_left"; break; case "run_left": newAnim = "run_right"; break; case "run_right": newAnim = "idle"; break; } if (crossFade) meshAnimator.Crossfade(newAnim); else meshAnimator.Play(newAnim); } }
With Mesh Animator, depending on the number of vertices, and number of frames in your animation, it is going to take up more memory than a traditional SkinnedMeshRenderer and Animator. Where you save is on the CPU. Finding a good balance between the two is important. If a character has 5k vertices and 20 animations each a few seconds long, it's not practical to use Mesh Animator.
The best use of Mesh Animator is with low-poly models with short animations. Each frame of animation is generated and copied from the base, this is why so much memory is needed for larger meshes and longer animations.
A 4k triangle character (like in the example) takes up 500KB of memory. So to display a 1 second idle animation baked at 30fps, you would need approximately 15MB of memory. Memory usage is the same whether you are displaying 1 character, or 1000 characters. A character that has only 400 triangles takes 32KB of memory per mesh. So the same length animation would only take 960KB of memory. You can use this information to plan accordingly in your projects.
Crossfading animations requires a temporary mesh to be created for the interpolation and adds a little CPU overhead for lerping the vertex positions. This overhead grows larger the more vertices your mesh has. The temporary meshes are pooled automatically so mesh animators sharing the same base mesh can use it. Crossfading a mesh requires at least 1 extra copy of the base mesh.
All Mesh Animator scripts reside in the FSG.MeshAnimator namespace.
using FSG.MeshAnimator;
// The mesh that will be animated public Mesh baseMesh; // The default animation that will be played if playAutomatically = true public MeshAnimation defaultAnimation; // Array of animations on the animator public MeshAnimation[] animations; // Playback speed of the animator public float speed; // Continue playing animation when the animator is off screen public bool updateWhenOffscreen; // Should animation begin playing when the animator is enabled public bool playAutomatically; // Reset the animator OnEnable and play the default animation public bool resetOnEnable; // The target object to recieve AnimationEvents public GameObject eventReciever; // Get the current animation playing public MeshAnimation currentAnimation { get; } // The FPS the animations were baked at public int FPS; // Callback for when an animation has finished playing public ActionOnAnimationFinished; // Callback for when the mesh has changed frames public Action OnFrameUpdated; // Callback for when the object has entered or left the viewable screen public ActionOnVisibilityChanged;
// Crossfade an animation by index public void Crossfade(int index, float speed = 0.1f); meshAnimator.Crossfade(0, 0.25f); // Crossfade an animation by name public void Crossfade(string anim, float speed = 0.1f); meshAnimator.Crossfade("idle", 0.25f); // Play the default animation, or resume playing a paused animator public void Play(); meshAnimator.Play(); // Play an animation by name public void Play(string anim); meshAnimator.Play("idle"); // Play an animation by index public void Play(int index); meshAnimator.Play(0); // Play a random animation public void PlayRandom(params string[] anim); meshAnimator.Play("idle", "idle_bored", "dance", "sit"); // Play an animation after the previous one has finished public void PlayQueued(string anim); meshAnimator.Play("wave"); meshAnimator.PlayQueued("idle"); // Pause an animator, disabling the component also has the same effect public void Pause(); meshAnimator.Pause(); // Restart the current animation from the beginning public void RestartAnim(); meshAnimator.RestartAnim(); // Get the MeshAnimation by name public MeshAnimation GetClip(string clipname); MeshAnimation clip = meshAnimator.GetClip("idle");