UNPKG

three-mesh-bvh

Version:

A BVH implementation to speed up raycasting against three.js meshes.

120 lines (89 loc) 2.89 kB
import { wgslFn, wgsl } from 'three/tsl'; export const constants = wgsl( /* wgsl */` const BVH_STACK_DEPTH = 60u; const INFINITY = 1e20; const TRI_INTERSECT_EPSILON = 1e-5; ` ); export const rayStruct = wgsl( /* wgsl */` struct Ray { origin: vec3f, direction: vec3f, }; ` ); export const bvhNodeBoundsStruct = wgsl( /* wgsl */` struct BVHBoundingBox { min: array<f32, 3>, max: array<f32, 3>, } ` ); export const bvhNodeStruct = wgsl( /* wgsl */` struct BVHNode { bounds: BVHBoundingBox, rightChildOrTriangleOffset: u32, splitAxisOrTriangleCount: u32, }; `, [ bvhNodeBoundsStruct ] ); export const intersectionResultStruct = wgsl( /* wgsl */` struct IntersectionResult { didHit: bool, indices: vec4u, normal: vec3f, barycoord: vec3f, side: f32, dist: f32, }; ` ); export const getVertexAttribute = wgslFn( /* wgsl */` fn getVertexAttribute( barycoord: vec3f, indices: vec3u, attributeBuffer: ptr<storage, array<vec3f>, read> ) -> vec3f { let n0 = attributeBuffer[ indices.x ]; let n1 = attributeBuffer[ indices.y ]; let n2 = attributeBuffer[ indices.z ]; return barycoord.x * n0 + barycoord.y * n1 + barycoord.z * n2; } ` ); export const ndcToCameraRay = wgslFn( /* wgsl*/` fn ndcToCameraRay( ndc: vec2f, inverseModelViewProjection: mat4x4f ) -> Ray { // Calculate the ray by picking the points at the near and far plane and deriving the ray // direction from the two points. This approach works for both orthographic and perspective // camera projection matrices. // The returned ray direction is not normalized and extends to the camera far plane. var homogeneous = vec4f(); var ray = Ray(); homogeneous = inverseModelViewProjection * vec4f( ndc, 0.0, 1.0 ); ray.origin = homogeneous.xyz / homogeneous.w; homogeneous = inverseModelViewProjection * vec4f( ndc, 1.0, 1.0 ); ray.direction = ( homogeneous.xyz / homogeneous.w ) - ray.origin; return ray; } ` ); export const intersectsBounds = wgslFn( /* wgsl */` fn intersectsBounds( ray: Ray, bounds: BVHBoundingBox, dist: ptr<function, f32> ) -> bool { let boundsMin = vec3( bounds.min[0], bounds.min[1], bounds.min[2] ); let boundsMax = vec3( bounds.max[0], bounds.max[1], bounds.max[2] ); let invDir = 1.0 / ray.direction; let tMinPlane = ( boundsMin - ray.origin ) * invDir; let tMaxPlane = ( boundsMax - ray.origin ) * invDir; let tMinHit = vec3f( min( tMinPlane.x, tMaxPlane.x ), min( tMinPlane.y, tMaxPlane.y ), min( tMinPlane.z, tMaxPlane.z ) ); let tMaxHit = vec3f( max( tMinPlane.x, tMaxPlane.x ), max( tMinPlane.y, tMaxPlane.y ), max( tMinPlane.z, tMaxPlane.z ) ); let t0 = max( max( tMinHit.x, tMinHit.y ), tMinHit.z ); let t1 = min( min( tMaxHit.x, tMaxHit.y ), tMaxHit.z ); ( *dist ) = max( t0, 0.0 ); return t1 >= ( *dist ); } `, [ rayStruct, bvhNodeBoundsStruct ] );