
Pascal 3D 編輯器材質與主題體系詳解從表面角色到場景主題的完整著色管線【免費下載鏈接】editorOpen-source 3D architectural editor with a local CLI, MCP tools, and practical workflows for humans and AI agents.項目地址: https://gitcode.com/GitHub_Trending/editor93/editor本文檔基于wiki/architecture/materials-and-themes.md編寫結合packages/viewer、packages/core、packages/nodes等源碼展開。文中提到的文件路徑均相對倉庫根目錄。導讀本指南系統講解開源 3D 建筑編輯器 Pascal當前倉庫中表面顏色surface colour的完整機制從節點如何聲明表面角色surfaceRole、顏色如何被解析與緩存到四種顏色預設colorPreset與十余種場景主題sceneTheme如何正交疊加、以及自定義網格Block的面級材質槽Slots與紋理世界尺度UV 以米為單位約定。讀完本文你將掌握 Pascal 查看器packages/viewer中shading、textures、colorPreset、sceneTheme、shadows、edges六大外觀軸的全部含義與協作方式理解無紋理表面永遠使用主題化角色顏色這一核心規則并能獨立為倉庫新增一個場景主題或為自定義網格接入MaterialRef材質系統。一、外觀軸The axes六個正交的外觀狀態Pascal 把節點外觀拆成一組互相正交的狀態軸全部集中保存在查看器的useViewerstore 中packages/viewer/src/store/use-viewer.ts狀態取值控制內容shadingsolid \| renderedsolidMeshLambertNodeMaterial無 SSGI/AOrenderedMeshStandardNodeMaterial SSGI/AO屏幕空間全局光照/環境光遮蔽texturesboolean擁有真實材質/預設的表面是否顯示其紋理貼圖colorPresetclay \| white \| mono \| blueprint無紋理表面的按角色基礎調色板sceneTheme主題 idstudio、mediterranean、night、verdant等光照 背景 地面 按角色的顏色色調詳見場景主題shadowsboolean平行光投影常開的 key light見 packages/viewer/src/components/viewer/lights.tsxedgesoff \| soft \| strong屏幕空間墨水描邊在post-processing.tsx中處理lib/ink-edges.ts從 use-viewer.ts 的狀態定義可以看到shading、textures、colorPreset等字段均帶對應的setXxxsetter且shadingByContext讓編輯器editor默認使用solid、社區查看器viewer默認使用rendered——兩者可以有不同的默認著色模式。關鍵設計shading/textures/colorPreset按上下文context持久化而shadingByContext正是PartialRecordRenderContext, RenderShading類型RenderContext editor | viewer即同一場景在編輯器與查看器里可以分別記住各自的著色偏好。二、表面角色Surface rolesCore 只存令牌不存顏色core包為每個注冊表種類registry kind提供一個可選的表面角色令牌聲明在其NodeDefinition上packages/core/src/registry/types.tssurfaceRole?: wall | floor | ceiling | roof | joinery | glazing | furnishing這一設計非常克制core只存儲令牌字符串不攜帶任何顏色也從不 import three.js。顏色解析完全發生在查看器層。令牌的意義在于墻wall、樓板slab、柱column等不同種類可以通過各自的surfaceRole從同一份調色板里解析出不同的顏色——同一個clay預設墻是#dcd6c7屋頂是#b8ad96玻璃是#c8d4dc。從源碼可見SurfaceRole類型被packages/viewer、packages/core多處引用是整個材質體系的最小契約單元。三、解析顏色單一事實來源與緩存鍵顏色解析的唯一事實來源在 packages/viewer/src/lib/materials.tsresolveSurfaceColor(role, colorPreset, sceneThemeId?) // getSceneTheme(sceneThemeId).clayTints?.[role] // theme override, if any // ?? PRESET_PALETTES[colorPreset][role] // else the preset palette實際實現materials.ts為export function resolveSurfaceColor( role: SurfaceRole, preset: ColorPreset, sceneThemeId?: string, ): string { // 主題可以按角色覆蓋顏色例如地中海主題的藍色屋頂未覆蓋時回退到所選顏色預設的調色板。 const tints sceneThemeId ? getSceneTheme(sceneThemeId).clayTints : undefined return tints?.[role] ?? (PRESET_PALETTES[preset] ?? CLAY_PALETTE)[role] }3.1 四種顏色預設的真實色值四個預設分別定義在 materials.ts 中每個都覆蓋全部 7 種表面角色clay黏土灰| 角色 | 色值 | |---|---| | wall |#dcd6c7| | floor |#cfc8b6| | ceiling |#e4ded0| | roof |#b8ad96| | joinery |#c4bba6| | glazing |#c8d4dc| | furnishing |#d2ccbe|white白色——源碼注釋特別說明albedo 被鉗制在約 0.83 線性值最大通道#eb因為真實白漆反射率約 80%純白 albedo 會殺死 GI/陰影對比度 wall#ebeae6、floor#e7e4dd、ceiling#ebeae6、roof#dedbd2、joinery#e5e2d9、glazing#dbe8ee、furnishing#e9e7e1。mono單色灰wall#c8c8c8、floor#b8b8b8、ceiling#d8d8d8、roof#9a9a9a、joinery#adadad、glazing#c2cbd0、furnishing#c0c0c0。blueprint藍圖藍wall#90a9c7、floor#7f98ba、ceiling#aec0d8、roof#5f789b、joinery#6f86a8、glazing#b6d7ea、furnishing#8ba2bf。3.2createSurfaceRoleMaterial與緩存鍵createSurfaceRoleMaterial(role, colorPreset, side?, sceneThemeId?)把解析出的顏色包裝成一個受光照的MeshLambertNodeMaterialmaterials.ts并按role-preset-side-sceneTheme組合做緩存const cacheKey ${role}-${preset}-${resolvedSide}-${sceneThemeId ?? base}緩存鍵正是每個消費方都必須把sceneTheme一路傳下來的根本原因——否則切換主題時會命中舊主題的陳舊緩存材質。另外兩個實現細節值得注意glazing 特殊處理玻璃角色強制使用FrontSiderole glazing ? THREE.FrontSide : ...且depthWrite: false、opacity: 0.25、transparent: true。原因是 MRT scenePassSSGI 的 diffuseColor/normal 目標中任何DoubleSideNodeMaterial 都會觸發 WebGPU 渲染管線校驗失敗back-face 變體缺少 MRT 輸出報錯 Color target has no corresponding fragment stage output 并污染整個渲染上下文。需要雙面可見時應把宿主網格旋轉 180° 讓 FrontSide 朝向觀察者。所有緩存材質都打上userData.__pascalCachedMaterial true標記供幾何重建時區分共享緩存材質與節點私有材質。3.3 材質緩存與紋理加載管線packages/viewer/src/lib/materials.ts 還維護了四類緩存materialCache預設/普通材質、defaultMaterialCache默認色材質、surfaceRoleMaterialCache角色材質、textureCache紋理。紋理支持.ktx2格式通過共享的 KTX2Loader 轉碼支持在 viewer 初始化時檢測一次與普通圖片兩種加載路徑且wrapS/wrapT/repeat/rotation/flipY等貼圖屬性均來自MaterialMapProperties見 packages/core/src/material-library.ts 中每個目錄項的mapProperties。四、核心規則兩種模式下無紋理表面都用主題色這是整個外觀體系最重要的一條規則對于沒有聲明插槽默認值slot defaults的種類有紋理僅當該節點顯式帶有materialPreset或material時才成立textures關閉→ 每個表面都使用resolveSurfaceColor(role, …)textures開啟→ 有紋理的表面顯示紋理無紋理表面仍然使用resolveSurfaceColor而不是硬編碼的白色/灰色默認值。因此選擇地中海Mediterranean主題會得到藍色屋頂 暖色墻而且完全不需要動textures開關。系統不存在全白模式——無紋理永遠意味著主題化的角色顏色。4.1 各種類的接入位置種類角色顏色應用位置wallpackages/viewer/src/systems/wall/wall-materials.tsgetMaterialsForWall每幀由wall-cutout.tsx重新應用roof / roof-segmentpackages/viewer/src/systems/roof/roof-materials.tsgetRoofMaterialArrayslabpackages/nodes/src/slab/geometry.tsgetSlabSlotMaterialceilingpackages/nodes/src/ceiling/renderer.tsx通用注冊表種類packages/viewer/src/systems/geometry/geometry-system.tsx →applyDefaultSurfaceRoletextures 關閉時door / windowpackages/viewer/src/systems/door/door-system.tsx / window-system.tsxstair / column / item / elevatorpackages/nodes/kind/renderer.tsx每個接入點都會從useViewer讀取shading/textures/colorPreset/sceneTheme或從GeometrySystem線程化傳入并且必須把sceneTheme放進材質緩存鍵和重建依賴數組中否則切換主題不會重新著色。4.2 GeometrySystem 的聯動機制geometry-system.tsx 用useEffect把外觀狀態作為故意的重建觸發器shading、textures、colorPreset、sceneTheme任一變化都會把所有聲明了def.geometry的節點重新標記為 dirty從而觸發幾何重建并取用新外觀。源碼中注釋明確說明這四個值是re-run TRIGGERS而非函數體讀取值刪除它們會靜默破壞外觀模式切換。同時def.geometryKey機制把全局渲染輸入折疊進緩存鍵geometry-system.tsxconst builtKey ${shading}|${textures}|${colorPreset}|${sceneTheme}|${def.geometryKey(effectiveNode)}|${childLiveOverrideKey}這樣主題/著色變化永遠不會被geometryKey的輸入未變則跳過重建邏輯誤跳過而當!textures def.surfaceRole時系統調用applyDefaultSurfaceRole(built, def.surfaceRole, colorPreset, sceneTheme)第 234-236 行統一給通用幾何體套上角色顏色。4.3 天花板與樓板的插槽默認值細節天花板和樓板在帶色textures開啟模式下使用聲明的插槽默認值declared slot defaults。實現上有幾點工程細節見 geometry-system.tsx 與 slab 幾何代碼天花板底面在兩種外觀下都使用不透明的BackSide材質只有ceiling-grid做混合blend。樓板頂面、側面/底面與可選的地形裙邊terrain skirt網格可以分別批量處理batch。扁平插槽默認值按顏色、粗糙度與著色模式共享 viewer 緩存slab 的舊版緩存材質攜帶__pascalCachedMaterial標記使幾何重建后共享材質仍存活。透明的插槽覆蓋slot overrides自己繪制自己不參與共享緩存。五、自定義網格Block的面級材質MaterialRef 與 SlotsBlock自定義網格通過穩定的、用戶可命名的對象插槽復用MaterialRef模型BlockNode.slots把插槽 ID 映射到scene:或library:材質引用slotNames存儲用戶可編輯的插槽標簽每個BlockFace.materialSlot存儲一個插槽 IDbody是永久基礎插槽也是未綁定/未解析插槽的回退目標。幾何構建器為每個拓撲面topology face生成一個 Three.js group并按節點穩定的插槽 ID 順序生成材質數組渲染材質順序發布在userData.slotIds每個面的頂點范圍記錄在geometry.userData.blockFaces。5.1 繪制能力Paint的命中映射Paint 工具重新對網格做射線檢測raycast把命中三角形通過這些頂點范圍映射到穩定的拓撲面 ID因此預覽與提交只影響該面。每個面的 UV 保留下文世界尺度投影契約。5.2 插槽交互編輯器中的 Slots 集合Block 檢查器把這一集合稱為Slots。交互規則用戶可重命名插槽Paint 工具通過可復用的 scene-material 數據塊改變插槽材質。編輯模式下選中一個或多個面后點擊某個插槽立即把那些面綁定到該插槽——沒有單獨的 Assign / Select / Deselect 按鈕行。在已選面的情況下添加插槽同一場景更新中創建插槽、綁定那些面、并分配一個明顯不同的生成強調材質accent material——這樣在用戶選定最終涂裝材質之前新表面在編輯模式和渲染模型中都能肉眼可見。無選中面時 Add Slot 是 no-op避免產生不可見的無用插槽。刪除非 body 插槽在同一節點更新中把所有已分配面重新映射回bodybody成為激活的賦值來源可復用的 scene/library 材質仍可供其他節點使用。5.3 全局 Paint 工具與拓撲操作符的確定性全局 Paint 工具解析命中面的已分配插槽改變該插槽的材質綁定。全新網格的每個面都綁定到body所以第一次涂裝會更新整個網格一旦面被分配到命名插槽涂裝其中任意面都會更新使用該插槽的所有面。一次性材質在創建可復用 scene 材質前會先復用結構匹配的 scene 材質。擦除Erase清除插槽綁定body回到墻角色默認值其他未綁定插槽回退到body。拓撲操作符保持賦值確定性保留與變換的面保持其插槽擠出蓋/側、內縮蓋/環繼承源面環切loop-cut片段繼承被切分的面倒角帶bevel bands與混合材質溶解使用穩定topology.faces順序中的第一個相鄰面刪除使用某插槽的最后一個面不會刪除其可復用材質。5.4 外部插件渲染器的接入契約插件渲染器通過公開的pascal-app/viewer表面遵循同樣的四個軸。對導入的層級結構先一次性捕獲其作者材質再響應式地應用以下映射宿主狀態導入材質帶色 Rendered作者材質帶色 Solid緩存 Lambert 變體保留顏色、albedo 貼圖、alpha 與插槽MonochromecreateSurfaceRoleMaterial(surfaceRole, colorPreset, side, sceneTheme)適配器屬于插件渲染器——因為它擁有層級結構知道哪些表面是 furnishing、glazing 還是其他角色。材質交換發生在偏好變化時絕不在useFrame中。銷毀 loader 擁有的層級結構前先恢復作者材質只銷毀插件擁有的變體宿主緩存的角色材質保持不動。另外描邊edges與昂貴的渲染管線不需要插件材質鉤子——它們是覆蓋SCENE_LAYER的屏幕空間宿主通道。放置幽靈placement ghosts應使用編輯器疊加層overlay layer保持清晰且不進入場景深度/法線目標。六、場景主題Scene themes一個SceneThemepackages/viewer/src/lib/scene-themes.ts把定義一個look所需的一切打包字段驅動appearance: light \| dark2D 場景 chrome——畫布背景、網格線顏色、測量標簽/光標對比度沒有獨立的淺/深色開關主題擁有這一切background3D 背景在 packages/viewer/src/components/viewer/post-processing.tsx 中與無幾何處混合backgroundSky?可選的天頂顏色后處理管線渲染從該色頂部到background地平線的垂直屏幕空間漸變省略則用純backgroundground場地地面填充nodes/site/renderer.tsx與無限地面遮擋平面viewer/ground-occluder.tsx。與background分離使深色主題得到受光照的中調地面而非近黑lights/ambient/hemi燈光裝置lights.tsx一盞 key light 投射陰影toneMappingExposure渲染器曝光clayTints?每SurfaceRole的顏色覆蓋疊加在colorPreset之上編輯器 UI chrome 永遠是深色的固定document.body.classList.add(dark)與appearance無關。6.1 內置主題速查倉庫內置 9 個主題scene-themes.tsid名稱appearancebackgroundground代表性 clayTintsstudioStudiolight#fbfbfa#e9e7e2wall#e9e5db/ roof#c4bba6paperPaperlight#ede9df#e7e1d3wall#efe9da/ roof#b9b09asunsetSunsetlight#f6e8d4#ecd9bfwall#f3e3cf/ roof#a6764fovercastOvercastlight#e6e7e6#dadcd9wall#dedfdc/ roof#a3a49eblueprintBlueprintlight#dde6ef#c9d6e6wall#9fb6d2/ roof#5f789bmediterraneanMediterraneanlight#bdd6e8#ddd2bbwall#f6f1e6/roof#3e6585藍twilightTwilightdark#3a3550#67618awall#c5b9cf/ roof#5b4f74nightNightdark#1f2433#4a5470wall#aab3c6/ roof#5b6680verdantVerdantlight#d6e4d2#c7d6b4wall#eef0e6/ roof#6f8a5a主題查找函數getSceneTheme(id)未命中時回退到SCENE_THEMES[0]即studioSCENE_THEME_IDS導出全部 id 供 UI 使用。6.2 添加一個主題把SceneTheme追加到SCENE_THEMES數組并填齊所有必填字段即可。clayTints是Partial類型——省略的角色自動回退到當前colorPreset。主題選擇器工具欄 社區 overlay會基于clayTints疊加在background上渲染 2×2 色塊因此至少填充wall/roof/floor/glazing才能得到像樣的預覽色塊。七、紋理世界尺度UV 以米為單位每一個程序化表面生成的 UV 都以米為單位1 個 UV 單位 1 米。這是一條全局契約參與方包括wallpackages/viewer/src/systems/wall/wall-system.tsxExtrudeGeometryslabpackages/viewer/src/systems/slab/slab-system.tsxgeneratePositiveSlabGeometry、generatePoolGeometryceilingpackages/viewer/src/systems/ceiling/ceiling-system.tsxroofpackages/viewer/src/systems/roof/roof-system.tsxchimney / dormerpackages/nodes/src/chimney/geometry.tsGLB 物品插槽遵循同樣的約 1 UV 單位/米作者約定由插槽驗證器的 UV 存在性檢查和 item-authoring 中的 Blender 配方強制保證。這是作者要求不是渲染期修正。因此目錄材質catalog material的repeatmapProperties.repeatX/repeatY見 packages/core/src/material-library.ts就是一個按材質的全局尺度設置每米瓷磚數repeat: 1→ 1 塊/米repeat: 0.4→ 每 2.5 米一塊repeat: 1.5→ 1.5 塊/米。repeat是材質的屬性對使用它的每個表面都相同永遠不是按物品或按表面的。自定義 repeat 值是有意為之的材質尺度而非逐表面的 hack。在材質庫實現中MaterialCatalogItem攜帶preset: MaterialPresetPayload其mapProperties內含完整的color、roughness、metalness、repeatX/repeatY、rotation、wrapS/wrapT、normalScaleX/Y、emissiveColor/Intensity、displacementScale、transparent、opacity、side等參數packages/core/src/material-library.ts。查看器側的 materials.tsapplyMaterialMapProperties會把這些參數逐一映射到 three.js 材質roughness、metalness、displacementScale、bumpScale、aoMapIntensity、lightMapIntensity、normalScale、emissive、opacity、side等并同步wrapS/wrapT/repeat/rotation/flipY貼圖屬性。渲染時紋理的 repeat 由resolveTextureRepeat(repeat, scale)解析優先二維數組[x, y]其次標量x/y 相同再次{x, y}對象最后回退到scale或 1materials.ts。八、實現要點速查給源碼讀者主題必須進緩存鍵createSurfaceRoleMaterial的緩存鍵為role-preset-side-sceneThemeId任何新接入點漏傳sceneTheme都會導致切換主題后顏色不刷新。四個重建觸發器shading / textures / colorPreset / sceneTheme是GeometrySystem的故意 re-run 觸發器刪除它們會破壞外觀切換見 geometry-system.tsx 的 biome-ignore 注釋。glazing 用 FrontSideMRT 渲染管線對DoubleSideNodeMaterial 的校驗限制是玻璃強制FrontSide的根因需要雙面顯示時旋轉網格 180°。無全白模式無紋理表面永遠解析為主題化角色顏色這是 Mediterranean 藍屋頂等效果的機制來源。UV 契約是作者級約定1 UV 單位 1 米程序化表面與 GLB 物品均遵守repeat 每米瓷磚數是材質屬性而非表面屬性。外部插件材質交換只在偏好變化時進行絕不在useFrame銷毀順序為恢復作者材質 → 只銷毀插件變體 → 不動宿主緩存角色材質。相關文檔wiki/architecture/item-authoring.md —— GLB 物品與 UV 作者約定wiki/architecture/node-definitions.md ——NodeDefinition、geometry與幾何系統wiki/architecture/renderers.md —— 渲染器架構wiki/architecture/materials-and-themes.md —— 本文檔原始出處【免費下載鏈接】editorOpen-source 3D architectural editor with a local CLI, MCP tools, and practical workflows for humans and AI agents.項目地址: https://gitcode.com/GitHub_Trending/editor93/editor創作聲明:本文部分內容由AI輔助生成(AIGC),僅供參考