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
21 changes: 20 additions & 1 deletion src/utils/ExtensionUtilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) {
Expand All @@ -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 );
Comment on lines -20 to +21
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh interesting... So the previous issue was caused by Object3D.getWorldScale implicitly updating the world matrix without having synchronized position, rotation, and scale values. Confusing.

Why don't we use Matrix4.decompose, instead, and pass a dummy position and rotation into the function? I think it will be simpler than copying logic and directly accessing matrix elements.

direction.copy( ray.direction ).multiply( worldScale );

const scaleFactor = direction.length();
Expand Down Expand Up @@ -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 );

}
65 changes: 53 additions & 12 deletions test/RandomRaycasts.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
MeshBasicMaterial,
InterleavedBuffer,
InterleavedBufferAttribute,
InstancedMesh,
Object3D
} from 'three';
import {
acceleratedRaycast,
Expand All @@ -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 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 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 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 } ) );
Expand Down Expand Up @@ -96,21 +101,38 @@ 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();
updateMatrix( instancedMesh );

scene.add( mesh );
mesh.updateMatrix( true );
mesh.updateMatrixWorld( true );
instancedMesh.updateMatrixWorld( true );

scene.add( instancedMesh );

const tempObj = new Object3D();

for ( var i = 0; i < 10; i ++ ) {

updateMatrix( tempObj );
instancedMesh.setMatrixAt( i, tempObj.matrix );

}

} else {

for ( var i = 0; i < 10; i ++ ) {

let geo = i % 2 ? groupedGeometry : ungroupedGeometry;
let mesh = new Mesh( geo, new MeshBasicMaterial() );

updateMatrix( mesh );
mesh.updateMatrixWorld( true );
scene.add( mesh );

}

}

Expand Down Expand Up @@ -169,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 );

}