diff --git a/src/cameras/ArrayCamera.js b/src/cameras/ArrayCamera.js index d2621ef8358bc2..ced6075dd7824a 100644 --- a/src/cameras/ArrayCamera.js +++ b/src/cameras/ArrayCamera.js @@ -40,6 +40,15 @@ class ArrayCamera extends PerspectiveCamera { */ this.isMultiViewCamera = false; + /** + * Whether to perform view-frustum culling during rendering + * on a per-camera basis, or to use the `ArrayCamera`'s own projection matrix. + * + * @type {boolean} + * @default true + */ + this.perCameraCulling = true; + /** * An array of perspective sub cameras. * diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index 8bdfba89d6359c..eb0b5c332e2526 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -21,6 +21,7 @@ import { } from '../constants.js'; import { Color } from '../math/Color.js'; import { Frustum } from '../math/Frustum.js'; +import { FrustumArray } from '../math/FrustumArray.js'; import { Matrix4 } from '../math/Matrix4.js'; import { Vector3 } from '../math/Vector3.js'; import { Vector4 } from '../math/Vector4.js'; @@ -305,6 +306,7 @@ class WebGLRenderer { // frustum const _frustum = new Frustum(); + const _frustumArray = new FrustumArray(); // clipping @@ -1555,8 +1557,12 @@ class WebGLRenderer { renderStateStack.push( currentRenderState ); - _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - _frustum.setFromProjectionMatrix( _projScreenMatrix, WebGLCoordinateSystem, camera.reversedDepth ); + if ( ! camera.perCameraCulling ) { + + _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + _frustum.setFromProjectionMatrix( _projScreenMatrix, WebGLCoordinateSystem, camera.reversedDepth ); + + } _localClippingEnabled = this.localClippingEnabled; _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled ); @@ -1734,7 +1740,9 @@ class WebGLRenderer { } else if ( object.isSprite ) { - if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) { + const frustum = camera.perCameraCulling ? _frustumArray : _frustum; + + if ( ! object.frustumCulled || frustum.intersectsSprite( object, camera ) ) { if ( sortObjects ) { @@ -1756,7 +1764,9 @@ class WebGLRenderer { } else if ( object.isMesh || object.isLine || object.isPoints ) { - if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { + const frustum = camera.perCameraCulling ? _frustumArray : _frustum; + + if ( ! object.frustumCulled || frustum.intersectsObject( object, camera ) ) { const geometry = objects.update( object ); const material = object.material; diff --git a/src/renderers/common/Renderer.js b/src/renderers/common/Renderer.js index 715c19f50d5326..be0bed23cae95f 100644 --- a/src/renderers/common/Renderer.js +++ b/src/renderers/common/Renderer.js @@ -1408,12 +1408,10 @@ class Renderer { // - const frustum = camera.isArrayCamera ? _frustumArray : _frustum; - - if ( ! camera.isArrayCamera ) { + if ( ! camera.perCameraCulling ) { _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - frustum.setFromProjectionMatrix( _projScreenMatrix, camera.coordinateSystem, camera.reversedDepth ); + _frustum.setFromProjectionMatrix( _projScreenMatrix, camera.coordinateSystem, camera.reversedDepth ); } @@ -2645,7 +2643,7 @@ class Renderer { } else if ( object.isSprite ) { - const frustum = camera.isArrayCamera ? _frustumArray : _frustum; + const frustum = camera.perCameraCulling ? _frustumArray : _frustum; if ( ! object.frustumCulled || frustum.intersectsSprite( object, camera ) ) { @@ -2671,7 +2669,7 @@ class Renderer { } else if ( object.isMesh || object.isLine || object.isPoints ) { - const frustum = camera.isArrayCamera ? _frustumArray : _frustum; + const frustum = camera.perCameraCulling ? _frustumArray : _frustum; if ( ! object.frustumCulled || frustum.intersectsObject( object, camera ) ) { diff --git a/src/renderers/common/XRManager.js b/src/renderers/common/XRManager.js index c4d52dc76b78fb..89c471bd177d92 100644 --- a/src/renderers/common/XRManager.js +++ b/src/renderers/common/XRManager.js @@ -1152,7 +1152,7 @@ class XRManager extends EventDispatcher { } else { - // assume single camera setup (AR) + // view frustum culling will be performed per camera, but assign this anyway cameraXR.projectionMatrix.copy( cameraL.projectionMatrix ); @@ -1575,6 +1575,7 @@ function onAnimationFrame( time, frame ) { cameraXR.cameras.length = 0; cameraXRNeedsUpdate = true; + cameraXR.perCameraCulling = views.length !== 2; } diff --git a/src/renderers/webxr/WebXRManager.js b/src/renderers/webxr/WebXRManager.js index 6da45978e9995e..c01db9b86f942f 100644 --- a/src/renderers/webxr/WebXRManager.js +++ b/src/renderers/webxr/WebXRManager.js @@ -770,7 +770,7 @@ class WebXRManager extends EventDispatcher { } else { - // assume single camera setup (AR) + // view frustum culling will be performed per camera, but assign this anyway cameraXR.projectionMatrix.copy( cameraL.projectionMatrix ); @@ -936,6 +936,7 @@ class WebXRManager extends EventDispatcher { cameraXR.cameras.length = 0; cameraXRNeedsUpdate = true; + cameraXR.perCameraCulling = views.length !== 2; }