diff --git a/packages/nodes/src/slab/geometry.ts b/packages/nodes/src/slab/geometry.ts index 6b3c241db..b9ec1853f 100644 --- a/packages/nodes/src/slab/geometry.ts +++ b/packages/nodes/src/slab/geometry.ts @@ -122,7 +122,14 @@ function splitSlabFacesByFacing(geometry: BufferGeometry): { const build = (data: { pos: number[]; uv: number[] }) => { const geo = new BufferGeometry() geo.setAttribute('position', new Float32BufferAttribute(data.pos, 3)) - if (data.uv.length > 0) geo.setAttribute('uv', new Float32BufferAttribute(data.uv, 2)) + if (data.uv.length > 0) { + geo.setAttribute('uv', new Float32BufferAttribute(data.uv, 2)) + // Slot finishes with an aoMap (e.g. the default woodplank) sample uv2; + // a referenced-but-missing attribute crashes the WebGPU renderer mid + // scene pass, which leaks the MRT render target and poisons every + // pipeline built afterwards. + geo.setAttribute('uv2', new Float32BufferAttribute(data.uv.slice(), 2)) + } geo.computeVertexNormals() return geo } diff --git a/packages/viewer/src/components/viewer/post-processing.tsx b/packages/viewer/src/components/viewer/post-processing.tsx index 801b11742..44c05e3ca 100644 --- a/packages/viewer/src/components/viewer/post-processing.tsx +++ b/packages/viewer/src/components/viewer/post-processing.tsx @@ -598,6 +598,12 @@ const PostProcessingPasses = ({ } } catch (error) { hasPipelineErrorRef.current = true + // A mid-pass exception (e.g. thrown inside a PassNode's scene render) + // leaves the pass's MRT render target bound on the renderer. Every + // pipeline compiled afterwards then validates against that 3-attachment + // framebuffer and fails, poisoning the rebuilt pipeline and the fallback + // path alike. Restore the default target before retrying. + ;(renderer as any).setRenderTarget?.(null) console.error('[viewer/post-processing] Render pass failed.', { retryCount: retryCountRef.current, rendererCtor: (renderer as any).constructor?.name, diff --git a/packages/viewer/src/systems/roof/roof-system.tsx b/packages/viewer/src/systems/roof/roof-system.tsx index 3a65665a2..45c44afeb 100644 --- a/packages/viewer/src/systems/roof/roof-system.tsx +++ b/packages/viewer/src/systems/roof/roof-system.tsx @@ -497,8 +497,10 @@ function updateMergedRoofGeometry( if (children.length === 0) { mergedMesh.geometry.dispose() - // Keep a valid position attribute so Drei's BVH can index safely. - mergedMesh.geometry = new THREE.BoxGeometry(0, 0, 0) + // Keep a valid position attribute so Drei's BVH can index safely. Must + // also carry uv2 — the roof finish's aoMap samples it, and a missing + // attribute crashes the WebGPU renderer (BoxGeometry has no uv2). + mergedMesh.geometry = ensureRenderableGeometryAttributes(new THREE.BufferGeometry()) return }