feat(render-modes): items show real materials in colored mode (not flat clay)

In colored mode (textures on), every item now renders its authored material
— textures, vertex colours, and default colours — instead of being stripped
to the uniform off-white baseMaterial. AI-generated and vertex-coloured items
show their real appearance; slot resolution (override -> curated -> authored)
is unchanged. Monochrome (textures off) still collapses to the furnishing
clay role colour (the escape hatch). Drops the now-unused isAuthored marker.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Wassim SAMAD
2026-06-15 17:17:44 -04:00
co-authored by Claude Fable 5
parent f740f5993b
commit 3d5a36c73d
+6 -14
View File
@@ -9,16 +9,15 @@ import {
type ItemNode, type ItemNode,
isSlotMaterialName, isSlotMaterialName,
LIBRARY_MATERIAL_REF_PREFIX, LIBRARY_MATERIAL_REF_PREFIX,
type LightEffect,
SCENE_MATERIAL_REF_PREFIX, SCENE_MATERIAL_REF_PREFIX,
toLibraryMaterialRef, toLibraryMaterialRef,
type LightEffect,
useInteractive, useInteractive,
useLiveNodeOverrides, useLiveNodeOverrides,
useRegistry, useRegistry,
useScene, useScene,
} from '@pascal-app/core' } from '@pascal-app/core'
import { import {
baseMaterial,
type ColorPreset, type ColorPreset,
createDefaultMaterial, createDefaultMaterial,
createSurfaceRoleMaterial, createSurfaceRoleMaterial,
@@ -121,11 +120,6 @@ const captureItemMeshMaterials = (mesh: Mesh): CapturedItemMaterialData => {
return next return next
} }
const hasCapturedSlot = (captured: CapturedItemMaterialData): boolean =>
Array.isArray(captured.slotIds)
? captured.slotIds.some((slotId) => slotId != null)
: captured.slotIds != null
const isCapturedMaterialArray = ( const isCapturedMaterialArray = (
captured: CapturedItemMaterialData, captured: CapturedItemMaterialData,
): captured is CapturedMultiItemMaterialData => Array.isArray(captured.authoredMaterials) ): captured is CapturedMultiItemMaterialData => Array.isArray(captured.authoredMaterials)
@@ -155,20 +149,19 @@ const resolveItemMaterial = (
curatedRef: string | undefined, curatedRef: string | undefined,
{ {
colorPreset, colorPreset,
isAuthored,
nodeSlots, nodeSlots,
sceneMaterials, sceneMaterials,
shading, shading,
textures, textures,
}: { }: {
colorPreset: ColorPreset colorPreset: ColorPreset
isAuthored: boolean
nodeSlots: ItemNode['slots'] nodeSlots: ItemNode['slots']
sceneMaterials: SceneMaterials sceneMaterials: SceneMaterials
shading: RenderShading shading: RenderShading
textures: boolean textures: boolean
}, },
): Material => { ): Material => {
// Monochrome (textures off): collapse to the themed furnishing clay colour.
if (!textures) return createSurfaceRoleMaterial('furnishing', colorPreset) if (!textures) return createSurfaceRoleMaterial('furnishing', colorPreset)
if (authoredMaterial.name.toLowerCase() === 'glass') return glassMaterial if (authoredMaterial.name.toLowerCase() === 'glass') return glassMaterial
if (slotId != null) { if (slotId != null) {
@@ -178,8 +171,10 @@ const resolveItemMaterial = (
if (curated) return curated if (curated) return curated
return authoredMaterial return authoredMaterial
} }
if (isAuthored) return authoredMaterial // Colored (textures on): show the item's real authored material — its
return baseMaterial(shading) // textures, vertex colours, and default colours — for every item, not just
// slot-authored ones (no more strip-to-clay default).
return authoredMaterial
} }
const BrokenItemFallback = ({ node }: { node: ItemNode }) => { const BrokenItemFallback = ({ node }: { node: ItemNode }) => {
@@ -334,7 +329,6 @@ const ModelRenderer = ({ node }: { node: ItemNode }) => {
if (!root) return if (!root) return
const meshEntries: { mesh: Mesh; captured: CapturedItemMaterialData }[] = [] const meshEntries: { mesh: Mesh; captured: CapturedItemMaterialData }[] = []
let isAuthored = false
root.traverse((child) => { root.traverse((child) => {
if (!(child as Mesh).isMesh) return if (!(child as Mesh).isMesh) return
@@ -345,13 +339,11 @@ const ModelRenderer = ({ node }: { node: ItemNode }) => {
} }
const captured = captureItemMeshMaterials(mesh) const captured = captureItemMeshMaterials(mesh)
if (hasCapturedSlot(captured)) isAuthored = true
if (mesh.name !== 'cutout') meshEntries.push({ mesh, captured }) if (mesh.name !== 'cutout') meshEntries.push({ mesh, captured })
}) })
const materialOptions = { const materialOptions = {
colorPreset, colorPreset,
isAuthored,
nodeSlots: node.slots, nodeSlots: node.slots,
sceneMaterials, sceneMaterials,
shading, shading,