From 10abe1979074ab8fbe02575be1ce7260f1fcdb48 Mon Sep 17 00:00:00 2001 From: ANDREA GARGARO Date: Tue, 11 Jun 2024 23:11:22 +0200 Subject: [PATCH 1/3] Fix instancedMesh raycast --- src/utils/ExtensionUtilities.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/utils/ExtensionUtilities.js b/src/utils/ExtensionUtilities.js index 90ae28c4d..86784b151 100644 --- a/src/utils/ExtensionUtilities.js +++ b/src/utils/ExtensionUtilities.js @@ -6,6 +6,7 @@ const ray = /* @__PURE__ */ new Ray(); const direction = /* @__PURE__ */ new Vector3(); const tmpInverseMatrix = /* @__PURE__ */ new Matrix4(); const worldScale = /* @__PURE__ */ new Vector3(); +const tmpVec3 = /* @__PURE__ */ new Vector3(); const origMeshRaycastFunc = Mesh.prototype.raycast; export function acceleratedRaycast( raycaster, intersects ) { @@ -17,7 +18,7 @@ export function acceleratedRaycast( raycaster, intersects ) { tmpInverseMatrix.copy( this.matrixWorld ).invert(); ray.copy( raycaster.ray ).applyMatrix4( tmpInverseMatrix ); - this.getWorldScale( worldScale ); + getWorldScale( this.matrixWorld, worldScale ); direction.copy( ray.direction ).multiply( worldScale ); const scaleFactor = direction.length(); @@ -70,3 +71,21 @@ export function disposeBoundsTree() { this.boundsTree = null; } + +/** https://github.com/mrdoob/three.js/blob/dev/src/math/Matrix4.js#L732 */ +function getWorldScale( matrixWorld, target ) { + + const te = matrixWorld.elements; + + const sx = tmpVec3.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); + const sy = tmpVec3.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); + const sz = tmpVec3.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); + + // // if determine is negative, we need to invert one scale + // const det = matrixWorld.determinant(); + // if ( det < 0 ) sx = - sx; + // we don't need this. + + target.set( sx, sy, sz ); + +} From 3d1d76419781d3736d8d6f7054c5a2a1703e2a41 Mon Sep 17 00:00:00 2001 From: ANDREA GARGARO Date: Tue, 11 Jun 2024 23:11:42 +0200 Subject: [PATCH 2/3] Added InstancedMesh test --- test/RandomRaycasts.test.js | 80 +++++++++++++++++++++++++++++++------ 1 file changed, 68 insertions(+), 12 deletions(-) diff --git a/test/RandomRaycasts.test.js b/test/RandomRaycasts.test.js index e20087233..4b2b455ff 100644 --- a/test/RandomRaycasts.test.js +++ b/test/RandomRaycasts.test.js @@ -7,6 +7,8 @@ import { MeshBasicMaterial, InterleavedBuffer, InterleavedBufferAttribute, + InstancedMesh, + Object3D } from 'three'; import { acceleratedRaycast, @@ -25,14 +27,17 @@ BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree; describe( 'Random CENTER intersections', () => runRandomTests( { strategy: CENTER } ) ); describe( 'Random Interleaved CENTER intersections', () => runRandomTests( { strategy: CENTER, interleaved: true } ) ); describe( 'Random Indirect Buffer CENTER intersections', () => runRandomTests( { strategy: CENTER, indirect: true } ) ); +describe( 'Random Instanced Buffer CENTER intersections', () => runRandomTests( { strategy: CENTER, instanced: true } ) ); describe( 'Random AVERAGE intersections', () => runRandomTests( { strategy: AVERAGE } ) ); describe( 'Random Interleaved AVERAGE intersections', () => runRandomTests( { strategy: AVERAGE, interleaved: true } ) ); describe( 'Random Indirect Buffer AVERAGE intersections', () => runRandomTests( { strategy: AVERAGE, indirect: true } ) ); +describe( 'Random Instanced Buffer AVERAGE intersections', () => runRandomTests( { strategy: AVERAGE, instanced: true } ) ); describe( 'Random SAH intersections', () => runRandomTests( { strategy: SAH } ) ); describe( 'Random Interleaved SAH intersections', () => runRandomTests( { strategy: SAH, interleaved: true } ) ); describe( 'Random Indirect Buffer SAH intersections', () => runRandomTests( { strategy: SAH, indirect: true } ) ); +describe( 'Random Instanced Buffer SAH intersections', () => runRandomTests( { strategy: SAH, instanced: true } ) ); describe( 'Random CENTER intersections with near', () => runRandomTests( { strategy: CENTER, near: 6 } ) ); describe( 'Random CENTER intersections with far', () => runRandomTests( { strategy: CENTER, far: 7 } ) ); @@ -96,21 +101,72 @@ function runRandomTests( options ) { setSeed( transformSeed ); random(); // call random() to seed with a larger value - for ( var i = 0; i < 10; i ++ ) { + if ( options.instanced ) { - let geo = i % 2 ? groupedGeometry : ungroupedGeometry; - let mesh = new Mesh( geo, new MeshBasicMaterial() ); - mesh.rotation.x = random() * 10; - mesh.rotation.y = random() * 10; - mesh.rotation.z = random() * 10; + const geo = groupedGeometry; // ungroupedGeometry not used... + const instancedMesh = new InstancedMesh( geo, new MeshBasicMaterial(), 10 ); - mesh.position.x = random(); - mesh.position.y = random(); - mesh.position.z = random(); + instancedMesh.rotation.x = random() * 10; + instancedMesh.rotation.y = random() * 10; + instancedMesh.rotation.z = random() * 10; - scene.add( mesh ); - mesh.updateMatrix( true ); - mesh.updateMatrixWorld( true ); + instancedMesh.position.x = random(); + instancedMesh.position.y = random(); + instancedMesh.position.z = random(); + + instancedMesh.scale.x = random() * 2 - 1; + instancedMesh.scale.y = random() * 2 - 1; + instancedMesh.scale.z = random() * 2 - 1; + + instancedMesh.updateMatrix( true ); + instancedMesh.updateMatrixWorld( true ); + + scene.add( instancedMesh ); + + const tempMesh = new Object3D(); + + for ( var i = 0; i < 10; i ++ ) { + + tempMesh.rotation.x = random() * 10; + tempMesh.rotation.y = random() * 10; + tempMesh.rotation.z = random() * 10; + + tempMesh.position.x = random(); + tempMesh.position.y = random(); + tempMesh.position.z = random(); + + tempMesh.scale.x = random() * 2 - 1; + tempMesh.scale.y = random() * 2 - 1; + tempMesh.scale.z = random() * 2 - 1; + + tempMesh.updateMatrix( true ); + instancedMesh.setMatrixAt( i, tempMesh.matrix ); + + } + + } else { + + for ( var i = 0; i < 10; i ++ ) { + + let geo = i % 2 ? groupedGeometry : ungroupedGeometry; + let mesh = new Mesh( geo, new MeshBasicMaterial() ); + mesh.rotation.x = random() * 10; + mesh.rotation.y = random() * 10; + mesh.rotation.z = random() * 10; + + mesh.position.x = random(); + mesh.position.y = random(); + mesh.position.z = random(); + + mesh.scale.x = random() * 2 - 1; + mesh.scale.y = random() * 2 - 1; + mesh.scale.z = random() * 2 - 1; + + scene.add( mesh ); + mesh.updateMatrix( true ); + mesh.updateMatrixWorld( true ); + + } } From 55bc6fabc27fe2603f8de5f74ebc8e0e8bfc7917 Mon Sep 17 00:00:00 2001 From: ANDREA GARGARO Date: Wed, 12 Jun 2024 18:48:02 +0200 Subject: [PATCH 3/3] Cleaning --- test/RandomRaycasts.test.js | 71 +++++++++++++++---------------------- 1 file changed, 28 insertions(+), 43 deletions(-) diff --git a/test/RandomRaycasts.test.js b/test/RandomRaycasts.test.js index 4b2b455ff..8edf264d5 100644 --- a/test/RandomRaycasts.test.js +++ b/test/RandomRaycasts.test.js @@ -27,17 +27,17 @@ BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree; describe( 'Random CENTER intersections', () => runRandomTests( { strategy: CENTER } ) ); describe( 'Random Interleaved CENTER intersections', () => runRandomTests( { strategy: CENTER, interleaved: true } ) ); describe( 'Random Indirect Buffer CENTER intersections', () => runRandomTests( { strategy: CENTER, indirect: true } ) ); -describe( 'Random Instanced Buffer CENTER intersections', () => runRandomTests( { strategy: CENTER, instanced: true } ) ); +describe( 'Random Instanced CENTER intersections', () => runRandomTests( { strategy: CENTER, instanced: true } ) ); describe( 'Random AVERAGE intersections', () => runRandomTests( { strategy: AVERAGE } ) ); describe( 'Random Interleaved AVERAGE intersections', () => runRandomTests( { strategy: AVERAGE, interleaved: true } ) ); describe( 'Random Indirect Buffer AVERAGE intersections', () => runRandomTests( { strategy: AVERAGE, indirect: true } ) ); -describe( 'Random Instanced Buffer AVERAGE intersections', () => runRandomTests( { strategy: AVERAGE, instanced: true } ) ); +describe( 'Random Instanced AVERAGE intersections', () => runRandomTests( { strategy: AVERAGE, instanced: true } ) ); describe( 'Random SAH intersections', () => runRandomTests( { strategy: SAH } ) ); describe( 'Random Interleaved SAH intersections', () => runRandomTests( { strategy: SAH, interleaved: true } ) ); describe( 'Random Indirect Buffer SAH intersections', () => runRandomTests( { strategy: SAH, indirect: true } ) ); -describe( 'Random Instanced Buffer SAH intersections', () => runRandomTests( { strategy: SAH, instanced: true } ) ); +describe( 'Random Instanced SAH intersections', () => runRandomTests( { strategy: SAH, instanced: true } ) ); describe( 'Random CENTER intersections with near', () => runRandomTests( { strategy: CENTER, near: 6 } ) ); describe( 'Random CENTER intersections with far', () => runRandomTests( { strategy: CENTER, far: 7 } ) ); @@ -106,41 +106,18 @@ function runRandomTests( options ) { const geo = groupedGeometry; // ungroupedGeometry not used... const instancedMesh = new InstancedMesh( geo, new MeshBasicMaterial(), 10 ); - instancedMesh.rotation.x = random() * 10; - instancedMesh.rotation.y = random() * 10; - instancedMesh.rotation.z = random() * 10; + updateMatrix( instancedMesh ); - instancedMesh.position.x = random(); - instancedMesh.position.y = random(); - instancedMesh.position.z = random(); - - instancedMesh.scale.x = random() * 2 - 1; - instancedMesh.scale.y = random() * 2 - 1; - instancedMesh.scale.z = random() * 2 - 1; - - instancedMesh.updateMatrix( true ); instancedMesh.updateMatrixWorld( true ); scene.add( instancedMesh ); - const tempMesh = new Object3D(); + const tempObj = new Object3D(); for ( var i = 0; i < 10; i ++ ) { - tempMesh.rotation.x = random() * 10; - tempMesh.rotation.y = random() * 10; - tempMesh.rotation.z = random() * 10; - - tempMesh.position.x = random(); - tempMesh.position.y = random(); - tempMesh.position.z = random(); - - tempMesh.scale.x = random() * 2 - 1; - tempMesh.scale.y = random() * 2 - 1; - tempMesh.scale.z = random() * 2 - 1; - - tempMesh.updateMatrix( true ); - instancedMesh.setMatrixAt( i, tempMesh.matrix ); + updateMatrix( tempObj ); + instancedMesh.setMatrixAt( i, tempObj.matrix ); } @@ -150,21 +127,10 @@ function runRandomTests( options ) { let geo = i % 2 ? groupedGeometry : ungroupedGeometry; let mesh = new Mesh( geo, new MeshBasicMaterial() ); - mesh.rotation.x = random() * 10; - mesh.rotation.y = random() * 10; - mesh.rotation.z = random() * 10; - mesh.position.x = random(); - mesh.position.y = random(); - mesh.position.z = random(); - - mesh.scale.x = random() * 2 - 1; - mesh.scale.y = random() * 2 - 1; - mesh.scale.z = random() * 2 - 1; - - scene.add( mesh ); - mesh.updateMatrix( true ); + updateMatrix( mesh ); mesh.updateMatrixWorld( true ); + scene.add( mesh ); } @@ -225,3 +191,22 @@ function createInterleavedPositionBuffer( bufferAttribute ) { return newBuffer; } + + +function updateMatrix( target ) { + + target.rotation.x = random() * 10; + target.rotation.y = random() * 10; + target.rotation.z = random() * 10; + + target.position.x = random(); + target.position.y = random(); + target.position.z = random(); + + target.scale.x = random() * 2 - 1; + target.scale.y = random() * 2 - 1; + target.scale.z = random() * 2 - 1; + + target.updateMatrix( true ); + +}