Pascal Editor 自定义渲染对象该放哪个图层?Three.js 六层划分与后处理隔离原理
Pascal Editor 自定义渲染对象该放哪个图层Three.js 六层划分与后处理隔离原理【免费下载链接】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给 Pascal Editor 添加自定义渲染对象时——无论是packages/viewer里的节点 renderer还是通过插件体系挂载的模型与放置预览——一个绕不开的问题是这个 mesh 该挂到 Three.js 的哪个 layer 上。选错的后果不是报错而是静默的渲染异常编辑器辅助对象被屏幕空间描边ink描线、被 SSGI/AO 压暗本该被墙遮挡的地面网格穿透几何体或者本不该出现在缩略图导出里的 gizmo 跟着一起被烘焙。本文基于仓库中的 layers.md、post-processing.tsx 与 layers.ts 说明这套六层划分如何工作、每类自定义对象该放哪一层以及如何验证你的对象落对了层。适用环境仓库内packages/viewer、packages/editor与apps/editor渲染管线为 WebGPU无 WebGPU 时回退到 WebGL2 直接渲染见后文限制一节。先认清这六层常量表与取值所有图层常量定义在 layers.ts取值与用途如下与 layers.md 的 Layer Map 一致常量值用途SCENE_LAYER0默认 Three.js 层所有常规场景几何OVERLAY_LAYER1编辑器覆盖物gizmo、移动手柄、工具预览、光标 mesh、吸附辅助线。在独立 pass 中叠加合成到最上层ZONE_LAYER2Zone 地面填充与墙体边框——走独立的后处理 pass 合成GRID_LAYER3编辑器地面网格——在场景 pass 内渲染以获得正确的深度遮挡SHADOW_ONLY_LAYER4只投射阴影的几何剖切/solo 视图中隐藏的屋顶、楼层。任何 color pass 与相机都不启用它只有太阳光源的阴影相机会启用BATCHED_LAYER5已被合并批次collective batch绘制的源几何。没有渲染相机启用它表面 raycaster 通过setSurfaceRaycastLayers选择性加入apps/editor暴露的EDITOR_LAYER是OVERLAY_LAYER的别名再导出EDITOR_LAYER OVERLAY_LAYER让编辑器侧代码与 viewer 的 pass 编号解耦但落在同一层上。定义见 constants.tsimport { OVERLAY_LAYER } from pascal-app/viewer export const EDITOR_LAYER OVERLAY_LAYER决策规则你的对象属于哪一类按对象在渲染管线里应被当作什么而不是按它“看起来像什么”来选层常规场景几何模型、GLB、自定义节点 renderer→ 留在SCENE_LAYER即不显式设置 layer。plugin-authoring.md 明确写道“Normal plugin geometry stays onSCENE_LAYER, so the light rig and depth/normal pipeline include it automatically.” 光源、阴影与深度/法线 MRT 会自动包含它不需要你做任何层操作。仅编辑器可见的辅助物放置预览、gizmo、手柄、光标、吸附线→EDITOR_LAYER即OVERLAY_LAYER。这让它被合成到最上层不进入 ink 与 SSGI 的深度/法线 buffer同时缩略图相机会把它排除掉。半透明、depthTest: false的 Zone 类覆盖填充 →ZONE_LAYER。需要被墙和物体深度遮挡的平面地面网格这类→GRID_LAYER。注意不是 overlay 层。overlay pass 合成在最上层且不做场景深度测试网格若放在那会穿透墙体。希望隐藏但保留投影的几何 →SHADOW_ONLY_LAYER。通过 shadow-only.ts 的applyShadowOnly/clearShadowOnly按对象应用layer 不会沿父子级联所以是逐对象操作。剖切/solo 视图里用它隐藏屋顶后室内仍能保持窗形光斑。已被批次绘制的源几何 →BATCHED_LAYER。这一层由 collective renderer 与共享的场景可见性管理方scene-visibility owner负责搬移与恢复不属于你手动摆放的范围需要查询其表面时用setSurfaceRaycastLayers。写自定义 renderer 时的标准挂载方式见 renderers.mdrenderer 负责一个节点类型的几何与材质通过useRegistry(node.id, type, ref)注册 mesh。若插件里需要编辑器层常量按 plugin-authoring.md 从pascal-app/editor导入// 插件侧导入viewer 侧原始常量来自 pascal-app/viewer import { useDragAction, EDITOR_LAYER } from pascal-app/editorviewer 内部代码则直接用import { SCENE_LAYER, OVERLAY_LAYER, ZONE_LAYER, GRID_LAYER } from pascal-app/viewer辅助/覆盖 mesh 设置层的写法摘自 layers.md 规则一节// overlay/helper mesh 必须显式设置 layers才会进入 overlay pass mesh ref{ref} layers{EDITOR_LAYER} ... /mesh后处理隔离原理为什么层号决定了对象是否被描边和 AO核心在 post-processing.tsx 构建的 WebGPURenderPipeline。管线把一次帧拆成三个带 layer 掩码的 pass再按固定顺序合成1. 场景 passscenePass只允许场景层 网格层const sceneOnlyLayers useMemo(() { const l new Layers() l.set(SCENE_LAYER) l.enable(GRID_LAYER) return l }, [])sceneOnlyLayers只set(SCENE_LAYER)再enable(GRID_LAYER)因此 gizmo 和工具预览不会进入深度/法线 MRT也就不会被屏幕空间 ink 描线或被 SSGI 当作几何体压暗。网格留在场景 pass 内是因为它需要一个平面的深度遮挡——场景几何的深度 buffer 会正确遮住它而它自己不写深度、又是平面所以 ink 也捕捉不到它。2. Zone pass 只渲染 Zone 层、显式关掉场景层const zoneLayers useMemo(() { const l new Layers() l.enable(ZONE_LAYER) l.disable(SCENE_LAYER) return l }, []) zonePass.setLayers(zoneLayers)Zone 用的是半透明、depthTest: false材质。若让它进入场景 pass 的深度/法线 bufferSSGI 会在透明表面上算出错误的 AO独立zonePass渲染后手动把结果叠加进最终合成既保证了“浮在场景之上”又不污染 GI 输入。3. Overlay pass 最后合成const overlayPass new LayerPassNode(layerIndex, camera, OVERLAY_LAYER, scenePass) overlayPass.setLayers(overlayLayers) // 仅 OVERLAY_LAYERoverlay pass 在 ink 与选中轮廓之后合成且带深度门控写深度的 overlay 仍会被前方几何遮挡。最终合成处overlay 用自己的 alpha 直接盖在最上层// Editor overlays painted on top by their own alpha — they never get inked, // AOd, or outlined, and always read crisp regardless of scene depth. const withOverlay mix(composited, overlayColor.rgb, overlayColor.a)合成顺序是场景 color zone tint → SSGIAO/GI仅当shading rendered→ 屏幕空间 ink 描边edges ! off→ 选中/悬停轮廓 → 背景混合 → overlay。你的对象被哪些 pass 处理完全由它的 layer 掩码决定——这就是“隔离”的全部含义不是某个开关而是三个 pass 各持一份Layers掩码。动手验证放错层的现象与检查手段仓库没有“查询某 mesh 当前层”的运行时命令验证靠的是可观察的渲染行为。启动开发环境bun run dev根 package.json 中dev脚本为dotenv -e ./.env -e ./.env.defaults -- turbo run dev --env-modeloosepackageManager声明bun1.3.14engines要求node 20.9.0。按层检查对应现象均出自 layers.md 与源码注释overlay 层1编辑器相机启用OVERLAY_LAYER而缩略图生成器thumbnail generator禁用它所以导出是干净的。验证点gizmo/预览在编辑视口可见、锐利、无描边无 AO缩略图导出图中不出现。grid 层3网格应被墙体/物体遮挡同样被缩略图相机禁用。若网格穿透墙体说明它被误放到了 overlay 层。zone 层2填充应浮在场景之上且不产生 AO 异常。shadow-only 层4对象在颜色 pass 中不可见但阴影里仍存在剖切视图中室内有窗形光斑。post-processing.tsx 顶部还记录了一组诊断开关在 URL 上加?disableao,denoise,outline,postFx可取任意子集后重新加载可跳过对应 pass用于 A/B 判断“到底是哪个 pass 让我的对象画错了”。postFx会绕过整个RenderPipeline直接renderer.render(scene, camera)draw则完全跳过渲染提交只保留无头烘焙场景图构建的路径。相关单测可作行为参照layer-pass.test.ts、isolation.test.ts、scene-visibility.test.ts。限制与仓库规则不要硬编码层号一律使用命名常量layers.md 的第一条规则。所有层常量归属pascal-app/viewerEDITOR_LAYER只是OVERLAY_LAYER的别名再导出两者必须保持一致。不要新增图层而不更新 layers.md 和后处理管线——管线里的 pass 掩码是硬编码的新增层若没有被任何 pass/相机/阴影相机纳入就是纯死层。SHADOW_ONLY_LAYER与BATCHED_LAYER没有任何 color pass 或渲染相机启用它们只能靠阴影相机lights.tsx与setSurfaceRaycastLayers这类显式 opt-in 生效。指针拾取侧有一个隐藏耦合R3F 的共享 raycaster 默认掩码只有SCENE_LAYER进入批次的墙会瞬间失去 hover/点击响应pointer-raycast-layers.tsx 通过启用BATCHED_LAYER修复它。你若做自定义表面查询对应工具是 layers.ts 中的setSurfaceRaycastLayers它会set(SCENE_LAYER)并enable(BATCHED_LAYER)。后处理管线SSGI、denoise、RenderPipeline是 WebGPU-only API。浏览器回退到 WebGL2 时管线不会构建useFrame走renderer.render(scene, camera)直接渲染路径——此时上述 pass 隔离整体不生效层掩码只对相机拾取与可见性逻辑起作用。【免费下载链接】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),仅供参考