Переглянути джерело

InstancedMesh: Add bounding volumes. (#25591)

* InstancedMesh: Add bounding volumes.

* CurveModifier: Clean up.
Michael Herzog 2 роки тому
батько
коміт
5139941d7e

+ 22 - 0
docs/api/en/objects/InstancedMesh.html

@@ -37,6 +37,16 @@
 		<h2>Properties</h2>
 		<p>See the base [page:Mesh] class for common properties.</p>
 
+		<h3>[property:Box3 boundingBox]</h3>
+		<p>
+			This bounding box encloses all instances of the [name]. Can be calculated with [page:.computeBoundingBox](). Default is `null`.
+		</p>
+
+		<h3>[property:Sphere boundingSphere]</h3>
+		<p>
+			This bounding sphere encloses all instances of the [name]. Can be calculated with [page:.computeBoundingSphere](). Default is `null`.
+		</p>
+
 		<h3>[property:Integer count]</h3>
 		<p>
 			The number of instances. The `count` value passed into the constructor represents the maximum number of
@@ -67,6 +77,18 @@
 		<h2>Methods</h2>
 		<p>See the base [page:Mesh] class for common methods.</p>
 
+		<h3>[method:undefined computeBoundingBox]()</h3>
+		<p>
+		Computes the bounding box, updating [page:.boundingBox] attribute.<br />
+		Bounding boxes aren't computed by default. They need to be explicitly computed, otherwise they are `null`.
+		</p>
+
+		<h3>[method:undefined computeBoundingSphere]()</h3>
+		<p>
+		Computes the bounding sphere, updating [page:.boundingSphere] attribute.<br />
+		Bounding spheres aren't computed by default. They need to be explicitly computed, otherwise they are `null`.
+		</p>
+
 		<h3>[method:undefined dispose]()</h3>
 		<p>
 			Frees the GPU-related resources allocated by this instance. Call this method whenever this instance is no longer used in your app.

+ 24 - 0
docs/api/it/objects/InstancedMesh.html

@@ -38,6 +38,16 @@
 		<h2>Proprietà</h2>
 		<p>Vedi la classe base [page:Mesh] per le proprietà comuni.</p>
 
+		<h3>[property:Box3 boundingBox]</h3>
+		<p>
+			Bounding box per la [name], che può essere calcolato con [page:.computeBoundingBox](). Il valore predefinito è `null`.
+		</p>
+
+		<h3>[property:Sphere boundingSphere]</h3>
+		<p>
+			Bounding sphere per la [name], che può essere calcolato con [page:.computeBoundingSphere](). Il valore predefinito è `null`.
+		</p>
+
 		<h3>[property:Integer count]</h3>
 		<p>
 			Il numero di istanze. Il valore `count` passato nel costruttore rappresenta il numero 
@@ -70,6 +80,20 @@
 		<h2>Metodi</h2>
 		<p>Vedi la classe base [page:Mesh] per i metodi comuni.</p>
 
+		<h3>[method:undefined computeBoundingBox]()</h3>
+		<p>
+			Calcola il bounding box, aggiornando l'attributo [page:.boundingBox]. <br />
+			I Bounding box non sono calcolati per impostazione predefinita. Devono essere calcolati esplicitamente,
+			altrimenti sono `null`.
+		</p>
+
+		<h3>[method:undefined computeBoundingSphere]()</h3>
+		<p>
+			Calcola il bounding sphere, aggiornando l'attributo [page:.boundingSphere]. <br />
+			I Bounding sphere non sono calcolati per impostazione predefinita. Devono essere calcolati esplicitamente,
+			altrimenti sono `null`.
+		</p>
+
 		<h3>[method:undefined dispose]()</h3>
 		<p>
 			Libera le risorse relative alla GPU allocate da questa istanza.

+ 22 - 0
docs/api/zh/objects/InstancedMesh.html

@@ -36,6 +36,16 @@
 		<h2>属性</h2>
 		<p>See the base [page:Mesh] class for common properties.</p>
 
+		<h3>[property:Box3 boundingBox]</h3>
+		<p>
+			当前 [name] 的外边界矩形。可以通过 [page:.computeBoundingBox]() 计算。默认值是 *null*。
+		</p>
+
+		<h3>[property:Sphere boundingSphere]</h3>
+		<p>
+			当前 [name] 的外边界球形。可以通过 [page:.computeBoundingSphere]() 计算。默认值是 *null*。
+		</p>
+
 		<h3>[property:Integer count]</h3>
 		<p>
 			实例的数量。被传入到构造函数中的*count*表示mesh实例数量的最大值。
@@ -66,6 +76,18 @@
 		<h2>方法</h2>
 		<p>See the base [page:Mesh] class for common methods.</p>
 
+		<h3>[method:undefined computeBoundingBox]()</h3>
+		<p>
+			计算当前几何体的的边界矩形,该操作会更新已有 [param:.boundingBox]。<br />
+			边界矩形不会默认计算,需要调用该接口指定计算边界矩形,否则保持默认值 *null*。
+		</p>
+
+		<h3>[method:undefined computeBoundingSphere]()</h3>
+		<p>
+			计算当前几何体的的边界球形,该操作会更新已有 [param:.boundingSphere]。<br />
+			边界球形不会默认计算,需要调用该接口指定计算边界球形,否则保持默认值 *null*。
+		</p>
+
 		<h3>[method:undefined dispose]()</h3>
 		<p>
 			Frees the internal resources of this instance.

+ 1 - 0
examples/jsm/modifiers/CurveModifier.js

@@ -270,6 +270,7 @@ export class InstancedFlow extends Flow {
 			count
 		);
 		mesh.instanceMatrix.setUsage( DynamicDrawUsage );
+		mesh.frustumCulled = false;
 		super( mesh, curveCount );
 
 		this.offsets = new Array( count ).fill( 0 );

+ 1 - 0
examples/jsm/physics/AmmoPhysics.js

@@ -222,6 +222,7 @@ async function AmmoPhysics() {
 				}
 
 				mesh.instanceMatrix.needsUpdate = true;
+				mesh.computeBoundingSphere();
 
 			} else if ( mesh.isMesh ) {
 

+ 1 - 0
examples/jsm/physics/OimoPhysics.js

@@ -172,6 +172,7 @@ async function OimoPhysics() {
 				}
 
 				mesh.instanceMatrix.needsUpdate = true;
+				mesh.computeBoundingSphere();
 
 			} else if ( mesh.isMesh ) {
 

+ 1 - 0
examples/webgl_buffergeometry_instancing_interleaved.html

@@ -221,6 +221,7 @@
 			}
 
 			mesh.instanceMatrix.needsUpdate = true;
+			mesh.computeBoundingSphere();
 
 			lastTime = time;
 

+ 1 - 0
examples/webgl_instancing_dynamic.html

@@ -139,6 +139,7 @@
 					}
 
 					mesh.instanceMatrix.needsUpdate = true;
+					mesh.computeBoundingSphere();
 
 				}
 

+ 3 - 0
examples/webgl_instancing_scatter.html

@@ -310,6 +310,9 @@
 					stemMesh.instanceMatrix.needsUpdate = true;
 					blossomMesh.instanceMatrix.needsUpdate = true;
 
+					stemMesh.computeBoundingSphere();
+					blossomMesh.computeBoundingSphere();
+
 				}
 
 				renderer.render( scene, camera );

+ 32 - 15
src/math/Box3.js

@@ -159,32 +159,49 @@ class Box3 {
 
 		object.updateWorldMatrix( false, false );
 
-		const geometry = object.geometry;
+		if ( object.boundingBox !== undefined ) {
 
-		if ( geometry !== undefined ) {
+			if ( object.boundingBox === null ) {
 
-			if ( precise && geometry.attributes !== undefined && geometry.attributes.position !== undefined ) {
+				object.computeBoundingBox();
 
-				const position = geometry.attributes.position;
-				for ( let i = 0, l = position.count; i < l; i ++ ) {
+			}
 
-					_vector.fromBufferAttribute( position, i ).applyMatrix4( object.matrixWorld );
-					this.expandByPoint( _vector );
+			_box.copy( object.boundingBox );
+			_box.applyMatrix4( object.matrixWorld );
 
-				}
+			this.union( _box );
 
-			} else {
+		} else {
 
-				if ( geometry.boundingBox === null ) {
+			const geometry = object.geometry;
 
-					geometry.computeBoundingBox();
+			if ( geometry !== undefined ) {
 
-				}
+				if ( precise && geometry.attributes !== undefined && geometry.attributes.position !== undefined ) {
+
+					const position = geometry.attributes.position;
+					for ( let i = 0, l = position.count; i < l; i ++ ) {
+
+						_vector.fromBufferAttribute( position, i ).applyMatrix4( object.matrixWorld );
+						this.expandByPoint( _vector );
+
+					}
 
-				_box.copy( geometry.boundingBox );
-				_box.applyMatrix4( object.matrixWorld );
+				} else {
 
-				this.union( _box );
+					if ( geometry.boundingBox === null ) {
+
+						geometry.computeBoundingBox();
+
+					}
+
+					_box.copy( geometry.boundingBox );
+					_box.applyMatrix4( object.matrixWorld );
+
+					this.union( _box );
+
+				}
 
 			}
 

+ 13 - 3
src/math/Frustum.js

@@ -64,11 +64,21 @@ class Frustum {
 
 	intersectsObject( object ) {
 
-		const geometry = object.geometry;
+		if ( object.boundingSphere !== undefined ) {
 
-		if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
+			if ( object.boundingSphere === null ) object.computeBoundingSphere();
 
-		_sphere.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld );
+			_sphere.copy( object.boundingSphere ).applyMatrix4( object.matrixWorld );
+
+		} else {
+
+			const geometry = object.geometry;
+
+			if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
+
+			_sphere.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld );
+
+		}
 
 		return this.intersectsSphere( _sphere );
 

+ 68 - 1
src/objects/InstancedMesh.js

@@ -1,14 +1,18 @@
 import { InstancedBufferAttribute } from '../core/InstancedBufferAttribute.js';
 import { Mesh } from './Mesh.js';
+import { Box3 } from '../math/Box3.js';
 import { Matrix4 } from '../math/Matrix4.js';
+import { Sphere } from '../math/Sphere.js';
 
 const _instanceLocalMatrix = /*@__PURE__*/ new Matrix4();
 const _instanceWorldMatrix = /*@__PURE__*/ new Matrix4();
 
 const _instanceIntersects = [];
 
+const _box3 = /*@__PURE__*/ new Box3();
 const _identity = /*@__PURE__*/ new Matrix4();
 const _mesh = /*@__PURE__*/ new Mesh();
+const _sphere = /*@__PURE__*/ new Sphere();
 
 class InstancedMesh extends Mesh {
 
@@ -23,7 +27,8 @@ class InstancedMesh extends Mesh {
 
 		this.count = count;
 
-		this.frustumCulled = false;
+		this.boundingBox = null;
+		this.boundingSphere = null;
 
 		for ( let i = 0; i < count; i ++ ) {
 
@@ -33,6 +38,68 @@ class InstancedMesh extends Mesh {
 
 	}
 
+	computeBoundingBox() {
+
+		const geometry = this.geometry;
+		const count = this.count;
+
+		if ( this.boundingBox === null ) {
+
+			this.boundingBox = new Box3();
+
+		}
+
+		if ( geometry.boundingBox === null ) {
+
+			geometry.computeBoundingBox();
+
+		}
+
+		this.boundingBox.makeEmpty();
+
+		for ( let i = 0; i < count; i ++ ) {
+
+			this.getMatrixAt( i, _instanceLocalMatrix );
+
+			_box3.copy( geometry.boundingBox ).applyMatrix4( _instanceLocalMatrix );
+
+			this.boundingBox.union( _box3 );
+
+		}
+
+	}
+
+	computeBoundingSphere() {
+
+		const geometry = this.geometry;
+		const count = this.count;
+
+		if ( this.boundingSphere === null ) {
+
+			this.boundingSphere = new Sphere();
+
+		}
+
+		if ( geometry.boundingSphere === null ) {
+
+			geometry.computeBoundingSphere();
+
+		}
+
+		this.boundingSphere.makeEmpty();
+
+		for ( let i = 0; i < count; i ++ ) {
+
+			this.getMatrixAt( i, _instanceLocalMatrix );
+
+			_sphere.copy( geometry.boundingSphere ).applyMatrix4( _instanceLocalMatrix );
+
+			this.boundingSphere.union( _sphere );
+
+		}
+
+	}
+
 	copy( source, recursive ) {
 
 		super.copy( source, recursive );