diff --git a/examples/jsm/renderers/Projector.js b/examples/jsm/renderers/Projector.js index f80df799d42e66..a437117b4bda2a 100644 --- a/examples/jsm/renderers/Projector.js +++ b/examples/jsm/renderers/Projector.js @@ -365,7 +365,7 @@ class Projector { } else if ( object.isMesh || object.isLine || object.isPoints ) { if ( object.material.visible === false ) return; - if ( object.frustumCulled === true && _frustum.intersectsObject( object ) === false ) return; + if ( object.frustumCulled === true && object.intersectsFrustum( _frustum ) === false ) return; addObject( object ); diff --git a/examples/jsm/renderers/webgpu/WebGPURenderer.js b/examples/jsm/renderers/webgpu/WebGPURenderer.js index ff9b6e24968abf..ded6f4eb769417 100644 --- a/examples/jsm/renderers/webgpu/WebGPURenderer.js +++ b/examples/jsm/renderers/webgpu/WebGPURenderer.js @@ -727,7 +727,7 @@ class WebGPURenderer { } else if ( object.isMesh || object.isLine || object.isPoints ) { - if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { + if ( ! object.frustumCulled || object.intersectsFrustum( _frustum ) ) { if ( this.sortObjects === true ) { diff --git a/src/Three.js b/src/Three.js index 929845050689b7..5a1608c354332e 100644 --- a/src/Three.js +++ b/src/Three.js @@ -21,6 +21,7 @@ export { Skeleton } from './objects/Skeleton.js'; export { Bone } from './objects/Bone.js'; export { Mesh } from './objects/Mesh.js'; export { InstancedMesh } from './objects/InstancedMesh.js'; +export { InstancedMeshCulled } from './objects/InstancedMeshCulled.js'; export { LineSegments } from './objects/LineSegments.js'; export { LineLoop } from './objects/LineLoop.js'; export { Line } from './objects/Line.js'; diff --git a/src/core/Object3D.js b/src/core/Object3D.js index 37c0cc2d9e9be8..8138e877cbf115 100644 --- a/src/core/Object3D.js +++ b/src/core/Object3D.js @@ -532,6 +532,12 @@ class Object3D extends EventDispatcher { raycast( /* raycaster, intersects */ ) {} + intersectsFrustum( frustum ) { + + return frustum.intersectsObject( this ); + + } + traverse( callback ) { callback( this ); diff --git a/src/objects/InstancedMeshCulled.js b/src/objects/InstancedMeshCulled.js new file mode 100644 index 00000000000000..bbd10cd17a5c2a --- /dev/null +++ b/src/objects/InstancedMeshCulled.js @@ -0,0 +1,64 @@ +import { InstancedMesh } from './InstancedMesh.js'; +import { Sphere } from '../math/Sphere.js'; +import { Vector3 } from '../math/Vector3.js'; + + +class InstancedMeshCulled extends InstancedMesh { + + constructor( geometry, material, count ) { + + super( geometry, material, count ); + + this.frustumCulled = true; + this.boundingSphere = null; + + } + + computeBoundingSphere() { + + if ( this.geometry.boundingSphere === null ) this.geometry.computeBoundingSphere(); + + const min = new Vector3( Infinity, Infinity, Infinity ); + const max = new Vector3( - Infinity, - Infinity, - Infinity ); + const position = new Vector3(); + + for ( let m = 0; m < this.count; m ++ ) { + + const x = this.instanceMatrix[ m * 16 + 12 ]; + const y = this.instanceMatrix[ m * 16 + 13 ]; + const z = this.instanceMatrix[ m * 16 + 14 ]; + position.set( x, y, z ); + min.min( position ); + max.max( position ); + + } + + let radius = 0; + const center = new Vector3().addVectors( min, max ).multiply( 0.5 ); + for ( let m = 0; m < this.count; m ++ ) { + + const x = this.instanceMatrix[ m * 16 + 12 ]; + const y = this.instanceMatrix[ m * 16 + 13 ]; + const z = this.instanceMatrix[ m * 16 + 14 ]; + position.set( x, y, z ); + const distance = position.distanceTo( center ); + // note: we assume no scaling - computing scale from instance matrix is not trivial + const r = distance + this.geometry.boundingSphere.radius; + if ( r > radius ) radius = r; + + } + + this.boundingSphere = new Sphere( center, radius ); + + } + + intersectsFrustum( frustum ) { + + if ( this.boundingSphere === null ) this.computeBoundingSphere(); + frustum.intersectsSphere( this.boundingSphere ); + + } + +} + +export { InstancedMeshCulled }; diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index db020bbe8f3928..7fc2b606700af7 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -1149,7 +1149,7 @@ function WebGLRenderer( parameters = {} ) { } - if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { + if ( ! object.frustumCulled || object.intersectsFrustum( _frustum ) ) { if ( sortObjects ) { diff --git a/src/renderers/webgl/WebGLShadowMap.js b/src/renderers/webgl/WebGLShadowMap.js index 93fd4fe9f671c4..f41bfcbc1ec9ce 100644 --- a/src/renderers/webgl/WebGLShadowMap.js +++ b/src/renderers/webgl/WebGLShadowMap.js @@ -322,7 +322,7 @@ function WebGLShadowMap( _renderer, _objects, _capabilities ) { if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) { - if ( ( object.castShadow || ( object.receiveShadow && type === VSMShadowMap ) ) && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) { + if ( ( object.castShadow || ( object.receiveShadow && type === VSMShadowMap ) ) && ( ! object.frustumCulled || object.intersectsFrustum( _frustum ) ) ) { object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );