63 lines
4.0 KiB
Markdown
63 lines
4.0 KiB
Markdown
# 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.
|
|
- `MaterialPropertyBlocks` currently define the runtime-only schema and persistence exclusion, but
|
|
renderer application and the editor promote-to-instance transaction are not implemented. Gitea
|
|
#53 owns that complete workflow; callers must not treat the component as visibly applied yet.
|
|
- Material graph authoring, nested instances, blended/transmissive materials, and a generalized
|
|
per-renderer property-block inspector are outside this decision.
|