feat(paint-slots): concrete-plate finish + try defaults (wall=concrete, slab=wood plank 48, ceiling=soft white)
- material-library: add 'concrete-plate' KTX2 finish (512, fabric/leather-style pipeline) + editor-app texture mirror. - viewer: shared resolveSlotDefaultMaterial(colour|library ref) so a kind's slot default can be a catalog finish, not just a flat colour. - wall default -> library:concrete-plate (interior + exterior). - slab default -> library:wood-woodplank48 (slab geometry resolves it via the shared helper). - ceiling default -> soft white #f2eee6 (ceiling renders flat-tinted). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
967a905e3b
commit
737c4e9d1d
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 6.6 KiB |
@@ -3860,6 +3860,44 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'concrete-plate',
|
||||||
|
label: 'Concrete Plate',
|
||||||
|
category: 'concrete',
|
||||||
|
surfaces: ['wall', 'floor'],
|
||||||
|
description: 'Smooth cast concrete plate',
|
||||||
|
previewThumbnailUrl: '/material/concrete/concrete_plate/concrete_plate_thumb.webp',
|
||||||
|
preset: {
|
||||||
|
maps: {
|
||||||
|
albedoMap: '/material/concrete/concrete_plate/concrete_plate_basecolor_512.ktx2',
|
||||||
|
normalMap: '/material/concrete/concrete_plate/concrete_plate_normal_512.ktx2',
|
||||||
|
roughnessMap: '/material/concrete/concrete_plate/concrete_plate_roughness_512.ktx2',
|
||||||
|
aoMap: '/material/concrete/concrete_plate/concrete_plate_ao_512.ktx2',
|
||||||
|
},
|
||||||
|
mapProperties: {
|
||||||
|
color: '#ffffff',
|
||||||
|
roughness: 0.8,
|
||||||
|
metalness: 0,
|
||||||
|
repeatX: 0.5,
|
||||||
|
repeatY: 0.5,
|
||||||
|
rotation: 0,
|
||||||
|
wrapS: 'Repeat',
|
||||||
|
wrapT: 'Repeat',
|
||||||
|
normalScaleX: 1,
|
||||||
|
normalScaleY: 1,
|
||||||
|
emissiveIntensity: 1,
|
||||||
|
displacementScale: 0,
|
||||||
|
transparent: false,
|
||||||
|
flipY: false,
|
||||||
|
bumpScale: 1,
|
||||||
|
emissiveColor: '#000000',
|
||||||
|
aoMapIntensity: 1,
|
||||||
|
side: 0,
|
||||||
|
opacity: 1,
|
||||||
|
lightMapIntensity: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'concrete-stucco',
|
id: 'concrete-stucco',
|
||||||
label: 'White Stucco',
|
label: 'White Stucco',
|
||||||
|
|||||||
@@ -52,8 +52,8 @@ export type WallSurfaceSide = 'interior' | 'exterior'
|
|||||||
// May be a `#rrggbb` colour or a `library:<id>` ref. Textures-off still
|
// May be a `#rrggbb` colour or a `library:<id>` ref. Textures-off still
|
||||||
// collapses to the themed wall role (the escape hatch).
|
// collapses to the themed wall role (the escape hatch).
|
||||||
export const WALL_SLOT_DEFAULT: Record<WallSurfaceSide, string> = {
|
export const WALL_SLOT_DEFAULT: Record<WallSurfaceSide, string> = {
|
||||||
interior: '#ffffff',
|
interior: 'library:concrete-plate',
|
||||||
exterior: '#ffffff',
|
exterior: 'library:concrete-plate',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WallSurfaceMaterialSpec = {
|
export type WallSurfaceMaterialSpec = {
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ import type { SlotDeclaration } from '@pascal-app/core'
|
|||||||
|
|
||||||
export type CeilingSlotId = 'surface'
|
export type CeilingSlotId = 'surface'
|
||||||
|
|
||||||
// Visual parity with the retired DEFAULT_CEILING_MATERIAL (warm beige).
|
// Soft white — the default underside colour for an unpainted ceiling. (A
|
||||||
export const CEILING_SLOT_DEFAULT_COLOR = '#f5f5dc'
|
// ceiling renders flat-tinted, so this is a colour, not a `library:` finish.)
|
||||||
|
export const CEILING_SLOT_DEFAULT_COLOR = '#f2eee6'
|
||||||
|
|
||||||
/** A ceiling exposes a single paintable underside surface. */
|
/** A ceiling exposes a single paintable underside surface. */
|
||||||
export function ceilingSlots(): SlotDeclaration[] {
|
export function ceilingSlots(): SlotDeclaration[] {
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ import {
|
|||||||
generateSlabGeometry,
|
generateSlabGeometry,
|
||||||
type RenderShading,
|
type RenderShading,
|
||||||
resolveMaterialRef,
|
resolveMaterialRef,
|
||||||
|
resolveSlotDefaultMaterial,
|
||||||
} from '@pascal-app/viewer'
|
} from '@pascal-app/viewer'
|
||||||
import { FrontSide, Group, type Material, Mesh, type Texture } from 'three'
|
import { FrontSide, Group, type Material, Mesh, type Texture } from 'three'
|
||||||
import { SLAB_SLOT_DEFAULT_COLOR } from './slots'
|
import { SLAB_SLOT_DEFAULT } from './slots'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stage B builder for slab. Reuses `generateSlabGeometry` (pure
|
* Stage B builder for slab. Reuses `generateSlabGeometry` (pure
|
||||||
@@ -62,8 +63,8 @@ function getSlabMaterial(
|
|||||||
return getLegacySlabMaterial(node, shading)
|
return getLegacySlabMaterial(node, shading)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Declared slot default (visual parity with the retired DEFAULT_SLAB_MATERIAL).
|
// Declared slot default — a catalog `library:` finish or a flat colour.
|
||||||
return createDefaultMaterial(SLAB_SLOT_DEFAULT_COLOR, 0.8, shading)
|
return resolveSlotDefaultMaterial(SLAB_SLOT_DEFAULT, shading, 0.8)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLegacySlabMaterial(node: SlabNode, shading: RenderShading): Material {
|
function getLegacySlabMaterial(node: SlabNode, shading: RenderShading): Material {
|
||||||
@@ -83,7 +84,7 @@ function getLegacySlabMaterial(node: SlabNode, shading: RenderShading): Material
|
|||||||
? createDefaultMaterial('#ffffff', 0.5, shading)
|
? createDefaultMaterial('#ffffff', 0.5, shading)
|
||||||
: node.material
|
: node.material
|
||||||
? createMaterial(node.material, shading).clone()
|
? createMaterial(node.material, shading).clone()
|
||||||
: createDefaultMaterial(SLAB_SLOT_DEFAULT_COLOR, 0.8, shading)
|
: createDefaultMaterial('#e5e5e5', 0.8, shading)
|
||||||
|
|
||||||
if (preset) {
|
if (preset) {
|
||||||
applyMaterialPresetToMaterials(material, preset)
|
applyMaterialPresetToMaterials(material, preset)
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ import type { SlotDeclaration } from '@pascal-app/core'
|
|||||||
|
|
||||||
export type SlabSlotId = 'surface'
|
export type SlabSlotId = 'surface'
|
||||||
|
|
||||||
// Visual parity with the retired DEFAULT_SLAB_MATERIAL (light grey).
|
// Declared default appearance for an unpainted slab surface in colored mode —
|
||||||
export const SLAB_SLOT_DEFAULT_COLOR = '#e5e5e5'
|
// a catalog `library:<id>` finish or a `#rrggbb` colour. Textures-off collapses
|
||||||
|
// to the themed floor role (the escape hatch).
|
||||||
|
export const SLAB_SLOT_DEFAULT = 'library:wood-woodplank48'
|
||||||
|
|
||||||
/** A slab exposes a single paintable floor surface. */
|
/** A slab exposes a single paintable floor surface. */
|
||||||
export function slabSlots(): SlotDeclaration[] {
|
export function slabSlots(): SlotDeclaration[] {
|
||||||
return [{ slotId: 'surface', label: 'Surface', default: SLAB_SLOT_DEFAULT_COLOR }]
|
return [{ slotId: 'surface', label: 'Surface', default: SLAB_SLOT_DEFAULT }]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ export {
|
|||||||
PRESET_PALETTES,
|
PRESET_PALETTES,
|
||||||
type RenderShading,
|
type RenderShading,
|
||||||
resolveMaterialRef,
|
resolveMaterialRef,
|
||||||
|
resolveSlotDefaultMaterial,
|
||||||
resolveSurfaceColor,
|
resolveSurfaceColor,
|
||||||
WHITE_PALETTE,
|
WHITE_PALETTE,
|
||||||
} from './lib/materials'
|
} from './lib/materials'
|
||||||
|
|||||||
@@ -516,6 +516,26 @@ export function resolveMaterialRef(
|
|||||||
return createMaterial(sceneMaterial.material, shading)
|
return createMaterial(sceneMaterial.material, shading)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve a node kind's declared slot default — either a catalog `library:<id>`
|
||||||
|
* finish or a flat `#rrggbb` colour — to a renderable material. Shared by the
|
||||||
|
* procedural kinds whose colored-mode unpainted appearance comes from a
|
||||||
|
* declarative default (slab, wall).
|
||||||
|
*/
|
||||||
|
export function resolveSlotDefaultMaterial(
|
||||||
|
slotDefault: string,
|
||||||
|
shading: RenderShading = 'rendered',
|
||||||
|
roughness = 0.9,
|
||||||
|
): THREE.Material {
|
||||||
|
if (parseMaterialRef(slotDefault)?.kind === 'library') {
|
||||||
|
return (
|
||||||
|
createMaterialFromPresetRef(slotDefault, shading) ??
|
||||||
|
createDefaultMaterial('#ffffff', roughness, shading)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return createDefaultMaterial(slotDefault, roughness, shading)
|
||||||
|
}
|
||||||
|
|
||||||
export function createDefaultMaterial(
|
export function createDefaultMaterial(
|
||||||
color = '#ffffff',
|
color = '#ffffff',
|
||||||
roughness = 0.9,
|
roughness = 0.9,
|
||||||
|
|||||||
Reference in New Issue
Block a user