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

Adjusted batched mesh bvh computation functions #700

Merged
merged 7 commits into from
Sep 1, 2024
Merged
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
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
Loading