diff --git a/src/viewport-three/viewport-host.js b/src/viewport-three/viewport-host.js index 7c1db662..25b13e5d 100644 --- a/src/viewport-three/viewport-host.js +++ b/src/viewport-three/viewport-host.js @@ -1676,7 +1676,10 @@ export class ViewportHost { const volumeRenderPaths = resolveBoxVolumeRenderPaths(document.world.advancedRendering); for (const brush of Object.values(document.brushes)) { const geometry = buildBoxBrushDerivedMeshData(brush).geometry; - const materials = BOX_FACE_IDS.map((faceId) => this.createFaceMaterial(brush, faceId, document.materials[brush.faces[faceId].materialId ?? ""], this.getFaceHighlightState(brush.id, faceId), volumeRenderPaths)); + const contactPatches = brush.volume.mode === "water" + ? this.collectViewportWaterContactPatches(document, brush.id, brush.center, brush.rotationDegrees, brush.size) + : []; + const materials = BOX_FACE_IDS.map((faceId) => this.createFaceMaterial(brush, faceId, document.materials[brush.faces[faceId].materialId ?? ""], this.getFaceHighlightState(brush.id, faceId), volumeRenderPaths, contactPatches)); const mesh = new Mesh(geometry, materials); const brushSelected = isBrushSelected(selection, brush.id); mesh.userData.brushId = brush.id; @@ -2067,7 +2070,7 @@ export class ViewportHost { } return "none"; } - createFaceMaterial(brush, faceId, material, highlightState, volumeRenderPaths) { + createFaceMaterial(brush, faceId, material, highlightState, volumeRenderPaths, contactPatches) { const face = brush.faces[faceId]; const selectedFace = highlightState === "selected"; const hoveredFace = highlightState === "hovered"; @@ -2077,32 +2080,25 @@ export class ViewportHost { const baseOpacity = Math.max(0.08, Math.min(1, brush.volume.water.surfaceOpacity)); const opacityBoost = faceId === "posY" ? 0.16 : 0; const opacity = Math.min(1, baseOpacity + opacityBoost + (selectedFace ? 0.08 : hoveredFace ? 0.04 : 0)); - if (this.displayMode === "wireframe") { - return new MeshBasicMaterial({ - color: brush.volume.water.colorHex, - wireframe: true, - transparent: true, - opacity: Math.min(1, opacity + 0.2), - depthWrite: false - }); - } - if (this.displayMode === "authoring") { - return new MeshBasicMaterial({ - color: brush.volume.water.colorHex, - transparent: true, - opacity - }); - } - return new MeshStandardMaterial({ - color: brush.volume.water.colorHex, - emissive: brush.volume.water.colorHex, - emissiveIntensity: quality ? 0.09 + brush.volume.water.waveStrength * 0.1 : 0.03, - roughness: quality ? 0.1 : 0.2, - metalness: quality ? 0.04 : 0.01, - transparent: true, + const waterMaterial = createWaterMaterial({ + colorHex: brush.volume.water.colorHex, + surfaceOpacity: brush.volume.water.surfaceOpacity, + waveStrength: brush.volume.water.waveStrength, opacity, - envMapIntensity: quality ? 1.15 : 1 + quality, + wireframe: this.displayMode === "wireframe", + isTopFace: faceId === "posY", + time: this.volumeTime, + halfSize: { + x: brush.size.x * 0.5, + z: brush.size.z * 0.5 + }, + contactPatches }); + if (waterMaterial.animationUniform !== null) { + this.volumeAnimatedUniforms.push(waterMaterial.animationUniform); + } + return waterMaterial.material; } if (brush.volume.mode === "fog") { const quality = volumeRenderPaths.fog === "quality";