From 0be6d84c9888f0775532748231a6a20e43b07fcf Mon Sep 17 00:00:00 2001 From: Developer Date: Mon, 30 Mar 2026 20:29:29 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=AE=8C=E5=96=84=E6=9D=90?= =?UTF-8?q?=E8=B4=A8=E7=B3=BB=E7=BB=9F=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复 node-actions.ts 中 forEach 返回值 lint 警告 - 更新材质 schema 定义和渲染器 - wall-cutout.tsx 材质颜色保留修复 --- packages/core/src/schema/material.ts | 90 ++++++++++++++++--- .../core/src/store/actions/node-actions.ts | 12 ++- packages/core/src/utils/clone-scene-graph.ts | 4 +- .../src/components/editor/export-manager.tsx | 2 +- .../src/components/tools/wall/wall-tool.tsx | 7 +- .../renderers/ceiling/ceiling-renderer.tsx | 7 +- .../roof-segment/roof-segment-renderer.tsx | 2 +- .../renderers/roof/roof-renderer.tsx | 9 +- .../renderers/slab/slab-renderer.tsx | 9 +- packages/viewer/src/hooks/use-gltf-ktx2.tsx | 1 + packages/viewer/src/lib/materials.ts | 5 +- .../viewer/src/systems/wall/wall-cutout.tsx | 14 ++- 12 files changed, 129 insertions(+), 33 deletions(-) diff --git a/packages/core/src/schema/material.ts b/packages/core/src/schema/material.ts index a43d5edc..fe9a7a80 100644 --- a/packages/core/src/schema/material.ts +++ b/packages/core/src/schema/material.ts @@ -38,16 +38,86 @@ export const MaterialSchema = z.object({ export type MaterialSchema = z.infer export const DEFAULT_MATERIALS: Record = { - white: { color: '#ffffff', roughness: 0.9, metalness: 0, opacity: 1, transparent: false, side: 'front' }, - brick: { color: '#8b4513', roughness: 0.85, metalness: 0, opacity: 1, transparent: false, side: 'front' }, - concrete: { color: '#808080', roughness: 0.8, metalness: 0, opacity: 1, transparent: false, side: 'front' }, - wood: { color: '#deb887', roughness: 0.7, metalness: 0, opacity: 1, transparent: false, side: 'front' }, - glass: { color: '#87ceeb', roughness: 0.1, metalness: 0.1, opacity: 0.3, transparent: true, side: 'double' }, - metal: { color: '#c0c0c0', roughness: 0.3, metalness: 0.9, opacity: 1, transparent: false, side: 'front' }, - plaster: { color: '#f5f5dc', roughness: 0.95, metalness: 0, opacity: 1, transparent: false, side: 'front' }, - tile: { color: '#d3d3d3', roughness: 0.4, metalness: 0.1, opacity: 1, transparent: false, side: 'front' }, - marble: { color: '#fafafa', roughness: 0.2, metalness: 0.1, opacity: 1, transparent: false, side: 'front' }, - custom: { color: '#ffffff', roughness: 0.5, metalness: 0, opacity: 1, transparent: false, side: 'front' }, + white: { + color: '#ffffff', + roughness: 0.9, + metalness: 0, + opacity: 1, + transparent: false, + side: 'front', + }, + brick: { + color: '#8b4513', + roughness: 0.85, + metalness: 0, + opacity: 1, + transparent: false, + side: 'front', + }, + concrete: { + color: '#808080', + roughness: 0.8, + metalness: 0, + opacity: 1, + transparent: false, + side: 'front', + }, + wood: { + color: '#deb887', + roughness: 0.7, + metalness: 0, + opacity: 1, + transparent: false, + side: 'front', + }, + glass: { + color: '#87ceeb', + roughness: 0.1, + metalness: 0.1, + opacity: 0.3, + transparent: true, + side: 'double', + }, + metal: { + color: '#c0c0c0', + roughness: 0.3, + metalness: 0.9, + opacity: 1, + transparent: false, + side: 'front', + }, + plaster: { + color: '#f5f5dc', + roughness: 0.95, + metalness: 0, + opacity: 1, + transparent: false, + side: 'front', + }, + tile: { + color: '#d3d3d3', + roughness: 0.4, + metalness: 0.1, + opacity: 1, + transparent: false, + side: 'front', + }, + marble: { + color: '#fafafa', + roughness: 0.2, + metalness: 0.1, + opacity: 1, + transparent: false, + side: 'front', + }, + custom: { + color: '#ffffff', + roughness: 0.5, + metalness: 0, + opacity: 1, + transparent: false, + side: 'front', + }, } export function resolveMaterial(material?: MaterialSchema): MaterialProperties { diff --git a/packages/core/src/store/actions/node-actions.ts b/packages/core/src/store/actions/node-actions.ts index e162a873..e0cce687 100644 --- a/packages/core/src/store/actions/node-actions.ts +++ b/packages/core/src/store/actions/node-actions.ts @@ -104,11 +104,17 @@ export const updateNodesAction = ( }) // Collect all IDs that need to be marked dirty - updates.forEach((u) => idsToMarkDirty.add(u.id)) - parentsToUpdate.forEach((pId) => idsToMarkDirty.add(pId)) + for (const u of updates) { + idsToMarkDirty.add(u.id) + } + for (const pId of parentsToUpdate) { + idsToMarkDirty.add(pId) + } // Add to pending updates set - idsToMarkDirty.forEach((id) => pendingUpdates.add(id)) + for (const id of idsToMarkDirty) { + pendingUpdates.add(id) + } // Cancel any pending RAF and schedule a new one if (pendingRafId !== null) { diff --git a/packages/core/src/utils/clone-scene-graph.ts b/packages/core/src/utils/clone-scene-graph.ts index 2eb3ff39..e4aa55b2 100644 --- a/packages/core/src/utils/clone-scene-graph.ts +++ b/packages/core/src/utils/clone-scene-graph.ts @@ -52,9 +52,7 @@ export function cloneSceneGraph(sceneGraph: SceneGraph): SceneGraph { // Remap children array (walls, levels, buildings, sites, items can have children) if ('children' in clonedNode && Array.isArray(clonedNode.children)) { - ;(clonedNode as Record).children = ( - clonedNode.children as string[] - ) + ;(clonedNode as Record).children = (clonedNode.children as string[]) .map((childId) => idMap.get(childId)) .filter((id): id is string => id !== undefined) } diff --git a/packages/editor/src/components/editor/export-manager.tsx b/packages/editor/src/components/editor/export-manager.tsx index 4bac49cb..50f1025b 100644 --- a/packages/editor/src/components/editor/export-manager.tsx +++ b/packages/editor/src/components/editor/export-manager.tsx @@ -4,8 +4,8 @@ import { useViewer } from '@pascal-app/viewer' import { useThree } from '@react-three/fiber' import { useEffect } from 'react' import { GLTFExporter } from 'three/examples/jsm/exporters/GLTFExporter.js' -import { STLExporter } from 'three/examples/jsm/exporters/STLExporter.js' import { OBJExporter } from 'three/examples/jsm/exporters/OBJExporter.js' +import { STLExporter } from 'three/examples/jsm/exporters/STLExporter.js' export function ExportManager() { const scene = useThree((state) => state.scene) diff --git a/packages/editor/src/components/tools/wall/wall-tool.tsx b/packages/editor/src/components/tools/wall/wall-tool.tsx index 8ec3169a..1ecf6576 100644 --- a/packages/editor/src/components/tools/wall/wall-tool.tsx +++ b/packages/editor/src/components/tools/wall/wall-tool.tsx @@ -6,7 +6,12 @@ import { markToolCancelConsumed } from '../../../hooks/use-keyboard' import { EDITOR_LAYER } from '../../../lib/constants' import { sfxEmitter } from '../../../lib/sfx-bus' import { CursorSphere } from '../shared/cursor-sphere' -import { createWallOnCurrentLevel, snapWallDraftPoint, WALL_MIN_LENGTH, type WallPlanPoint } from './wall-drafting' +import { + createWallOnCurrentLevel, + snapWallDraftPoint, + WALL_MIN_LENGTH, + type WallPlanPoint, +} from './wall-drafting' const WALL_HEIGHT = 2.5 diff --git a/packages/viewer/src/components/renderers/ceiling/ceiling-renderer.tsx b/packages/viewer/src/components/renderers/ceiling/ceiling-renderer.tsx index e1d2717c..4e79c3c0 100644 --- a/packages/viewer/src/components/renderers/ceiling/ceiling-renderer.tsx +++ b/packages/viewer/src/components/renderers/ceiling/ceiling-renderer.tsx @@ -3,7 +3,7 @@ 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 { createMaterial, DEFAULT_CEILING_MATERIAL } from '../../../lib/materials' +import { DEFAULT_CEILING_MATERIAL } from '../../../lib/materials' import { NodeRenderer } from '../node-renderer' const gridScale = 5 @@ -46,7 +46,10 @@ export const CeilingRenderer = ({ node }: { node: CeilingNode }) => { const color = props?.color || '#999999' return createCeilingMaterials(color) } - return { topMaterial: createCeilingMaterials().topMaterial, bottomMaterial: DEFAULT_CEILING_MATERIAL } + return { + topMaterial: createCeilingMaterials().topMaterial, + bottomMaterial: DEFAULT_CEILING_MATERIAL, + } }, [node.material, node.material?.preset, node.material?.properties, node.material?.texture]) return ( diff --git a/packages/viewer/src/components/renderers/roof-segment/roof-segment-renderer.tsx b/packages/viewer/src/components/renderers/roof-segment/roof-segment-renderer.tsx index 92ffed90..327935ce 100644 --- a/packages/viewer/src/components/renderers/roof-segment/roof-segment-renderer.tsx +++ b/packages/viewer/src/components/renderers/roof-segment/roof-segment-renderer.tsx @@ -35,4 +35,4 @@ export const RoofSegmentRenderer = ({ node }: { node: RoofSegmentNode }) => { ) -} \ No newline at end of file +} diff --git a/packages/viewer/src/components/renderers/roof/roof-renderer.tsx b/packages/viewer/src/components/renderers/roof/roof-renderer.tsx index e5c88b51..c89174f0 100644 --- a/packages/viewer/src/components/renderers/roof/roof-renderer.tsx +++ b/packages/viewer/src/components/renderers/roof/roof-renderer.tsx @@ -2,7 +2,7 @@ import { type RoofNode, useRegistry } from '@pascal-app/core' import { useMemo, useRef } from 'react' import type * as THREE from 'three' import { useNodeEvents } from '../../../hooks/use-node-events' -import { createMaterial, DEFAULT_ROOF_MATERIAL } from '../../../lib/materials' +import { createMaterial } from '../../../lib/materials' import useViewer from '../../../store/use-viewer' import { NodeRenderer } from '../node-renderer' import { roofDebugMaterials, roofMaterials } from './roof-materials' @@ -31,12 +31,7 @@ export const RoofRenderer = ({ node }: { node: RoofNode }) => { visible={node.visible} {...handlers} > - + diff --git a/packages/viewer/src/components/renderers/slab/slab-renderer.tsx b/packages/viewer/src/components/renderers/slab/slab-renderer.tsx index f33b6ec0..0abfbdc4 100644 --- a/packages/viewer/src/components/renderers/slab/slab-renderer.tsx +++ b/packages/viewer/src/components/renderers/slab/slab-renderer.tsx @@ -18,7 +18,14 @@ export const SlabRenderer = ({ node }: { node: SlabNode }) => { }, [node.material, node.material?.preset, node.material?.properties, node.material?.texture]) return ( - + ) diff --git a/packages/viewer/src/hooks/use-gltf-ktx2.tsx b/packages/viewer/src/hooks/use-gltf-ktx2.tsx index 28578c76..040beaf7 100644 --- a/packages/viewer/src/hooks/use-gltf-ktx2.tsx +++ b/packages/viewer/src/hooks/use-gltf-ktx2.tsx @@ -36,4 +36,5 @@ const useGLTFKTX2 = (path: string): ReturnType => { loader.setMeshoptDecoder(MeshoptDecoder) }) } + export { useGLTFKTX2 } diff --git a/packages/viewer/src/lib/materials.ts b/packages/viewer/src/lib/materials.ts index 97e5b46c..369ec7e0 100644 --- a/packages/viewer/src/lib/materials.ts +++ b/packages/viewer/src/lib/materials.ts @@ -34,7 +34,10 @@ export function createMaterial(material?: MaterialSchema): THREE.MeshStandardMat return threeMaterial } -export function createDefaultMaterial(color: string = '#ffffff', roughness: number = 0.9): THREE.MeshStandardMaterial { +export function createDefaultMaterial( + color: string = '#ffffff', + roughness: number = 0.9, +): THREE.MeshStandardMaterial { return new THREE.MeshStandardMaterial({ color, roughness, diff --git a/packages/viewer/src/systems/wall/wall-cutout.tsx b/packages/viewer/src/systems/wall/wall-cutout.tsx index 6568d471..0b50da19 100644 --- a/packages/viewer/src/systems/wall/wall-cutout.tsx +++ b/packages/viewer/src/systems/wall/wall-cutout.tsx @@ -103,7 +103,12 @@ function getMaterialsForWall(wallNode: WallNode): WallMaterials { return result } -function getWallHideState(wallNode: WallNode, wallMesh: Mesh, wallMode: string, cameraDir: Vector3): boolean { +function getWallHideState( + wallNode: WallNode, + wallMesh: Mesh, + wallMode: string, + cameraDir: Vector3, +): boolean { let hideWall = wallNode.frontSide === 'interior' && wallNode.backSide === 'interior' if (wallMode === 'up') { @@ -167,7 +172,10 @@ export const WallCutout = () => { } else { const currentMaterial = (wallMesh as Mesh).material const materials = wallMaterialCache.get(wallId) - if (!materials || currentMaterial !== (hideWall ? materials.invisible : materials.visible)) { + if ( + !materials || + currentMaterial !== (hideWall ? materials.invisible : materials.visible) + ) { const newMaterials = getMaterialsForWall(wallNode) ;(wallMesh as Mesh).material = hideWall ? newMaterials.invisible : newMaterials.visible } @@ -202,4 +210,4 @@ export const WallCutout = () => { } }) return null -} \ No newline at end of file +}