This ADR describes the GPU skinning pipeline used for avatar rendering in the Decentraland Explorer (decentraland/unity-explorer), which replaces the modular avatar system described in ADR-65 (now deprecated). The new pipeline uses compute shaders, a Global Vertex Buffer (GVB), the AvatarCelShading shader, and Unity's Job System for high-performance avatar rendering at scale.
The old avatar system (ADR-65) was designed for the unity-renderer and used a modular pattern with a curator, loader, animator, GPU skinning module, LOD module, and visibility module, all coordinated through the DataStore plugin pattern.
The new explorer client required a fundamentally different approach to handle large numbers of
avatars efficiently. The key challenge is that Unity's SkinnedMeshRenderer does
not scale well, so a custom skinning pipeline was needed.
Each avatar consists of:
SkinnedMeshRenderer to MeshRenderer for scalability
The pipeline has three stages:
The StartAvatarMatricesCalculationSystem dispatches a job early in the frame to
transform animated bone matrices into local space, using Unity's Burst compiler for
parallelization. The FinishAvatarMatricesCalculationSystem completes the job as
late as possible to maximize parallelism.
The bone matrices are sent to the GPU via a single SetData call. The compute
shader performs 4-weight bone skinning, calculating position, normals, and tangents for every
vertex. Results are written into the Global Vertex Buffer (GVB).
The GVB stores vertex info for all instantiated avatars. When an avatar is removed, its space
is freed for reuse. The FixedComputeBufferHandler and
MakeVertsOutBufferDefragmentationSystem manage buffer fragmentation.
The AvatarCelShading shader reads from the GVB using indexes set during setup. Textures are stored in texture arrays to minimize binding costs between draw calls, enabling efficient SRP batching.
| Aspect | ADR-65 (Old) | This ADR (New) |
|---|---|---|
| Skinning | Module-based GPU skinning | Compute shader + GVB pipeline |
| Rendering | Standard Unity rendering | AvatarCelShading with texture arrays |
| Architecture | Modular OOP (Curator/Loader/Animator) | ECS systems pipeline |
| Wearable swap | Mesh recombination needed | Instant (buffer index update) |
| Coordination | DataStore plugin pattern | ECS single-instance entities |
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.