Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove lazyGeneration option #196

Merged
merged 15 commits into from
Mar 2, 2021
12 changes: 1 addition & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ const invMat = new THREE.Matrix4();

// ...

const bvh = new MeshBVH( geometry, { lazyGeneration: false } );
const bvh = new MeshBVH( geometry );
invMat.copy( mesh.matrixWorld ).invert();

// raycasting
Expand Down Expand Up @@ -224,16 +224,6 @@ Constructs the bounds tree for the given geometry and produces a new index attri
// Print out warnings encountered during tree construction.
verbose: true,

// If true the bounds tree is generated progressively as the tree is used allowing
// for a fast initialization time and memory allocation as needed but a higher memory
// footprint once the tree is completed. The initial raycasts are also slower until the
// tree is built up.
// If false then the bounds tree will be completely generated up front and packed into
// an array buffer for a lower final memory footprint and long initialization time.
// Note that this will keep intermediate buffers needed for generation in scope until
// the tree has been fully generated.
lazyGeneration: true

}
```

Expand Down
31 changes: 13 additions & 18 deletions benchmark/run-benchmark.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,9 @@ function logExtremes( bvh, geometry ) {

}

function runSuite( strategy, lazyGeneration = true ) {

const options = { lazyGeneration, strategy };
let preFunc = lazyGeneration ? () => geometry.computeBoundsTree( options ) : null;
function runSuite( strategy ) {

const options = { strategy };
geometry.computeBoundsTree( options );
logExtremes( geometry.boundsTree, geometry );

Expand All @@ -69,7 +67,7 @@ function runSuite( strategy, lazyGeneration = true ) {
runBenchmark(

'Serialize',
preFunc,
null,
() => {

MeshBVH.serialize( geometry.boundsTree, geometry );
Expand All @@ -84,7 +82,7 @@ function runSuite( strategy, lazyGeneration = true ) {
runBenchmark(

'Deserialize',
preFunc,
null,
() => {

MeshBVH.deserialize( serialized, geometry );
Expand All @@ -100,7 +98,7 @@ function runSuite( strategy, lazyGeneration = true ) {
runBenchmark(

'BVH Raycast',
preFunc,
null,
() => mesh.raycast( raycaster, [] ),
3000

Expand All @@ -110,7 +108,7 @@ function runSuite( strategy, lazyGeneration = true ) {
runBenchmark(

'First Hit Raycast',
preFunc,
null,
() => mesh.raycast( raycaster, [] ),
3000

Expand All @@ -119,7 +117,7 @@ function runSuite( strategy, lazyGeneration = true ) {
runBenchmark(

'Sphere Shapecast',
preFunc,
null,
() => {

mesh.geometry.boundsTree.shapecast( mesh, box => sphere.intersectsBox( box ), tri => {
Expand All @@ -136,7 +134,7 @@ function runSuite( strategy, lazyGeneration = true ) {
runBenchmark(

'IntersectsSphere',
preFunc,
null,
() => mesh.geometry.boundsTree.intersectsSphere( mesh, sphere ),
3000

Expand All @@ -145,7 +143,7 @@ function runSuite( strategy, lazyGeneration = true ) {
runBenchmark(

'IntersectsBox',
preFunc,
null,
() => mesh.geometry.boundsTree.intersectsBox( mesh, box, boxMat ),
3000

Expand All @@ -154,7 +152,7 @@ function runSuite( strategy, lazyGeneration = true ) {
runBenchmark(

'DistanceToGeometry',
preFunc,
null,
() => mesh.geometry.boundsTree.closestPointToGeometry( mesh, intersectGeometry, geomMat, target1, target2 ),
3000

Expand All @@ -164,7 +162,7 @@ function runSuite( strategy, lazyGeneration = true ) {
runBenchmark(

'DistanceToPoint',
preFunc,
null,
() => mesh.geometry.boundsTree.closestPointToPoint( mesh, vec, target1 ),
3000

Expand All @@ -176,7 +174,7 @@ function runSuite( strategy, lazyGeneration = true ) {
runBenchmark(

'IntersectsGeometry with BVH',
preFunc,
null,
() => mesh.geometry.boundsTree.intersectsGeometry( mesh, intersectGeometry, geomMat ),
3000

Expand All @@ -187,7 +185,7 @@ function runSuite( strategy, lazyGeneration = true ) {
runBenchmark(

'IntersectsGeometry without BVH',
preFunc,
null,
() => mesh.geometry.boundsTree.intersectsGeometry( mesh, intersectGeometry, geomMat ),
3000

Expand All @@ -199,9 +197,6 @@ function runSuite( strategy, lazyGeneration = true ) {
console.log( '*Strategy: CENTER*' );
runSuite( CENTER );

console.log( '' );
console.log( '*Strategy: Non-Lazy CENTER*' );
runSuite( CENTER, false );

console.log( '' );
console.log( '*Strategy: AVERAGE*' );
Expand Down
2 changes: 1 addition & 1 deletion scripts/generate-cast-functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import path from 'path';
function replaceUnneededCode( str ) {

str = str.replace(
/if \( [^)]*node.continueGeneration \)(.|\n|\r)*?}[\r|\n]/mg,
/\/\* INSERT_BUFFER_VARS \*\//mg,
match => {

if ( match.indexOf( '/* skip */' ) !== - 1 ) {
Expand Down
28 changes: 4 additions & 24 deletions src/MeshBVH.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,6 @@ export default class MeshBVH {

static serialize( bvh, geometry, copyIndexBuffer = true ) {

function finishTree( node ) {

if ( node.continueGeneration ) {

node.continueGeneration();

}

if ( ! node.count ) {

finishTree( node.left );
finishTree( node.right );

}

}

function countNodes( node ) {

if ( node.count ) {
Expand Down Expand Up @@ -125,7 +108,6 @@ export default class MeshBVH {
for ( let i = 0; i < roots.length; i ++ ) {

const root = roots[ i ];
finishTree( root );
let nodeCount = countNodes( root );

const buffer = new ArrayBuffer( BYTES_PER_NODE * nodeCount );
Expand Down Expand Up @@ -200,12 +182,10 @@ export default class MeshBVH {
maxDepth: 40,
maxLeafTris: 10,
verbose: true,
lazyGeneration: true,

// undocumented options

// whether to the pack the data as a buffer or not. The data
// will not be packed if lazyGeneration is true.
// whether to the pack the data as a buffer or not.
packData: true,

// Whether to skip generating the tree. Used for deserialization.
Expand All @@ -219,7 +199,7 @@ export default class MeshBVH {
if ( ! options[ SKIP_GENERATION ] ) {

this._roots = buildTree( geo, options );
if ( ! options.lazyGeneration && options.packData ) {
if ( options.packData ) {

this._roots = MeshBVH.serialize( this, geo, false ).roots;
this._isPacked = true;
Expand Down Expand Up @@ -254,7 +234,7 @@ export default class MeshBVH {
const left = stride4Offset + BYTES_PER_NODE / 4;
const right = uint32Array[ stride4Offset + 6 ];
const splitAxis = uint32Array[ stride4Offset + 7 ];
const stopTraversal = callback( depth, isLeaf, new Float32Array( buffer, stride4Offset * 4, 6 ), splitAxis, false );
const stopTraversal = callback( depth, isLeaf, new Float32Array( buffer, stride4Offset * 4, 6 ), splitAxis );

if ( ! stopTraversal ) {

Expand All @@ -280,7 +260,7 @@ export default class MeshBVH {

} else {

const stopTraversal = callback( depth, isLeaf, node.boundingData, node.splitAxis, ! ! node.continueGeneration );
const stopTraversal = callback( depth, isLeaf, node.boundingData, node.splitAxis );

if ( ! stopTraversal ) {

Expand Down
6 changes: 3 additions & 3 deletions src/Utils/Debug.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,16 @@ function getRootExtremes( bvh, group ) {
splits: [ 0, 0, 0 ]
};

bvh.traverse( ( depth, isLeaf, boundingData, offsetOrSplit, countOrIsUnfinished ) => {
bvh.traverse( ( depth, isLeaf, boundingData, offsetOrSplit, count ) => {

result.total ++;
if ( isLeaf ) {

result.depth.min = Math.min( depth, result.depth.min );
result.depth.max = Math.max( depth, result.depth.max );

result.tris.min = Math.min( countOrIsUnfinished, result.tris.min );
result.tris.max = Math.max( countOrIsUnfinished, result.tris.max );
result.tris.min = Math.min( count, result.tris.min );
result.tris.max = Math.max( count, result.tris.max );

} else {

Expand Down
39 changes: 4 additions & 35 deletions src/buildFunctions.js
Original file line number Diff line number Diff line change
Expand Up @@ -552,23 +552,8 @@ export function buildTree( geo, options ) {
node.left = left;
left.boundingData = new Float32Array( 6 );

if ( lazyGeneration ) {

getBounds( triangleBounds, lstart, lcount, left.boundingData );
left.continueGeneration = function () {

delete this.continueGeneration;
getCentroidBounds( triangleBounds, lstart, lcount, cacheCentroidBoundingData );
splitNode( left, lstart, lcount, cacheCentroidBoundingData, depth + 1 );

};

} else {

getBounds( triangleBounds, lstart, lcount, left.boundingData, cacheCentroidBoundingData );
splitNode( left, lstart, lcount, cacheCentroidBoundingData, depth + 1 );

}
getBounds( triangleBounds, lstart, lcount, left.boundingData, cacheCentroidBoundingData );
splitNode( left, lstart, lcount, cacheCentroidBoundingData, depth + 1 );

// repeat for right
const right = new MeshBVHNode();
Expand All @@ -577,23 +562,8 @@ export function buildTree( geo, options ) {
node.right = right;
right.boundingData = new Float32Array( 6 );

if ( lazyGeneration ) {

getBounds( triangleBounds, rstart, rcount, right.boundingData );
right.continueGeneration = function () {

delete this.continueGeneration;
getCentroidBounds( triangleBounds, rstart, rcount, cacheCentroidBoundingData );
splitNode( right, rstart, rcount, cacheCentroidBoundingData, depth + 1 );

};

} else {

getBounds( triangleBounds, rstart, rcount, right.boundingData, cacheCentroidBoundingData );
splitNode( right, rstart, rcount, cacheCentroidBoundingData, depth + 1 );

}
getBounds( triangleBounds, rstart, rcount, right.boundingData, cacheCentroidBoundingData );
splitNode( right, rstart, rcount, cacheCentroidBoundingData, depth + 1 );

}

Expand All @@ -611,7 +581,6 @@ export function buildTree( geo, options ) {
const verbose = options.verbose;
const maxLeafTris = options.maxLeafTris;
const strategy = options.strategy;
const lazyGeneration = options.lazyGeneration;
let reachedMaxDepth = false;

const roots = [];
Expand Down
Loading