Skip to content

Commit

Permalink
Merge pull request #700 from gkjohnson/compute-batched-update
Browse files Browse the repository at this point in the history
Adjusted batched mesh bvh computation functions
  • Loading branch information
gkjohnson authored Sep 1, 2024
2 parents 7bcce17 + 7851b09 commit 77f910c
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 63 deletions.
49 changes: 33 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,19 +77,18 @@ Using pre-made functions
```js
// Import via ES6 modules
import * as THREE from 'three';
import { computeBoundsTree, disposeBoundsTree, acceleratedRaycast } from 'three-mesh-bvh';

// Or UMD
const { computeBoundsTree, disposeBoundsTree, acceleratedRaycast } = window.MeshBVHLib;

import {
computeBoundsTree, disposeBoundsTree,
computeBatchedBoundsTree, disposeBatchedBoundsTree, acceleratedRaycast,
} from 'three-mesh-bvh';

// Add the extension functions
THREE.BufferGeometry.prototype.computeBoundsTree = computeBoundsTree;
THREE.BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree;
THREE.Mesh.prototype.raycast = acceleratedRaycast;

THREE.BatchedMesh.prototype.computeBoundsTree = computeBoundsTree;
THREE.BatchedMesh.prototype.disposeBoundsTree = disposeBoundsTree;
THREE.BatchedMesh.prototype.computeBoundsTree = computeBatchedBoundsTree;
THREE.BatchedMesh.prototype.disposeBoundsTree = disposeBatchedBoundsTree;
THREE.BatchedMesh.prototype.raycast = acceleratedRaycast;

// Generate geometry and associated BVH
Expand All @@ -110,10 +109,6 @@ Or manually building the BVH
import * as THREE from 'three';
import { MeshBVH, acceleratedRaycast } from 'three-mesh-bvh';

// Or UMD
const { MeshBVH, acceleratedRaycast } = window.MeshBVHLib;


// Add the raycast function. Assumes the BVH is available on
// the `boundsTree` variable
THREE.Mesh.prototype.raycast = acceleratedRaycast;
Expand Down Expand Up @@ -845,14 +840,13 @@ If the `Raycaster` member `firstHitOnly` is set to true then the [.acceleratedRa
### .computeBoundsTree

```js
computeBoundsTree( options : Object ) : void
computeBoundsTree( options? : Object ) : void
```

A pre-made BufferGeometry and BatchedMesh extension function that builds a new BVH, assigns it to `boundsTree` for BufferGeometry or `boundsTrees` for BatchedMesh, and applies the new index buffer to the geometry. Comparable to `computeBoundingBox` and `computeBoundingSphere`.
A pre-made BufferGeometry extension function that builds a new BVH, assigns it to `boundsTree` for BufferGeometry, and applies the new index buffer to the geometry. Comparable to `computeBoundingBox` and `computeBoundingSphere`.

```js
THREE.BufferGeometry.prototype.computeBoundsTree = computeBoundsTree;
THREE.BatchedMesh.prototype.computeBoundsTree = computeBoundsTree;
```

### .disposeBoundsTree
Expand All @@ -861,11 +855,34 @@ THREE.BatchedMesh.prototype.computeBoundsTree = computeBoundsTree;
disposeBoundsTree() : void
```

A BufferGeometry and BatchedMesh extension function that disposes of the BVH.
A BufferGeometry extension function that disposes of the BVH.

```js
THREE.BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree;
THREE.BatchedMesh.prototype.disposeBoundsTree = disposeBoundsTree;
```

### .computeBatchedBoundsTree

```js
computeBatchedBoundsTree( index = - 1 : Number, options? : Object ) : void
```

Equivalent of `computeBoundsTree` for BatchedMesh. Calling this generates a `BatchedMesh.boundsTrees` array if it doesn't exist and assigns the newly generated BVHs. If `index` is -1 then BVHs for all available geometry are generated. Otherwise only the BVH for the geometry at the given index is generated.

```js
THREE.BatchedMesh.prototype.computeBoundsTree = computeBatchedBoundsTree;
```

### .disposeBatchedBoundsTree

```js
disposeBatchedBoundsTree( index = - 1 : Number, options? : Object ) : void
```

Equivalent of `disposeBoundsTree` for BatchedMesh. Calling this sets entries in `BatchedMesh.boundsTrees` array to null. If `index` is -1 then BVHs are disposed. Otherwise only the BVH for the geometry at the given index is disposed.

```js
THREE.BatchedMesh.prototype.disposeBoundsTree = disposeBatchedBoundsTree;
```

### .acceleratedRaycast
Expand Down
24 changes: 14 additions & 10 deletions example/batchedMesh.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@ import * as dat from 'three/examples/jsm/libs/lil-gui.module.min.js';
import * as THREE from 'three';
import {
acceleratedRaycast, computeBoundsTree, disposeBoundsTree,
computeBatchedBoundsTree, disposeBatchedBoundsTree,
CENTER, SAH, AVERAGE,
} from '..';

THREE.Mesh.prototype.raycast = acceleratedRaycast;
THREE.BufferGeometry.prototype.computeBoundsTree = computeBoundsTree;
THREE.BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree;

THREE.BatchedMesh.prototype.raycast = acceleratedRaycast;
THREE.BatchedMesh.prototype.computeBoundsTree = computeBoundsTree;
THREE.BatchedMesh.prototype.disposeBoundsTree = disposeBoundsTree;
THREE.BatchedMesh.prototype.computeBoundsTree = computeBatchedBoundsTree;
THREE.BatchedMesh.prototype.disposeBoundsTree = disposeBatchedBoundsTree;

const bgColor = 0x263238 / 2;
const bgColor = 0xcfd8dc;
const meshColor = 0x263238;
const lineColor = 0xd81b60;

let renderer, scene, stats, camera;
let material, containerObj, batchedMesh;
Expand Down Expand Up @@ -61,15 +65,15 @@ function init() {

// scene setup
scene = new THREE.Scene();
scene.fog = new THREE.Fog( 0x263238 / 2, 40, 80 );
scene.fog = new THREE.Fog( bgColor, 40, 100 );

const light = new THREE.DirectionalLight( 0xffffff, 0.5 );
const light = new THREE.DirectionalLight( 0xffffff, 1.5 );
light.position.set( 1, 1, 1 );
scene.add( light );
scene.add( new THREE.AmbientLight( 0xffffff, 0.4 ) );
scene.add( new THREE.AmbientLight( 0xffffff, 1.2 ) );

containerObj = new THREE.Object3D();
material = new THREE.MeshPhongMaterial( { color: 0xE91E63 } );
material = new THREE.MeshPhongMaterial( { color: meshColor } );
containerObj.scale.multiplyScalar( 10 );
containerObj.rotation.x = 10.989999999999943;
containerObj.rotation.y = 10.989999999999943;
Expand Down Expand Up @@ -189,13 +193,13 @@ function addRaycaster() {

// Objects
const obj = new THREE.Object3D();
const material = new THREE.MeshBasicMaterial( { color: 0xffffff } );
const material = new THREE.MeshBasicMaterial( { color: lineColor } );
const origMesh = new THREE.Mesh( sphere, material );
const hitMesh = new THREE.Mesh( sphere, material );
hitMesh.scale.multiplyScalar( 0.25 );
origMesh.scale.multiplyScalar( 0.5 );

const cylinderMesh = new THREE.Mesh( cylinder, new THREE.MeshBasicMaterial( { color: 0xffffff, transparent: true, opacity: 0.25 } ) );
const cylinderMesh = new THREE.Mesh( cylinder, new THREE.MeshBasicMaterial( { color: lineColor, transparent: true, opacity: 0.5 } ) );

// Init the rotation root
obj.add( cylinderMesh );
Expand Down Expand Up @@ -288,7 +292,7 @@ function updateFromOptions() {
if ( params.mesh.useBoundsTree && ! batchedMesh.boundsTrees ) {

console.time( 'computing bounds tree' );
batchedMesh.computeBoundsTree( {
batchedMesh.computeBoundsTree( - 1, {
maxLeafTris: 5,
strategy: parseFloat( params.mesh.splitStrategy ),
} );
Expand Down
12 changes: 8 additions & 4 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,10 +199,14 @@ export class MeshBVHHelper extends Group {

// THREE.js Extensions

export function computeBoundsTree( options?: MeshBVHOptions ): MeshBVH | MeshBVH[];
export function computeBoundsTree( options?: MeshBVHOptions ): MeshBVH;

export function disposeBoundsTree(): void;

export function computeBatchedBoundsTree( index?: Number, options?: MeshBVHOptions ): MeshBVH | MeshBVH[];

export function disposeBatchedBoundsTree( index?: Number ): void;

export function acceleratedRaycast(
raycaster: Raycaster,
intersects: Array<Intersection>
Expand All @@ -216,9 +220,9 @@ declare module 'three' {
}

export interface BatchedMesh {
boundsTrees?: MeshBVH[];
computeBoundsTree: typeof computeBoundsTree;
disposeBoundsTree: typeof disposeBoundsTree;
boundsTrees?: Array<MeshBVH | null>;
computeBoundsTree: typeof computeBatchedBoundsTree;
disposeBoundsTree: typeof disposeBatchedBoundsTree;
}

export interface Raycaster {
Expand Down
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export { MeshBVH } from './core/MeshBVH.js';
export { MeshBVHHelper } from './objects/MeshBVHHelper.js';
export { CENTER, AVERAGE, SAH, NOT_INTERSECTED, INTERSECTED, CONTAINED } from './core/Constants.js';
export { getBVHExtremes, estimateMemoryInBytes, getJSONStructure, validateBounds } from './debug/Debug.js';
export { acceleratedRaycast, computeBoundsTree, disposeBoundsTree } from './utils/ExtensionUtilities.js';
export * from './utils/ExtensionUtilities.js';
export { getTriangleHitPointInfo } from './utils/TriangleUtilities.js';
export * from './math/ExtendedTriangle.js';
export * from './math/OrientedBox.js';
Expand Down
84 changes: 59 additions & 25 deletions src/utils/ExtensionUtilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,30 +151,53 @@ function acceleratedMeshRaycast( raycaster, intersects ) {

export function computeBoundsTree( options = {} ) {

if ( this.isBatchedMesh ) {
this.boundsTree = new MeshBVH( this, options );
return this.boundsTree;

if ( ! IS_REVISION_166 ) {
}

console.error( 'Three r166+ is required.' );
return;
export function disposeBoundsTree() {

}
this.boundsTree = null;

if ( options.indirect ) {
}

console.warn( '"Indirect" is set to false because it is not supported for BatchedMesh.' );
export function computeBatchedBoundsTree( index = - 1, options = {} ) {

}
if ( ! IS_REVISION_166 ) {

options = {
...options,
indirect: false,
range: null
};
throw new Error( 'BatchedMesh: Three r166+ is required to compute bounds trees.' );

const drawRanges = this._drawRanges;
const geometryCount = this._geometryCount;
const boundsTrees = [];
}

if ( options.indirect ) {

console.warn( '"Indirect" is set to false because it is not supported for BatchedMesh.' );

}

options = {
...options,
indirect: false,
range: null
};

const drawRanges = this._drawRanges;
const geometryCount = this._geometryCount;
if ( ! this.boundsTrees ) {

this.boundsTrees = new Array( geometryCount ).fill( null );

}

const boundsTrees = this.boundsTrees;
while ( boundsTrees.length < geometryCount ) {

boundsTrees.push( null );

}

if ( index < 0 ) {

for ( let i = 0; i < geometryCount; i ++ ) {

Expand All @@ -183,25 +206,36 @@ export function computeBoundsTree( options = {} ) {

}

this.boundsTrees = boundsTrees;
return this.boundsTrees;
return boundsTrees;

}
} else {

this.boundsTree = new MeshBVH( this, options );
return this.boundsTree;
if ( index < drawRanges.length ) {

options.range = drawRanges[ index ];
boundsTrees[ index ] = new MeshBVH( this.geometry, options );

}

return boundsTrees[ index ] || null;

}

}

export function disposeBoundsTree() {
export function disposeBatchedBoundsTree( index = - 1 ) {

if ( this.isBatchedMesh ) {
if ( index < 0 ) {

this.boundsTrees = null;
this.boundsTrees.fill( null );

} else {

this.boundsTree = null;
if ( index < this.boundsTree.length ) {

this.boundsTrees[ index ] = null;

}

}

Expand Down
10 changes: 6 additions & 4 deletions test/RandomRaycasts.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {
acceleratedRaycast,
computeBoundsTree,
disposeBoundsTree,
computeBatchedBoundsTree,
disposeBatchedBoundsTree,
CENTER,
SAH,
AVERAGE,
Expand All @@ -26,8 +28,8 @@ Mesh.prototype.raycast = acceleratedRaycast;
BufferGeometry.prototype.computeBoundsTree = computeBoundsTree;
BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree;
BatchedMesh.prototype.raycast = acceleratedRaycast;
BatchedMesh.prototype.computeBoundsTree = computeBoundsTree;
BatchedMesh.prototype.disposeBoundsTree = disposeBoundsTree;
BatchedMesh.prototype.computeBoundsTree = computeBatchedBoundsTree;
BatchedMesh.prototype.disposeBoundsTree = disposeBatchedBoundsTree;

describe( 'Random CENTER intersections', () => runRandomTests( { strategy: CENTER } ) );
describe( 'Random Interleaved CENTER intersections', () => runRandomTests( { strategy: CENTER, interleaved: true } ) );
Expand Down Expand Up @@ -144,14 +146,14 @@ function runRandomTests( options ) {
const geoId = batchedMesh.addGeometry( geo );
if ( options.onlyOneGeo ) {

batchedMesh.computeBoundsTree( options );
batchedMesh.computeBoundsTree( - 1, options );

}

const geo2Id = batchedMesh.addGeometry( geo2 );
if ( ! options.onlyOneGeo ) {

batchedMesh.computeBoundsTree( options );
batchedMesh.computeBoundsTree( - 1, options );

}

Expand Down
8 changes: 5 additions & 3 deletions test/TypescriptImportTest.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { BufferGeometry, Mesh, Raycaster, BatchedMesh } from 'three';
import { acceleratedRaycast, computeBoundsTree, disposeBoundsTree } from '../src/index';
import { acceleratedRaycast, computeBoundsTree, disposeBoundsTree, computeBatchedBoundsTree, disposeBatchedBoundsTree } from '../src/index';

Mesh.prototype.raycast = acceleratedRaycast;
BufferGeometry.prototype.computeBoundsTree = computeBoundsTree;
BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree;
BatchedMesh.prototype.computeBoundsTree = computeBoundsTree;
BatchedMesh.prototype.disposeBoundsTree = disposeBoundsTree;

BatchedMesh.prototype.raycast = acceleratedRaycast;
BatchedMesh.prototype.computeBoundsTree = computeBatchedBoundsTree;
BatchedMesh.prototype.disposeBoundsTree = disposeBatchedBoundsTree;

const mesh = new Mesh();
mesh.geometry.computeBoundsTree();
Expand Down

0 comments on commit 77f910c

Please sign in to comment.