|
|
@@ -3,7 +3,6 @@ import { Frustum } from './Frustum.js';
|
|
|
import { Matrix4 } from './Matrix4.js';
|
|
|
|
|
|
const _projScreenMatrix = /*@__PURE__*/ new Matrix4();
|
|
|
-const _frustum = /*@__PURE__*/ new Frustum();
|
|
|
|
|
|
/**
|
|
|
* FrustumArray is used to determine if an object is visible in at least one camera
|
|
|
@@ -25,220 +24,191 @@ class FrustumArray {
|
|
|
*/
|
|
|
this.coordinateSystem = WebGLCoordinateSystem;
|
|
|
|
|
|
+ /**
|
|
|
+ * A pool of frustum instances. It may hold more entries than are
|
|
|
+ * currently in use; surplus instances are kept for reuse to avoid
|
|
|
+ * reallocating when array cameras of different lengths are rendered.
|
|
|
+ *
|
|
|
+ * @private
|
|
|
+ * @type {Array<Frustum>}
|
|
|
+ */
|
|
|
+ this._frustums = [];
|
|
|
+
|
|
|
+ /**
|
|
|
+ * The number of frustums in {@link FrustumArray#_frustums} that are currently
|
|
|
+ * in use.
|
|
|
+ *
|
|
|
+ * @private
|
|
|
+ * @type {number}
|
|
|
+ * @default 0
|
|
|
+ */
|
|
|
+ this._count = 0;
|
|
|
+
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Returns `true` if the 3D object's bounding sphere is intersecting any frustum
|
|
|
- * from the camera array.
|
|
|
+ * Computes and caches a frustum for each camera of the given array camera.
|
|
|
*
|
|
|
- * @param {Object3D} object - The 3D object to test.
|
|
|
- * @param {Object} cameraArray - An object with a cameras property containing an array of cameras.
|
|
|
- * @return {boolean} Whether the 3D object is visible in any camera.
|
|
|
+ * @param {ArrayCamera} cameraArray - The array camera whose sub-cameras define the frustums.
|
|
|
+ * @return {FrustumArray} A reference to this frustum array.
|
|
|
*/
|
|
|
- intersectsObject( object, cameraArray ) {
|
|
|
-
|
|
|
- if ( ! cameraArray.isArrayCamera || cameraArray.cameras.length === 0 ) {
|
|
|
-
|
|
|
- return false;
|
|
|
-
|
|
|
- }
|
|
|
+ setFromArrayCamera( cameraArray ) {
|
|
|
|
|
|
- for ( let i = 0; i < cameraArray.cameras.length; i ++ ) {
|
|
|
+ const cameras = cameraArray.cameras;
|
|
|
+ const frustums = this._frustums;
|
|
|
|
|
|
- const camera = cameraArray.cameras[ i ];
|
|
|
+ for ( let i = 0; i < cameras.length; i ++ ) {
|
|
|
|
|
|
- _projScreenMatrix.multiplyMatrices(
|
|
|
- camera.projectionMatrix,
|
|
|
- camera.matrixWorldInverse
|
|
|
- );
|
|
|
+ const camera = cameras[ i ];
|
|
|
|
|
|
- _frustum.setFromProjectionMatrix(
|
|
|
- _projScreenMatrix,
|
|
|
- camera.coordinateSystem,
|
|
|
- camera.reversedDepth
|
|
|
- );
|
|
|
+ _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
|
|
|
|
|
|
- if ( _frustum.intersectsObject( object ) ) {
|
|
|
+ if ( frustums[ i ] === undefined ) frustums[ i ] = new Frustum();
|
|
|
|
|
|
- return true; // Object is visible in at least one camera
|
|
|
-
|
|
|
- }
|
|
|
+ frustums[ i ].setFromProjectionMatrix( _projScreenMatrix, camera.coordinateSystem, camera.reversedDepth );
|
|
|
|
|
|
}
|
|
|
|
|
|
- return false; // Not visible in any camera
|
|
|
+ this._count = cameras.length;
|
|
|
+
|
|
|
+ return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Returns `true` if the given sprite is intersecting any frustum
|
|
|
- * from the camera array.
|
|
|
+ * Returns `true` if the 3D object's bounding sphere is intersecting any cached frustum.
|
|
|
*
|
|
|
- * @param {Sprite} sprite - The sprite to test.
|
|
|
- * @param {Object} cameraArray - An object with a cameras property containing an array of cameras.
|
|
|
- * @return {boolean} Whether the sprite is visible in any camera.
|
|
|
+ * {@link FrustumArray#setFromArrayCamera} must be called once per render before this method.
|
|
|
+ *
|
|
|
+ * @param {Object3D} object - The 3D object to test.
|
|
|
+ * @return {boolean} Whether the 3D object is visible in any camera.
|
|
|
*/
|
|
|
- intersectsSprite( sprite, cameraArray ) {
|
|
|
+ intersectsObject( object ) {
|
|
|
|
|
|
- if ( ! cameraArray || ! cameraArray.cameras || cameraArray.cameras.length === 0 ) {
|
|
|
+ const frustums = this._frustums;
|
|
|
|
|
|
- return false;
|
|
|
+ for ( let i = 0; i < this._count; i ++ ) {
|
|
|
|
|
|
- }
|
|
|
+ if ( frustums[ i ].intersectsObject( object ) ) return true;
|
|
|
|
|
|
- for ( let i = 0; i < cameraArray.cameras.length; i ++ ) {
|
|
|
+ }
|
|
|
|
|
|
- const camera = cameraArray.cameras[ i ];
|
|
|
+ return false;
|
|
|
|
|
|
- _projScreenMatrix.multiplyMatrices(
|
|
|
- camera.projectionMatrix,
|
|
|
- camera.matrixWorldInverse
|
|
|
- );
|
|
|
+ }
|
|
|
|
|
|
- _frustum.setFromProjectionMatrix(
|
|
|
- _projScreenMatrix,
|
|
|
- camera.coordinateSystem,
|
|
|
- camera.reversedDepth
|
|
|
- );
|
|
|
+ /**
|
|
|
+ * Returns `true` if the given sprite is intersecting any cached frustum.
|
|
|
+ *
|
|
|
+ * {@link FrustumArray#setFromArrayCamera} must be called once per render before this method.
|
|
|
+ *
|
|
|
+ * @param {Sprite} sprite - The sprite to test.
|
|
|
+ * @return {boolean} Whether the sprite is visible in any camera.
|
|
|
+ */
|
|
|
+ intersectsSprite( sprite ) {
|
|
|
|
|
|
- if ( _frustum.intersectsSprite( sprite ) ) {
|
|
|
+ const frustums = this._frustums;
|
|
|
|
|
|
- return true; // Sprite is visible in at least one camera
|
|
|
+ for ( let i = 0; i < this._count; i ++ ) {
|
|
|
|
|
|
- }
|
|
|
+ if ( frustums[ i ].intersectsSprite( sprite ) ) return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
- return false; // Not visible in any camera
|
|
|
+ return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Returns `true` if the given bounding sphere is intersecting any frustum
|
|
|
- * from the camera array.
|
|
|
+ * Returns `true` if the given bounding sphere is intersecting any cached frustum.
|
|
|
+ *
|
|
|
+ * {@link FrustumArray#setFromArrayCamera} must be called once per render before this method.
|
|
|
*
|
|
|
* @param {Sphere} sphere - The bounding sphere to test.
|
|
|
- * @param {Object} cameraArray - An object with a cameras property containing an array of cameras.
|
|
|
* @return {boolean} Whether the sphere is visible in any camera.
|
|
|
*/
|
|
|
- intersectsSphere( sphere, cameraArray ) {
|
|
|
-
|
|
|
- if ( ! cameraArray || ! cameraArray.cameras || cameraArray.cameras.length === 0 ) {
|
|
|
-
|
|
|
- return false;
|
|
|
-
|
|
|
- }
|
|
|
+ intersectsSphere( sphere ) {
|
|
|
|
|
|
- for ( let i = 0; i < cameraArray.cameras.length; i ++ ) {
|
|
|
+ const frustums = this._frustums;
|
|
|
|
|
|
- const camera = cameraArray.cameras[ i ];
|
|
|
+ for ( let i = 0; i < this._count; i ++ ) {
|
|
|
|
|
|
- _projScreenMatrix.multiplyMatrices(
|
|
|
- camera.projectionMatrix,
|
|
|
- camera.matrixWorldInverse
|
|
|
- );
|
|
|
-
|
|
|
- _frustum.setFromProjectionMatrix(
|
|
|
- _projScreenMatrix,
|
|
|
- camera.coordinateSystem,
|
|
|
- camera.reversedDepth
|
|
|
- );
|
|
|
-
|
|
|
- if ( _frustum.intersectsSphere( sphere ) ) {
|
|
|
-
|
|
|
- return true; // Sphere is visible in at least one camera
|
|
|
-
|
|
|
- }
|
|
|
+ if ( frustums[ i ].intersectsSphere( sphere ) ) return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
- return false; // Not visible in any camera
|
|
|
+ return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Returns `true` if the given bounding box is intersecting any frustum
|
|
|
- * from the camera array.
|
|
|
+ * Returns `true` if the given bounding box is intersecting any cached frustum.
|
|
|
+ *
|
|
|
+ * {@link FrustumArray#setFromArrayCamera} must be called once per render before this method.
|
|
|
*
|
|
|
* @param {Box3} box - The bounding box to test.
|
|
|
- * @param {Object} cameraArray - An object with a cameras property containing an array of cameras.
|
|
|
* @return {boolean} Whether the box is visible in any camera.
|
|
|
*/
|
|
|
- intersectsBox( box, cameraArray ) {
|
|
|
-
|
|
|
- if ( ! cameraArray || ! cameraArray.cameras || cameraArray.cameras.length === 0 ) {
|
|
|
-
|
|
|
- return false;
|
|
|
+ intersectsBox( box ) {
|
|
|
|
|
|
- }
|
|
|
-
|
|
|
- for ( let i = 0; i < cameraArray.cameras.length; i ++ ) {
|
|
|
-
|
|
|
- const camera = cameraArray.cameras[ i ];
|
|
|
-
|
|
|
- _projScreenMatrix.multiplyMatrices(
|
|
|
- camera.projectionMatrix,
|
|
|
- camera.matrixWorldInverse
|
|
|
- );
|
|
|
+ const frustums = this._frustums;
|
|
|
|
|
|
- _frustum.setFromProjectionMatrix(
|
|
|
- _projScreenMatrix,
|
|
|
- camera.coordinateSystem,
|
|
|
- camera.reversedDepth
|
|
|
- );
|
|
|
+ for ( let i = 0; i < this._count; i ++ ) {
|
|
|
|
|
|
- if ( _frustum.intersectsBox( box ) ) {
|
|
|
-
|
|
|
- return true; // Box is visible in at least one camera
|
|
|
-
|
|
|
- }
|
|
|
+ if ( frustums[ i ].intersectsBox( box ) ) return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
- return false; // Not visible in any camera
|
|
|
+ return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Returns `true` if the given point lies within any frustum
|
|
|
- * from the camera array.
|
|
|
+ * Returns `true` if the given point lies within any cached frustum.
|
|
|
+ *
|
|
|
+ * {@link FrustumArray#setFromArrayCamera} must be called once per render before this method.
|
|
|
*
|
|
|
* @param {Vector3} point - The point to test.
|
|
|
- * @param {Object} cameraArray - An object with a cameras property containing an array of cameras.
|
|
|
* @return {boolean} Whether the point is visible in any camera.
|
|
|
*/
|
|
|
- containsPoint( point, cameraArray ) {
|
|
|
+ containsPoint( point ) {
|
|
|
|
|
|
- if ( ! cameraArray || ! cameraArray.cameras || cameraArray.cameras.length === 0 ) {
|
|
|
+ const frustums = this._frustums;
|
|
|
|
|
|
- return false;
|
|
|
+ for ( let i = 0; i < this._count; i ++ ) {
|
|
|
+
|
|
|
+ if ( frustums[ i ].containsPoint( point ) ) return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
- for ( let i = 0; i < cameraArray.cameras.length; i ++ ) {
|
|
|
+ return false;
|
|
|
|
|
|
- const camera = cameraArray.cameras[ i ];
|
|
|
+ }
|
|
|
|
|
|
- _projScreenMatrix.multiplyMatrices(
|
|
|
- camera.projectionMatrix,
|
|
|
- camera.matrixWorldInverse
|
|
|
- );
|
|
|
+ /**
|
|
|
+ * Copies the values of the given frustum array to this instance.
|
|
|
+ *
|
|
|
+ * @param {FrustumArray} frustumArray - The frustum array to copy.
|
|
|
+ * @return {FrustumArray} A reference to this frustum array.
|
|
|
+ */
|
|
|
+ copy( source ) {
|
|
|
+
|
|
|
+ this.coordinateSystem = source.coordinateSystem;
|
|
|
|
|
|
- _frustum.setFromProjectionMatrix(
|
|
|
- _projScreenMatrix,
|
|
|
- camera.coordinateSystem,
|
|
|
- camera.reversedDepth
|
|
|
- );
|
|
|
+ const frustums = this._frustums;
|
|
|
+ const sourceFrustums = source._frustums;
|
|
|
|
|
|
- if ( _frustum.containsPoint( point ) ) {
|
|
|
+ for ( let i = 0; i < source._count; i ++ ) {
|
|
|
|
|
|
- return true; // Point is visible in at least one camera
|
|
|
+ if ( frustums[ i ] === undefined ) frustums[ i ] = new Frustum();
|
|
|
|
|
|
- }
|
|
|
+ frustums[ i ].copy( sourceFrustums[ i ] );
|
|
|
|
|
|
}
|
|
|
|
|
|
- return false; // Not visible in any camera
|
|
|
+ this._count = source._count;
|
|
|
+
|
|
|
+ return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -249,7 +219,7 @@ class FrustumArray {
|
|
|
*/
|
|
|
clone() {
|
|
|
|
|
|
- return new FrustumArray();
|
|
|
+ return new FrustumArray().copy( this );
|
|
|
|
|
|
}
|
|
|
|