
3D 객체간의 상호작용
3D 공간에서 Ray를 발사하여, 이 Ray가 어떤 3D object와 교차하는지 검사하는 컴퓨터 그래픽스 기술
R3F에서는 Canvas 컴포넌트 내부에서 렌더링되는 모든 Three.js mesh object는 기본적으로 Raycasting 기능을 자동으로 가진다.
https://r3f.docs.pmnd.rs/api/events
편리하지만, 모든 Raycast 가능한 객체를 대상으로 Ray intersection 검사를 진행한다.
위의 문제 상황을 해결하기 위해서 BVH를 사용

Bounding Volume Hierarchy
어떻게 하면 3D scene 상에서 Intersection 검사를 최소화할 수 있을까
object 하나하나 검사한다면 계산량이 늘어난다.
단순한 형태로 해당 object들을 감싸고 이를 검사하면 계산이 줄어들 것이다.
단순한 형태를 AABB로 구성해보자
Axis Aligned Bounding Box
Intersection 검사 과정에서
Bounding Box에 교차되지 않으면 절대로 실제 object와 교차되지 않으므로 검사를 진행하지 않는다.
이러한 Bounding Volume을 계층적 Tree 구조로 관리하는 것이 BVH이다.
여러개의 작은 Bounding Volume이 모여서 더 큰 Bounding volume을 형성
다시 더 큰 Bounding volume이 모여서 보다 더 큰 Bounding volume을 형성하여 최종적으로 하나의 거대한 Bounding volume(root node)을 형성
이렇게 트리구조로 구정하면 object와 교차되는 검사를 이분 탐색으로 진행할 수 있어서
탐색 효율성이 올라간다.
두가지 방법이 있다.
https://drei.docs.pmnd.rs/performances/bvh
npm install @react-three/bvh three-mesh-bvh
# 또는
yarn add @react-three/bvh three-mesh-bvh
<Canvas>
<Bvh firstHitOnly>
<Scene />
</Bvh>
</Canvas>
firstHitOnly
- ture가 default value
- Ray의 가장 먼저 만나는 객체 하나만 찾고 Raycasting 종료
- 가장 효율적
https://github.com/gkjohnson/three-mesh-bvh
npm install three-mesh-bvh
# 또는
yarn add three-mesh-bvh
import {
acceleratedRaycast, // BVH 가속 Raycast 함수
computeBoundsTree, // BVH 트리를 계산하는 함수
disposeBoundsTree // BVH 트리를 해제하는 함수
} from 'three-mesh-bvh';
useEffect(() => {
// 모델의 모든 하위 메시를 순회하며 BVH 적용
gltf.scene.traverse((child) => {
if (child.isMesh) {
// 3. 메시의 지오메트리에 BVH 트리 계산
child.geometry.computeBoundsTree = computeBoundsTree; // BVH 빌드 함수 할당
child.geometry.disposeBoundsTree = disposeBoundsTree; // BVH 해제 함수 할당 (클린업 시 사용)
child.geometry.computeBoundsTree(); // 실제로 BVH 트리 빌드
// (선택 사항) 만약 특정 메시에서 원래 Raycast 기능을 사용하고 싶다면,
// child.raycast = originalRaycastFunction; 처럼 오버라이드 가능
}
});
// 컴포넌트 언마운트 시 BVH 트리 메모리 해제 (선택 사항이지만 권장)
return () => {
gltf.scene.traverse((child) => {
if (child.isMesh && child.geometry.boundsTree) {
child.geometry.disposeBoundsTree();
}
});
};
}, [gltf.scene]); // gltf.scene이 변경될 때만 다시 실행
THREE.Mesh.prototype.raycast = acceleratedRaycast;
Ray 연산이 크게 줄어들어서 성능적으로 이득
복잡한 model의 경우 BVH 빌드 시간이 필요
object의 위치, 회전, 크기등이 실시간으로 변하는 경우, 변하면 BVH 트리를 다시 빌드해야하므로, 이 경우에는 오히려 성능 저하
특정 mesh에만 BVH를 적용하고 싶을 경우에 three-mesh-bvh가 유리
custom Raycaster 로직을 사용하는 경우 three-mesh-bvh가 유리