Skip to content
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
236 changes: 103 additions & 133 deletions src/math/FrustumArray.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;

}

Expand All @@ -249,7 +219,7 @@ class FrustumArray {
*/
clone() {

return new FrustumArray();
return new FrustumArray().copy( this );

}

Expand Down
15 changes: 9 additions & 6 deletions src/math/Matrix4.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@
*/
extractBasis( xAxis, yAxis, zAxis ) {

if ( this.determinant3x3() === 0 ) {
if ( this.determinantAffine() === 0 ) {

xAxis.set( 1, 0, 0 );
yAxis.set( 0, 1, 0 );
Expand Down Expand Up @@ -288,7 +288,7 @@
*/
extractRotation( m ) {

if ( m.determinant3x3() === 0 ) {
if ( m.determinantAffine() === 0 ) {

return this.identity();

Expand Down Expand Up @@ -650,14 +650,17 @@
}

/**
* Computes and returns the determinant of the upper-left 3x3 submatrix.
* Computes and returns the determinant of the 4x4 matrix, but assumes the
* matrix is affine, saving some computations.
*
* For affine matrices (like an object's world matrix), this value equals the
* full 4x4 {@link Matrix4#determinant} but is cheaper to compute.
*

Check failure on line 658 in src/math/Matrix4.js

View workflow job for this annotation

GitHub Actions / Lint, Unit, Unit addons, Circular dependencies & Examples testing

Trailing spaces not allowed
* Assumes the bottom row is [0, 0, 0, 1].
*
* @return {number} The determinant of the upper-left 3x3 submatrix.
* @return {number} The determinant of the matrix.
*/
determinant3x3() {
determinantAffine() {

const te = this.elements;

Expand Down Expand Up @@ -1080,7 +1083,7 @@
position.y = te[ 13 ];
position.z = te[ 14 ];

const det = this.determinant3x3();
const det = this.determinantAffine();

if ( det === 0 ) {

Expand Down
Loading
Loading