UNPKG

three-mesh-bvh

Version:

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

180 lines (132 loc) 4.47 kB
import { FLOAT32_EPSILON } from '../Constants.js'; import { getTriCount } from './geometryUtils.js'; // computes the union of the bounds of all of the given triangles and puts the resulting box in "target". // A bounding box is computed for the centroids of the triangles, as well, and placed in "centroidTarget". // These are computed together to avoid redundant accesses to bounds array. export function getBounds( triangleBounds, offset, count, target, centroidTarget ) { let minx = Infinity; let miny = Infinity; let minz = Infinity; let maxx = - Infinity; let maxy = - Infinity; let maxz = - Infinity; let cminx = Infinity; let cminy = Infinity; let cminz = Infinity; let cmaxx = - Infinity; let cmaxy = - Infinity; let cmaxz = - Infinity; for ( let i = offset * 6, end = ( offset + count ) * 6; i < end; i += 6 ) { const cx = triangleBounds[ i + 0 ]; const hx = triangleBounds[ i + 1 ]; const lx = cx - hx; const rx = cx + hx; if ( lx < minx ) minx = lx; if ( rx > maxx ) maxx = rx; if ( cx < cminx ) cminx = cx; if ( cx > cmaxx ) cmaxx = cx; const cy = triangleBounds[ i + 2 ]; const hy = triangleBounds[ i + 3 ]; const ly = cy - hy; const ry = cy + hy; if ( ly < miny ) miny = ly; if ( ry > maxy ) maxy = ry; if ( cy < cminy ) cminy = cy; if ( cy > cmaxy ) cmaxy = cy; const cz = triangleBounds[ i + 4 ]; const hz = triangleBounds[ i + 5 ]; const lz = cz - hz; const rz = cz + hz; if ( lz < minz ) minz = lz; if ( rz > maxz ) maxz = rz; if ( cz < cminz ) cminz = cz; if ( cz > cmaxz ) cmaxz = cz; } target[ 0 ] = minx; target[ 1 ] = miny; target[ 2 ] = minz; target[ 3 ] = maxx; target[ 4 ] = maxy; target[ 5 ] = maxz; centroidTarget[ 0 ] = cminx; centroidTarget[ 1 ] = cminy; centroidTarget[ 2 ] = cminz; centroidTarget[ 3 ] = cmaxx; centroidTarget[ 4 ] = cmaxy; centroidTarget[ 5 ] = cmaxz; } // precomputes the bounding box for each triangle; required for quickly calculating tree splits. // result is an array of size tris.length * 6 where triangle i maps to a // [x_center, x_delta, y_center, y_delta, z_center, z_delta] tuple starting at index i * 6, // representing the center and half-extent in each dimension of triangle i export function computeTriangleBounds( geo, target = null, offset = null, count = null ) { const posAttr = geo.attributes.position; const index = geo.index ? geo.index.array : null; const triCount = getTriCount( geo ); const normalized = posAttr.normalized; let triangleBounds; if ( target === null ) { triangleBounds = new Float32Array( triCount * 6 ); offset = 0; count = triCount; } else { triangleBounds = target; offset = offset || 0; count = count || triCount; } // used for non-normalized positions const posArr = posAttr.array; // support for an interleaved position buffer const bufferOffset = posAttr.offset || 0; let stride = 3; if ( posAttr.isInterleavedBufferAttribute ) { stride = posAttr.data.stride; } // used for normalized positions const getters = [ 'getX', 'getY', 'getZ' ]; for ( let tri = offset; tri < offset + count; tri ++ ) { const tri3 = tri * 3; const tri6 = tri * 6; let ai = tri3 + 0; let bi = tri3 + 1; let ci = tri3 + 2; if ( index ) { ai = index[ ai ]; bi = index[ bi ]; ci = index[ ci ]; } // we add the stride and offset here since we access the array directly // below for the sake of performance if ( ! normalized ) { ai = ai * stride + bufferOffset; bi = bi * stride + bufferOffset; ci = ci * stride + bufferOffset; } for ( let el = 0; el < 3; el ++ ) { let a, b, c; if ( normalized ) { a = posAttr[ getters[ el ] ]( ai ); b = posAttr[ getters[ el ] ]( bi ); c = posAttr[ getters[ el ] ]( ci ); } else { a = posArr[ ai + el ]; b = posArr[ bi + el ]; c = posArr[ ci + el ]; } let min = a; if ( b < min ) min = b; if ( c < min ) min = c; let max = a; if ( b > max ) max = b; if ( c > max ) max = c; // Increase the bounds size by float32 epsilon to avoid precision errors when // converting to 32 bit float. Scale the epsilon by the size of the numbers being // worked with. const halfExtents = ( max - min ) / 2; const el2 = el * 2; triangleBounds[ tri6 + el2 + 0 ] = min + halfExtents; triangleBounds[ tri6 + el2 + 1 ] = halfExtents + ( Math.abs( min ) + halfExtents ) * FLOAT32_EPSILON; } } return triangleBounds; }