Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 14 additions & 24 deletions src/core/cast/bvhcast.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import { Box3, Matrix4 } from 'three';
import { BufferStack } from '../utils/BufferStack.js';
import { BOUNDING_DATA_INDEX, COUNT, IS_LEAF, LEFT_NODE, OFFSET, RIGHT_NODE } from '../utils/nodeBufferUtils.js';
import { arrayToBox } from '../../utils/ArrayBoxUtilities.js';
import { arrayToBox, arrayIntersectsBox } from '../../utils/ArrayBoxUtilities.js';
import { PrimitivePool } from '../../utils/PrimitivePool.js';

const _bufferStack1 = new BufferStack.constructor();
const _bufferStack2 = new BufferStack.constructor();
const _boxPool = new PrimitivePool( () => new Box3() );
const _leftBox1 = new Box3();
const _rightBox1 = new Box3();

const _leftBox2 = new Box3();
const _rightBox2 = new Box3();

let _active = false;

Expand Down Expand Up @@ -170,12 +165,10 @@ function _traverse(
// get the child bounds to check before traversal
const cl1 = LEFT_NODE( node1Index32 );
const cr1 = RIGHT_NODE( node1Index32, uint32Array1 );
arrayToBox( BOUNDING_DATA_INDEX( cl1 ), float32Array1, _leftBox1 );
arrayToBox( BOUNDING_DATA_INDEX( cr1 ), float32Array1, _rightBox1 );

// precompute the intersections otherwise the global boxes will be modified during traversal
const intersectCl1 = newBox.intersectsBox( _leftBox1 );
const intersectCr1 = newBox.intersectsBox( _rightBox1 );
const intersectCl1 = arrayIntersectsBox( BOUNDING_DATA_INDEX( cl1 ), float32Array1, newBox );
const intersectCr1 = arrayIntersectsBox( BOUNDING_DATA_INDEX( cr1 ), float32Array1, newBox );
result = (
intersectCl1 && _traverse(
node2Index32, cl1, matrix1to2, matrix2to1, intersectsRangesFunc,
Expand All @@ -200,11 +193,10 @@ function _traverse(
// get the child bounds to check
const cl2 = LEFT_NODE( node2Index32 );
const cr2 = RIGHT_NODE( node2Index32, uint32Array2 );
arrayToBox( BOUNDING_DATA_INDEX( cl2 ), float32Array2, _leftBox2 );
arrayToBox( BOUNDING_DATA_INDEX( cr2 ), float32Array2, _rightBox2 );

const leftIntersects = currBox.intersectsBox( _leftBox2 );
const rightIntersects = currBox.intersectsBox( _rightBox2 );
const leftIntersects = arrayIntersectsBox( BOUNDING_DATA_INDEX( cl2 ), float32Array2, currBox );
const rightIntersects = arrayIntersectsBox( BOUNDING_DATA_INDEX( cr2 ), float32Array2, currBox );

if ( leftIntersects && rightIntersects ) {

// continue to traverse both children if they both intersect
Expand Down Expand Up @@ -234,16 +226,15 @@ function _traverse(
// SWAP
// if only one box intersects then we have to swap to the other bvh to continue
const newBox = _boxPool.getPrimitive();
newBox.copy( _leftBox2 ).applyMatrix4( matrix2to1 );
arrayToBox( BOUNDING_DATA_INDEX( cl2 ), float32Array2, newBox );
newBox.applyMatrix4( matrix2to1 );

const cl1 = LEFT_NODE( node1Index32 );
const cr1 = RIGHT_NODE( node1Index32, uint32Array1 );
arrayToBox( BOUNDING_DATA_INDEX( cl1 ), float32Array1, _leftBox1 );
arrayToBox( BOUNDING_DATA_INDEX( cr1 ), float32Array1, _rightBox1 );

// precompute the intersections otherwise the global boxes will be modified during traversal
const intersectCl1 = newBox.intersectsBox( _leftBox1 );
const intersectCr1 = newBox.intersectsBox( _rightBox1 );
const intersectCl1 = arrayIntersectsBox( BOUNDING_DATA_INDEX( cl1 ), float32Array1, newBox );
const intersectCr1 = arrayIntersectsBox( BOUNDING_DATA_INDEX( cr1 ), float32Array1, newBox );
result = (
intersectCl1 && _traverse(
cl2, cl1, matrix1to2, matrix2to1, intersectsRangesFunc,
Expand Down Expand Up @@ -278,16 +269,15 @@ function _traverse(
// SWAP
// if only one box intersects then we have to swap to the other bvh to continue
const newBox = _boxPool.getPrimitive();
newBox.copy( _rightBox2 ).applyMatrix4( matrix2to1 );
arrayToBox( BOUNDING_DATA_INDEX( cr2 ), float32Array2, newBox );
newBox.applyMatrix4( matrix2to1 );

const cl1 = LEFT_NODE( node1Index32 );
const cr1 = RIGHT_NODE( node1Index32, uint32Array1 );
arrayToBox( BOUNDING_DATA_INDEX( cl1 ), float32Array1, _leftBox1 );
arrayToBox( BOUNDING_DATA_INDEX( cr1 ), float32Array1, _rightBox1 );

// precompute the intersections otherwise the global boxes will be modified during traversal
const intersectCl1 = newBox.intersectsBox( _leftBox1 );
const intersectCr1 = newBox.intersectsBox( _rightBox1 );
const intersectCl1 = arrayIntersectsBox( BOUNDING_DATA_INDEX( cl1 ), float32Array1, newBox );
const intersectCr1 = arrayIntersectsBox( BOUNDING_DATA_INDEX( cr1 ), float32Array1, newBox );
result = (
intersectCl1 && _traverse(
cr2, cl1, matrix1to2, matrix2to1, intersectsRangesFunc,
Expand Down
25 changes: 20 additions & 5 deletions src/core/cast/intersectsGeometry.template.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Box3, Matrix4 } from 'three';
import { OrientedBox } from '../../math/OrientedBox.js';
import { ExtendedTriangle } from '../../math/ExtendedTriangle.js';
import { setTriangle } from '../../utils/TriangleUtilities.js';
import { arrayToBox } from '../../utils/ArrayBoxUtilities.js';
import { setOBBFromArray } from '../../utils/ArrayBoxUtilities.js';
import { COUNT, OFFSET, IS_LEAF, BOUNDING_DATA_INDEX } from '../utils/nodeBufferUtils.js';
import { BufferStack } from '../utils/BufferStack.js';
import { getTriCount } from '../build/geometryUtils.js';
Expand Down Expand Up @@ -65,9 +65,8 @@ function _intersectsGeometry( nodeIndex32, bvh, otherGeometry, geometryToBvh, ca
if ( otherGeometry.boundsTree ) {

// if there's a bounds tree
arrayToBox( BOUNDING_DATA_INDEX( nodeIndex32 ), float32Array, obb2 );
setOBBFromArray( obb2, BOUNDING_DATA_INDEX( nodeIndex32 ), float32Array );
obb2.matrix.copy( invertedMat );
obb2.needsUpdate = true;

// TODO: use a triangle iteration function here
const res = otherGeometry.boundsTree.shapecast( {
Expand Down Expand Up @@ -178,14 +177,30 @@ function _intersectsGeometry( nodeIndex32, bvh, otherGeometry, geometryToBvh, ca
const left = nodeIndex32 + 8;
const right = uint32Array[ nodeIndex32 + 6 ];

arrayToBox( BOUNDING_DATA_INDEX( left ), float32Array, boundingBox );
// Check left child - inline bounds setting to avoid function call
const leftBoundsIndex = BOUNDING_DATA_INDEX( left );
boundingBox.min.x = float32Array[ leftBoundsIndex ];
boundingBox.min.y = float32Array[ leftBoundsIndex + 1 ];
boundingBox.min.z = float32Array[ leftBoundsIndex + 2 ];
boundingBox.max.x = float32Array[ leftBoundsIndex + 3 ];
boundingBox.max.y = float32Array[ leftBoundsIndex + 4 ];
boundingBox.max.z = float32Array[ leftBoundsIndex + 5 ];

const leftIntersection =
cachedObb.intersectsBox( boundingBox ) &&
_intersectsGeometry( left, bvh, otherGeometry, geometryToBvh, cachedObb );

if ( leftIntersection ) return true;

arrayToBox( BOUNDING_DATA_INDEX( right ), float32Array, boundingBox );
// Check right child - inline bounds setting to avoid function call
const rightBoundsIndex = BOUNDING_DATA_INDEX( right );
boundingBox.min.x = float32Array[ rightBoundsIndex ];
boundingBox.min.y = float32Array[ rightBoundsIndex + 1 ];
boundingBox.min.z = float32Array[ rightBoundsIndex + 2 ];
boundingBox.max.x = float32Array[ rightBoundsIndex + 3 ];
boundingBox.max.y = float32Array[ rightBoundsIndex + 4 ];
boundingBox.max.z = float32Array[ rightBoundsIndex + 5 ];

const rightIntersection =
cachedObb.intersectsBox( boundingBox ) &&
_intersectsGeometry( right, bvh, otherGeometry, geometryToBvh, cachedObb );
Expand Down
28 changes: 28 additions & 0 deletions src/utils/ArrayBoxUtilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,34 @@ export function arrayToBox( nodeIndex32, array, target ) {

}

// Optimized box intersection test that reads directly from array without creating a Box3
export function arrayIntersectsBox( nodeIndex32, array, box ) {

return array[ nodeIndex32 + 3 ] >= box.min.x &&
array[ nodeIndex32 ] <= box.max.x &&
array[ nodeIndex32 + 4 ] >= box.min.y &&
array[ nodeIndex32 + 1 ] <= box.max.y &&
array[ nodeIndex32 + 5 ] >= box.min.z &&
array[ nodeIndex32 + 2 ] <= box.max.z;

}

// Helper for OBB intersection test - reads bounds from array and sets OBB min/max directly
// This avoids creating an intermediate Box3 object for the common case
export function setOBBFromArray( obb, nodeIndex32, array ) {

obb.min.x = array[ nodeIndex32 ];
obb.min.y = array[ nodeIndex32 + 1 ];
obb.min.z = array[ nodeIndex32 + 2 ];

obb.max.x = array[ nodeIndex32 + 3 ];
obb.max.y = array[ nodeIndex32 + 4 ];
obb.max.z = array[ nodeIndex32 + 5 ];

obb.needsUpdate = true;

}

export function makeEmptyBounds( target ) {

target[ 0 ] = target[ 1 ] = target[ 2 ] = Infinity;
Expand Down
Loading