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}>
|
<mesh ref={ref} castShadow receiveShadow visible={node.visible}>
|
||||||
{/* WallSystem will replace this geometry in the next frame */}
|
{/* WallSystem will replace this geometry in the next frame */}
|
||||||
<boxGeometry args={[0, 0, 0]} />
|
<boxGeometry args={[0, 0, 0]} />
|
||||||
<meshStandardMaterial color="white" />
|
|
||||||
<mesh name="collision-mesh" {...handlers} visible={false}>
|
<mesh name="collision-mesh" {...handlers} visible={false}>
|
||||||
<boxGeometry args={[0, 0, 0]} />
|
<boxGeometry args={[0, 0, 0]} />
|
||||||
</mesh>
|
</mesh>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import * as THREE from 'three/webgpu'
|
|||||||
import { GuideSystem } from '../../systems/guide/guide-system'
|
import { GuideSystem } from '../../systems/guide/guide-system'
|
||||||
import { LevelSystem } from '../../systems/level/level-system'
|
import { LevelSystem } from '../../systems/level/level-system'
|
||||||
import { ScanSystem } from '../../systems/scan/scan-system'
|
import { ScanSystem } from '../../systems/scan/scan-system'
|
||||||
|
import { WallCutout } from '../../systems/wall/wall-cutout'
|
||||||
import { SceneRenderer } from '../renderers/scene-renderer'
|
import { SceneRenderer } from '../renderers/scene-renderer'
|
||||||
import { Lights } from './lights'
|
import { Lights } from './lights'
|
||||||
import PostProcessing from './post-processing'
|
import PostProcessing from './post-processing'
|
||||||
@@ -55,6 +56,7 @@ const Viewer: React.FC<ViewerProps> = ({ children, selectionManager = 'default'
|
|||||||
<LevelSystem />
|
<LevelSystem />
|
||||||
<GuideSystem />
|
<GuideSystem />
|
||||||
<ScanSystem />
|
<ScanSystem />
|
||||||
|
<WallCutout />
|
||||||
{/* Core systems */}
|
{/* Core systems */}
|
||||||
<CeilingSystem />
|
<CeilingSystem />
|
||||||
<ItemSystem />
|
<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