Blacksite/docs/adr/0035-shared-material-assets-and-renderer-slots.md
Rbanh 0798aa5d57 Build renderer and material component foundations
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.
2026-07-12 00:24:06 -04:00

3.8 KiB

ADR 0035: Shared Material Assets and Renderer Slots

Status

Accepted

Context

Renderer material authoring previously mixed copied MaterialDesc values, imported source-material defaults, and static-mesh draw data. That made a renderer's ownership unclear, encouraged material copies per actor, and left rigged geometry without the same assignment model as static geometry. Matching imported materials by a display name was also unsafe: names are neither unique nor stable when a model is reimported.

Static and skinned renderers need the same Unity-like authoring contract without sharing their mesh or hydration components. A project material must be reusable, an instance must express explicit overrides over one base material, and each renderer must expose stable material slots independently from its draw or skeleton representation.

Decision

  • Project materials use versioned MaterialAsset documents. A MaterialInstanceAsset references one direct base MaterialAsset and stores parameter and texture overrides. Nested material instances are invalid.
  • MaterialRef is the assignment type. Its registry UUID and subasset ID are authoritative; source_path is a cached loading hint that validation or migration may repair after a move.
  • StaticMeshRenderer and SkinnedMeshRenderer each own a RendererMaterialSet. They do not share a mesh component or hydration path. Each RendererMaterialSlot has a stable ID, a presentation name, a read-only imported source_material, and an optional explicit material assignment. Explicit assignment wins; clearing it returns to the imported source material.
  • Static draw parts and imported skinned-hierarchy draws bind to material slots by stable IDs. Reimport reconciles by ID only. An explicit assignment whose source slot disappears is retained as an OrphanedMaterialAssignment; the editor never silently reconnects it by display name.
  • Asset Browser Apply Material assigns a shared material or material instance to every material slot on each selected static or skinned renderer. Renderer inspectors provide per-slot Browse/Select/Locate/Clear controls and expose orphan warnings.
  • HydratedRendererMaterialBinding identifies each runtime draw's owner, slot, and effective material. A skinned renderer material-only edit patches the instantiated hierarchy without reloading its source hierarchy or joints.
  • MaterialPropertyBlocks are runtime-only, per-slot overrides. They do not mutate a shared asset and are excluded from scene and prefab persistence. Persisting a reusable variation requires an explicit material instance.
  • Scene schema v4 migrates legacy renderer assignments into RendererMaterialSet. Project material, material-instance, shader-schema, and scene rewrites are performed by the explicit transactional cargo upgrade-project command; ordinary loading remains read-only.

Consequences

  • Static and skinned renderers have a consistent material-slot workflow while retaining distinct geometry ownership and hydration behavior.
  • An assignment remains a reference rather than a copied material value, so editing or replacing a shared asset does not create actor-local material copies. Material/base/schema/evaluator dependency revisions update the shared runtime handle in place across all assigned slots.
  • Source reimport cannot silently move an override to the wrong draw. Orphans require an explicit user decision to reassign or discard.
  • Legacy primitive/actor MaterialDesc paths remain compatibility paths until their consumers move to renderer slots; new mesh-renderer work uses shared references.
  • Runtime property blocks have no editor promotion workflow yet.
  • Material graph authoring, nested instances, blended/transmissive materials, and a generalized per-renderer property-block inspector are outside this decision.