Developer 0be6d84c98 refactor: 完善材质系统相关代码
- 修复 node-actions.ts 中 forEach 返回值 lint 警告
- 更新材质 schema 定义和渲染器
- wall-cutout.tsx 材质颜色保留修复
2026-03-30 20:29:29 +08:00

73 lines
2.3 KiB
TypeScript

import { type CeilingNode, useRegistry } from '@pascal-app/core'
import { useMemo, useRef } from 'react'
import { float, mix, positionWorld, smoothstep } from 'three/tsl'
import { BackSide, FrontSide, type Mesh, MeshBasicNodeMaterial } from 'three/webgpu'
import { useNodeEvents } from '../../../hooks/use-node-events'
import { DEFAULT_CEILING_MATERIAL } from '../../../lib/materials'
import { NodeRenderer } from '../node-renderer'
const gridScale = 5
const gridX = positionWorld.x.mul(gridScale).fract()
const gridY = positionWorld.z.mul(gridScale).fract()
const lineWidth = 0.05
const lineX = smoothstep(lineWidth, 0, gridX).add(smoothstep(1.0 - lineWidth, 1.0, gridX))
const lineY = smoothstep(lineWidth, 0, gridY).add(smoothstep(1.0 - lineWidth, 1.0, gridY))
const gridPattern = lineX.max(lineY)
const gridOpacity = mix(float(0.2), float(0.6), gridPattern)
function createCeilingMaterials(color: string = '#999999') {
const topMaterial = new MeshBasicNodeMaterial({
color,
transparent: true,
depthWrite: false,
side: FrontSide,
})
topMaterial.opacityNode = gridOpacity
const bottomMaterial = new MeshBasicNodeMaterial({
color,
transparent: true,
side: BackSide,
})
return { topMaterial, bottomMaterial }
}
export const CeilingRenderer = ({ node }: { node: CeilingNode }) => {
const ref = useRef<Mesh>(null!)
useRegistry(node.id, 'ceiling', ref)
const handlers = useNodeEvents(node, 'ceiling')
const materials = useMemo(() => {
const mat = node.material
if (mat) {
const props = mat.properties
const color = props?.color || '#999999'
return createCeilingMaterials(color)
}
return {
topMaterial: createCeilingMaterials().topMaterial,
bottomMaterial: DEFAULT_CEILING_MATERIAL,
}
}, [node.material, node.material?.preset, node.material?.properties, node.material?.texture])
return (
<mesh material={materials.bottomMaterial} ref={ref}>
<boxGeometry args={[0, 0, 0]} />
<mesh
material={materials.topMaterial}
name="ceiling-grid"
{...handlers}
scale={0}
visible={false}
>
<boxGeometry args={[0, 0, 0]} />
</mesh>
{node.children.map((childId) => (
<NodeRenderer key={childId} nodeId={childId} />
))}
</mesh>
)
}