Been looking at modernizing/formalizing the ThreeJS animation framework to be more similar to Unity/Unreal Engine 4. There is a lot of great code in ThreeJS but there is a bit of missing top level organization of animation structures, rather there is a lot of duplication.
Here are the classes I’ve been studying today:
- SkinnedMesh – derived from Mesh, adds support for array of Bone and Skeleton
The AnimationHandler/Animation pair:
- AnimationHandler – a global object for creating and advancing playing Animation
- Animation – a hierarchy of keyframe animation tracks usually used for bones on a skinned mesh, closely linked to AnimationHandler.
The following is not compatible with the Animation/AnimationHandler framework:
- KeyframeAnimation – AnimationHandler independent Keyframe track, only used by Collada example.
- MorphAnimation – AnimationHandler independent MorphTarget animation, only used by *morphtargets_horse.html examples.
The following combine scheduling of animations with meshes/mesh hierarchies:
- BlendCharacter – SkinnedMesh + Animation Scheduler (sometimes used with manually animated morph targets, such as in webgl_animation_skinning_morph.html)
- MorphAnimMesh – single Morph Target animation (for simple repeating things.)
- MorphBlendMesh – multiple Morph Target animation blending (meshes that change between morph target animations.)
- UCSCharacter – SkinnedMesh + Animation (only used in webgl_morphtargets_human.html)
- MD2Character – A bunch of MorphAnimMeshes (used only in webgl_morphtargets_md2.html)
- MD2Charactercomplex – A bunch of MorphBlendMeshes (used only in webgl_morphtargets_md2_control.html)
I’m trying to think of a way of reducing all of these classes into a clearer structure.
I think a structure similar to this might be the way forward:
- Track – a keyframe animation that contains a name, a set of keys that are composed of times and values. Keys can be weights, or pos/rot/scale. The name of the track can refer to morphTargets or bones/nodes or possibly other values within a node. (We could even abstract Track to not be keyframed, it could be equation based as well if we get the interface right.)
- Clip – a set of tracks with a name, duration. An animation sequence, such as blink, walk, jump, etc. Can be a morph or a keyframe or maybe both. Similar to Unity’s AnimationClip class
- Action – a clip that is being played. Would be associated with a root node to which the Track names would be relative. Would have a blend weight associated with it and can be queued into animation system. Could optionally loop and have a play speed. (Will likely require more parameters for various edge cases.) Similar to Unity’s AnimationState class
- Mixer – a container for a number of actions. Would be responsible for applying the actions to the hierarchy — it would be sort of like AnimationHandler, it could be global or there could be multiple — I’m open on this case. It would be responsible for blending between actions.
- Animator – a higher level structure on top of Mixer that would contain the logic to do things like walk, run, jump, it would do that by managing what actions are queued up and how they are blended between in order to create a smooth result. (Will have to be easy to extend to support new entity behaviors.) Similar to Unity’s Animator class
I would get rid of AnimationHandler, Animation (replaced by Clip/Track), KeyframeAnimation (replaced by Track), MorphAnimation (replaced by Track), BlendCharacter (replaced by Mixer/Clip/Track), MorphAnimMesh (replaced by Mixer/Clip/Track), MorphBlendMesh (replaced by Animator/Mixer/Clip/Track), USCCharacter, MD2Character, MD2CharacterComplex (replaced by Animator/Mixer/Clip/Track), or at least deprecate them in favor for the Track/Clip/Action/Mixer/Animator design, and this design could drive any objects in ThreeJS, including Materials, Lights and Cameras, if you so desired.
Basically this is a more flexible and actually simpler design.
The above is very similar to Unity/Unreal Engine.