wall cutout
This commit is contained in:
@@ -15,7 +15,6 @@ export const WallRenderer = ({ node }: { node: WallNode }) => {
|
||||
<mesh ref={ref} castShadow receiveShadow visible={node.visible}>
|
||||
{/* WallSystem will replace this geometry in the next frame */}
|
||||
<boxGeometry args={[0, 0, 0]} />
|
||||
<meshStandardMaterial color="white" />
|
||||
<mesh name="collision-mesh" {...handlers} visible={false}>
|
||||
<boxGeometry args={[0, 0, 0]} />
|
||||
</mesh>
|
||||
|
||||
@@ -7,6 +7,7 @@ import * as THREE from 'three/webgpu'
|
||||
import { GuideSystem } from '../../systems/guide/guide-system'
|
||||
import { LevelSystem } from '../../systems/level/level-system'
|
||||
import { ScanSystem } from '../../systems/scan/scan-system'
|
||||
import { WallCutout } from '../../systems/wall/wall-cutout'
|
||||
import { SceneRenderer } from '../renderers/scene-renderer'
|
||||
import { Lights } from './lights'
|
||||
import PostProcessing from './post-processing'
|
||||
@@ -55,6 +56,7 @@ const Viewer: React.FC<ViewerProps> = ({ children, selectionManager = 'default'
|
||||
<LevelSystem />
|
||||
<GuideSystem />
|
||||
<ScanSystem />
|
||||
<WallCutout />
|
||||
{/* Core systems */}
|
||||
<CeilingSystem />
|
||||
<ItemSystem />
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import { sceneRegistry, useScene, type WallNode } from '@pascal-app/core'
|
||||
import { useFrame } from '@react-three/fiber'
|
||||
import { useRef } from 'react'
|
||||
import { float, mix, positionLocal } from 'three/tsl'
|
||||
|
||||
import { type Mesh, MeshStandardNodeMaterial, Vector3 } from 'three/webgpu'
|
||||
|
||||
const tmpVec = new Vector3()
|
||||
const u = new Vector3()
|
||||
const v = new Vector3()
|
||||
|
||||
const invsibleWallMaterial = new MeshStandardNodeMaterial({
|
||||
// opacity: 0.1,
|
||||
transparent: true,
|
||||
opacityNode: mix(float(1), float(0.1), positionLocal.y.add(0.1)),
|
||||
})
|
||||
const wallMaterial = new MeshStandardNodeMaterial({
|
||||
color: 'white',
|
||||
})
|
||||
|
||||
export const WallCutout = () => {
|
||||
const lastCameraPosition = useRef(new Vector3())
|
||||
const lastCameraTarget = useRef(new Vector3())
|
||||
|
||||
useFrame(({ camera }) => {
|
||||
const currentCameraPosition = camera.position
|
||||
camera.getWorldDirection(tmpVec)
|
||||
tmpVec.add(currentCameraPosition)
|
||||
|
||||
if (
|
||||
!currentCameraPosition.equals(lastCameraPosition.current) ||
|
||||
!tmpVec.equals(lastCameraTarget.current)
|
||||
) {
|
||||
// Camera has moved, update cutout logic here
|
||||
|
||||
// Update last known positions
|
||||
lastCameraPosition.current.copy(currentCameraPosition)
|
||||
lastCameraTarget.current.copy(tmpVec)
|
||||
camera.getWorldDirection(u)
|
||||
// TODO: Debounce
|
||||
const walls = sceneRegistry.byType.wall
|
||||
walls.forEach((wallId) => {
|
||||
const wallMesh = sceneRegistry.nodes.get(wallId)
|
||||
if (!wallMesh) return
|
||||
const wallNode = useScene.getState().nodes[wallId as WallNode['id']]
|
||||
if (!wallNode || wallNode.type !== 'wall') return
|
||||
wallMesh.getWorldDirection(v)
|
||||
let hideWall = wallNode.frontSide === 'interior' && wallNode.backSide === 'interior'
|
||||
if (v.dot(u) < 0) {
|
||||
// Front side
|
||||
if (wallNode.frontSide === 'exterior') {
|
||||
hideWall = true
|
||||
}
|
||||
} else {
|
||||
// Back side
|
||||
if (wallNode.backSide === 'exterior') {
|
||||
hideWall = true
|
||||
}
|
||||
}
|
||||
;(wallMesh as Mesh).material = hideWall ? invsibleWallMaterial : wallMaterial
|
||||
})
|
||||
}
|
||||
})
|
||||
return null
|
||||
}
|
||||
Reference in New Issue
Block a user