Search Results for

    Show / Hide Table of Contents

    Architecture

    In this section, we’ll cover the general architecture of the package. As the package is built with extensibility in mind, this will go into more technical detail about how the package functions to familiarize the user with key concepts.

    The package works with both traditional GameObjects (a.k.a. hybrid) and ECS subscenes using the same authoring components (e.g., MonoBehaviours). However, in both use cases, all logic runs in the ECS world, and the authoring components merely contain logic to set up entities. In the hybrid scenario, during MonoBehaviour setup, it also creates an Entity that gets connected with the GameObject's lifetime and adds components that are connected with the authoring component. For the subscene workflow, it follows general Unity concepts, so for more details, it is recommended to check Unity’s com.unity.entities package documentation about subscenes.

    The other sections will cover the authoring components, entity components, and systems. Keep in mind this only covers the core elements of the package for simplicity. The package contains more components, but they follow this structure quite strictly.

    Authoring

    Each animated object will contain at minimum the following structure. There is a parent GameObject that contains the Animatron component, which is the main component. It references the Rig ScriptableObject that is baked at edit time and contains the bone structure and animation data.

    Then it contains one or more child GameObjects, referred to as Skin, where each of them at the very least contains a RenderMeshArray. RenderMeshArray is a general-purpose rendering component that replaces the SkinnedMeshRenderer.

    It is a helpful analogy to think of the parent GameObject with Animatron as the bones of a body, and the Skin objects as the flesh that gets rendered—usually bound to a subset of bones or all of them.

    Note

    Note: RenderMeshArray can be used as a standalone component that essentially works as a MeshRenderer. There are multiple benefits to using it instead of Unity’s built-in MeshRenderer. For more details, read the section about RenderMeshArray.

    Entity

    Entities follow a structure similar to authoring, but with more granular components. There is a parent entity that contains several key components. The first is an optional Animatron, which simply plays an animation at a given index. Next, it contains a JointPose buffer, which is an array of transforms representing the entity’s pose at the current frame. It also has references to Armature and Motion. Armature and Motion are generated by the Rig. Armature is a compact binary blob that contains joint data, while Motion is another compact blob containing animation data.

    Similarly to authoring, there are one or more child entities. They reference the same Armature and also contain a SkinMatrix buffer, which is an array of transforms derived from a subset of the parent’s JointPose.

    There is also a singleton entity that contains the SkinMatrixBuffer component. This holds all SkinMatrix buffers from all entities, flattened into a single array and stored in GPU memory. It is later bound to shaders for deformation. Each entity also contains a SkinMatrixBufferIndex, which is simply an offset into this buffer and is regenerated each frame.

    Systems

    Most of the system logic runs in a system group called AnimatronSystemGroup. Here is a simplified execution order of systems and what they do:

    • AnimatronSystemGroup contains systems:
      • AnimatronSystem: Plays the current animation by writing transforms into JointPose. This is optional, and users can implement more advanced systems here—e.g., playing multiple animations on different joints or using a custom animation graph.
      • Animation post-processing: This can be user-defined or, in this package’s case, includes blending (e.g., crossfade, inertialization, inverse kinematics, etc.).
      • PoseSystem: Transforms the JointPose array from local space to object space.
      • SkinSystem: Updates the SkinMatrix array from the parent’s JointPose and applies the bind pose transform, since this matrix will be used by the GPU. For more details, read the code or look up how skinning matrices are typically calculated.
      • SkinMatrixSystem: This includes several systems that execute at different stages for performance reasons. Their main purpose is to flatten all SkinMatrix data from all entities into the singleton SkinMatrixBuffer in GPU memory. It also binds this GPU memory to the shader.

    After this, the Unity Entities Graphics package takes over, issuing draw calls for each RenderMeshArray. Since SkinMatrixBuffer contains all skin matrices in a single buffer, and each entity contains instance data like SkinMatrixBufferIndex, the shader can easily access the correct transforms.

    In theory, other rendering solutions can also be used, as long as they correctly gather all entities' SkinMatrixBufferIndex components and pass them to the GPU as instanced data.

    In This Article
    Back to top Copyright © ProjectDawn.
    Generated by DocFX