UNPKG

three-mesh-bvh

Version:

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

102 lines (66 loc) 3.26 kB
import { IS_LEAF, OFFSET, COUNT, SPLIT_AXIS, LEFT_NODE, RIGHT_NODE } from '../utils/nodeBufferUtils.js'; import { BufferStack } from '../utils/BufferStack.js'; import { intersectRay } from '../utils/intersectUtils.js'; import '../utils/iterationUtils.generated.js'; import { intersectClosestTri_indirect } from '../utils/iterationUtils_indirect.generated.js'; /***********************************************************/ /* This file is generated from "raycastFirst.template.js". */ /***********************************************************/ const _xyzFields = [ 'x', 'y', 'z' ]; function raycastFirst_indirect( bvh, root, materialOrSide, ray, near, far ) { BufferStack.setBuffer( bvh._roots[ root ] ); const result = _raycastFirst( 0, bvh, materialOrSide, ray, near, far ); BufferStack.clearBuffer(); return result; } function _raycastFirst( nodeIndex32, bvh, materialOrSide, ray, near, far ) { const { float32Array, uint16Array, uint32Array } = BufferStack; let nodeIndex16 = nodeIndex32 * 2; const isLeaf = IS_LEAF( nodeIndex16, uint16Array ); if ( isLeaf ) { const offset = OFFSET( nodeIndex32, uint32Array ); const count = COUNT( nodeIndex16, uint16Array ); return intersectClosestTri_indirect( bvh, materialOrSide, ray, offset, count, near, far ); } else { // consider the position of the split plane with respect to the oncoming ray; whichever direction // the ray is coming from, look for an intersection among that side of the tree first const splitAxis = SPLIT_AXIS( nodeIndex32, uint32Array ); const xyzAxis = _xyzFields[ splitAxis ]; const rayDir = ray.direction[ xyzAxis ]; const leftToRight = rayDir >= 0; // c1 is the child to check first let c1, c2; if ( leftToRight ) { c1 = LEFT_NODE( nodeIndex32 ); c2 = RIGHT_NODE( nodeIndex32, uint32Array ); } else { c1 = RIGHT_NODE( nodeIndex32, uint32Array ); c2 = LEFT_NODE( nodeIndex32 ); } const c1Intersection = intersectRay( c1, float32Array, ray, near, far ); const c1Result = c1Intersection ? _raycastFirst( c1, bvh, materialOrSide, ray, near, far ) : null; // if we got an intersection in the first node and it's closer than the second node's bounding // box, we don't need to consider the second node because it couldn't possibly be a better result if ( c1Result ) { // check if the point is within the second bounds // "point" is in the local frame of the bvh const point = c1Result.point[ xyzAxis ]; const isOutside = leftToRight ? point <= float32Array[ c2 + splitAxis ] : // min bounding data point >= float32Array[ c2 + splitAxis + 3 ]; // max bounding data if ( isOutside ) { return c1Result; } } // either there was no intersection in the first node, or there could still be a closer // intersection in the second, so check the second node and then take the better of the two const c2Intersection = intersectRay( c2, float32Array, ray, near, far ); const c2Result = c2Intersection ? _raycastFirst( c2, bvh, materialOrSide, ray, near, far ) : null; if ( c1Result && c2Result ) { return c1Result.distance <= c2Result.distance ? c1Result : c2Result; } else { return c1Result || c2Result || null; } } } export { raycastFirst_indirect };