From e828fd0f543be948fba3e6f520acd2f2d9422489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0pan=C4=9Bl?= Date: Fri, 17 Feb 2023 15:07:40 +0100 Subject: [PATCH 1/2] Introduce intersectsFrustum so that objects can override it --- examples/jsm/renderers/Projector.js | 2 +- examples/jsm/renderers/webgpu/WebGPURenderer.js | 2 +- src/core/Object3D.js | 6 ++++++ src/renderers/WebGLRenderer.js | 2 +- src/renderers/webgl/WebGLShadowMap.js | 2 +- 5 files changed, 10 insertions(+), 4 deletions(-) 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/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/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 ); From b74058f2a22288ec9052f85619dc28c29bce3bfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C5=A0pan=C4=9Bl?= Date: Fri, 17 Feb 2023 16:10:29 +0100 Subject: [PATCH 2/2] Add InstancedMeshCulled implementation --- src/Three.js | 1 + src/objects/InstancedMeshCulled.js | 64 ++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 src/objects/InstancedMeshCulled.js 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/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 };