Add dedicated skinned rendering, pose restoration, shared Material and Material Instance slots, registry-driven components, Surface/Solari integration, transactional schema upgrades, navigation authoring, documentation, and evaluation evidence.
3.5 KiB
ADR 0033: Dedicated Skinned Mesh Renderer
Status
Accepted
Context
The normalized model artifact originally exposed every imported primitive to
StaticMeshRenderer, including primitives with joint indices and weights. Whole-model static
placement could therefore detach rigged geometry from its joints and render it in bind pose. The
animation workflow avoided individual skinned-part placement, but it still represented animated
geometry as generic ImportedModel + ModelRef, leaving no authoring boundary between an arbitrary
source scene and geometry that requires a skeleton hierarchy.
Static, generic scene-instance, and skinned rendering have different ownership rules. Static parts can be flattened into independent slots and triangle-mesh colliders. A skinned mesh must retain the source joints, inverse bind poses, animation player, and hierarchy. A generic scene instance may contain cameras, lights, or other source data and does not imply an animation contract.
Decision
Rigged geometry uses ActorKind::SkinnedMesh + SkinnedMeshRenderer. The renderer stores stable
asset identity, cached source path, and source scene index. Its dedicated hydration system creates a
HydratedSkinnedMeshRoot and instantiates the complete source hierarchy so Bevy owns the runtime
SkinnedMesh, joints, inverse bind poses, and animation-player placement. The animation runtime
binds only to this dedicated root. AnimationControllerDesc is valid only beside a
SkinnedMeshRenderer.
Renderer hydration itself remains animation-agnostic. The animation adapter captures the imported hierarchy baseline when that root becomes ready and optionally drives the explicit default clip recorded by animation-manifest schema v3. Without a controller, the dedicated renderer remains at the captured imported pose.
Static-mesh artifact schema v2 marks every part as skinned or unskinned. Static renderer creation
filters out skinned parts and all geometry from an animated source; static hydration enforces the
same rule even if a scene contains a hand-authored slot. Automatic renderable-model placement
chooses SkinnedMeshRenderer when any source part is skin-bound or the source contains animation,
and otherwise chooses StaticMeshRenderer. Placing a skinned or animated subasset
places its owning model through the dedicated renderer; it never creates a detached static slot.
ImportedModel + ModelRef remains the explicit generic scene-instance path. It is not the animation
renderer. Scene schema v3 migrates v2 entities containing both ModelRef and
AnimationControllerDesc to SkinnedMeshRenderer + ActorKind::SkinnedMesh; unrelated imported
scene instances remain unchanged.
Automatic triangle-mesh collider generation applies only to static renderers. Animated collision must be authored explicitly with stable gameplay shapes or hitboxes rather than a deforming render surface.
Consequences
- Static renderer slots can no longer silently accept newly imported skinned or animated geometry.
- Rigged models retain the exact hierarchy Bevy needs for skinning and animation playback.
- Generic scene instances, static meshes, and skinned meshes have distinct persisted components, actor kinds, hydration markers, validation, and editor presentation.
- A source containing both rigid and skinned nodes is placed as one skinned actor so the imported hierarchy remains coherent; splitting it requires separate source assets.
- FBX skinning and animation remain blocked by ADR 0031 until the FBX loader can build the same runtime hierarchy and clip contract as glTF.