three-mesh-bvh
Version:
A BVH implementation to speed up raycasting against three.js meshes.
180 lines (118 loc) • 4.62 kB
JavaScript
import { UINT32_PER_NODE, BYTES_PER_NODE } from '../Constants.js';
import { IS_LEAF, OFFSET, COUNT, LEFT_NODE, RIGHT_NODE } from '../utils/nodeBufferUtils.js';
/****************************************************/
/* This file is generated from "refit.template.js". */
/****************************************************/
function refit_indirect( bvh, nodeIndices = null ) {
if ( nodeIndices && Array.isArray( nodeIndices ) ) {
nodeIndices = new Set( nodeIndices );
}
const geometry = bvh.geometry;
const indexArr = geometry.index ? geometry.index.array : null;
const posAttr = geometry.attributes.position;
let buffer, uint32Array, uint16Array, float32Array;
let byteOffset = 0;
const roots = bvh._roots;
for ( let i = 0, l = roots.length; i < l; i ++ ) {
buffer = roots[ i ];
uint32Array = new Uint32Array( buffer );
uint16Array = new Uint16Array( buffer );
float32Array = new Float32Array( buffer );
_traverse( 0, byteOffset );
byteOffset += buffer.byteLength;
}
function _traverse( nodeIndex32, byteOffset, force = false ) {
const nodeIndex16 = nodeIndex32 * 2;
if ( IS_LEAF( nodeIndex16, uint16Array ) ) {
const offset = OFFSET( nodeIndex32, uint32Array );
const count = COUNT( nodeIndex16, uint16Array );
let minx = Infinity;
let miny = Infinity;
let minz = Infinity;
let maxx = - Infinity;
let maxy = - Infinity;
let maxz = - Infinity;
for ( let i = offset, l = offset + count; i < l; i ++ ) {
const t = 3 * bvh.resolveTriangleIndex( i );
for ( let j = 0; j < 3; j ++ ) {
let index = t + j;
index = indexArr ? indexArr[ index ] : index;
const x = posAttr.getX( index );
const y = posAttr.getY( index );
const z = posAttr.getZ( index );
if ( x < minx ) minx = x;
if ( x > maxx ) maxx = x;
if ( y < miny ) miny = y;
if ( y > maxy ) maxy = y;
if ( z < minz ) minz = z;
if ( z > maxz ) maxz = z;
}
}
if (
float32Array[ nodeIndex32 + 0 ] !== minx ||
float32Array[ nodeIndex32 + 1 ] !== miny ||
float32Array[ nodeIndex32 + 2 ] !== minz ||
float32Array[ nodeIndex32 + 3 ] !== maxx ||
float32Array[ nodeIndex32 + 4 ] !== maxy ||
float32Array[ nodeIndex32 + 5 ] !== maxz
) {
float32Array[ nodeIndex32 + 0 ] = minx;
float32Array[ nodeIndex32 + 1 ] = miny;
float32Array[ nodeIndex32 + 2 ] = minz;
float32Array[ nodeIndex32 + 3 ] = maxx;
float32Array[ nodeIndex32 + 4 ] = maxy;
float32Array[ nodeIndex32 + 5 ] = maxz;
return true;
} else {
return false;
}
} else {
const left = LEFT_NODE( nodeIndex32 );
const right = RIGHT_NODE( nodeIndex32, uint32Array );
// the identifying node indices provided by the shapecast function include offsets of all
// root buffers to guarantee they're unique between roots so offset left and right indices here.
let forceChildren = force;
let includesLeft = false;
let includesRight = false;
if ( nodeIndices ) {
// if we see that neither the left or right child are included in the set that need to be updated
// then we assume that all children need to be updated.
if ( ! forceChildren ) {
const leftNodeId = left / UINT32_PER_NODE + byteOffset / BYTES_PER_NODE;
const rightNodeId = right / UINT32_PER_NODE + byteOffset / BYTES_PER_NODE;
includesLeft = nodeIndices.has( leftNodeId );
includesRight = nodeIndices.has( rightNodeId );
forceChildren = ! includesLeft && ! includesRight;
}
} else {
includesLeft = true;
includesRight = true;
}
const traverseLeft = forceChildren || includesLeft;
const traverseRight = forceChildren || includesRight;
let leftChange = false;
if ( traverseLeft ) {
leftChange = _traverse( left, byteOffset, forceChildren );
}
let rightChange = false;
if ( traverseRight ) {
rightChange = _traverse( right, byteOffset, forceChildren );
}
const didChange = leftChange || rightChange;
if ( didChange ) {
for ( let i = 0; i < 3; i ++ ) {
const left_i = left + i;
const right_i = right + i;
const minLeftValue = float32Array[ left_i ];
const maxLeftValue = float32Array[ left_i + 3 ];
const minRightValue = float32Array[ right_i ];
const maxRightValue = float32Array[ right_i + 3 ];
float32Array[ nodeIndex32 + i ] = minLeftValue < minRightValue ? minLeftValue : minRightValue;
float32Array[ nodeIndex32 + i + 3 ] = maxLeftValue > maxRightValue ? maxLeftValue : maxRightValue;
}
}
return didChange;
}
}
}
export { refit_indirect };