diff --git a/src/core/Raycaster.js b/src/core/Raycaster.js index f44a3a4479e7f8..0e6d3388662a66 100644 --- a/src/core/Raycaster.js +++ b/src/core/Raycaster.js @@ -2,6 +2,7 @@ import { Matrix4 } from '../math/Matrix4.js'; import { Ray } from '../math/Ray.js'; import { Layers } from './Layers.js'; import { error } from '../utils.js'; +import { WebGPUCoordinateSystem } from '../constants.js'; const _matrix = /*@__PURE__*/ new Matrix4(); @@ -126,7 +127,23 @@ class Raycaster { } else if ( camera.isOrthographicCamera ) { - this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera + let coordsZ; + + if ( camera.reversedDepth ) { + + coordsZ = camera.far / ( camera.far - camera.near ); + + } else if ( camera.coordinateSystem === WebGPUCoordinateSystem ) { + + coordsZ = camera.near / ( camera.near - camera.far ); + + } else { + + coordsZ = ( camera.near + camera.far ) / ( camera.near - camera.far ); + + } + + this.ray.origin.set( coords.x, coords.y, coordsZ ).unproject( camera ); // set origin in plane of camera this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); this.camera = camera; diff --git a/test/unit/src/core/Raycaster.tests.js b/test/unit/src/core/Raycaster.tests.js index 072073462434e4..098cb7b25db674 100644 --- a/test/unit/src/core/Raycaster.tests.js +++ b/test/unit/src/core/Raycaster.tests.js @@ -7,6 +7,7 @@ import { Line } from '../../../../src/objects/Line.js'; import { Points } from '../../../../src/objects/Points.js'; import { PerspectiveCamera } from '../../../../src/cameras/PerspectiveCamera.js'; import { OrthographicCamera } from '../../../../src/cameras/OrthographicCamera.js'; +import { WebGPUCoordinateSystem } from '../../../../src/constants.js'; function checkRayDirectionAgainstReferenceVector( rayDirection, refVector, assert ) { @@ -190,6 +191,106 @@ export default QUnit.module( 'Core', () => { } ); + QUnit.test( 'intersectObject (Perspective, WebGPU coordinate system)', ( assert ) => { + + const camera = new PerspectiveCamera( 90, 1, 0.1, 100 ); + camera.coordinateSystem = WebGPUCoordinateSystem; + camera.updateProjectionMatrix(); + + const front = getSphere(); + front.position.set( 0, 0, - 5 ); + front.updateMatrixWorld(); + + const behind = getSphere(); + behind.position.set( 0, 0, 5 ); + behind.updateMatrixWorld(); + + const raycaster = new Raycaster(); + raycaster.setFromCamera( { x: 0, y: 0 }, camera ); + + assert.strictEqual( raycaster.intersectObject( front ).length, 1, + 'Sphere in front of the perspective camera is intersected under WebGPU coordinate system.' ); + + assert.strictEqual( raycaster.intersectObject( behind ).length, 0, + 'Sphere behind the perspective camera is not intersected under WebGPU coordinate system.' ); + + } ); + + QUnit.test( 'intersectObject (Orthographic, WebGPU coordinate system)', ( assert ) => { + + const camera = new OrthographicCamera( - 1, 1, 1, - 1, 0.1, 10 ); + camera.coordinateSystem = WebGPUCoordinateSystem; + camera.updateProjectionMatrix(); + + const front = getSphere(); + front.position.set( 0, 0, - 5 ); + front.updateMatrixWorld(); + + const behind = getSphere(); + behind.position.set( 0, 0, 5 ); + behind.updateMatrixWorld(); + + const raycaster = new Raycaster(); + raycaster.setFromCamera( { x: 0, y: 0 }, camera ); + + assert.strictEqual( raycaster.intersectObject( front ).length, 1, + 'Sphere in front of the orthographic camera is intersected under WebGPU coordinate system.' ); + + assert.strictEqual( raycaster.intersectObject( behind ).length, 0, + 'Sphere behind the orthographic camera is not intersected under WebGPU coordinate system.' ); + + } ); + + QUnit.test( 'intersectObject (Perspective, reversed depth)', ( assert ) => { + + const camera = new PerspectiveCamera( 90, 1, 0.1, 100 ); + camera._reversedDepth = true; + camera.updateProjectionMatrix(); + + const front = getSphere(); + front.position.set( 0, 0, - 5 ); + front.updateMatrixWorld(); + + const behind = getSphere(); + behind.position.set( 0, 0, 5 ); + behind.updateMatrixWorld(); + + const raycaster = new Raycaster(); + raycaster.setFromCamera( { x: 0, y: 0 }, camera ); + + assert.strictEqual( raycaster.intersectObject( front ).length, 1, + 'Sphere in front of the perspective camera is intersected with reversed depth.' ); + + assert.strictEqual( raycaster.intersectObject( behind ).length, 0, + 'Sphere behind the perspective camera is not intersected with reversed depth.' ); + + } ); + + QUnit.test( 'intersectObject (Orthographic, reversed depth)', ( assert ) => { + + const camera = new OrthographicCamera( - 1, 1, 1, - 1, 0.1, 10 ); + camera._reversedDepth = true; + camera.updateProjectionMatrix(); + + const front = getSphere(); + front.position.set( 0, 0, - 5 ); + front.updateMatrixWorld(); + + const behind = getSphere(); + behind.position.set( 0, 0, 5 ); + behind.updateMatrixWorld(); + + const raycaster = new Raycaster(); + raycaster.setFromCamera( { x: 0, y: 0 }, camera ); + + assert.strictEqual( raycaster.intersectObject( front ).length, 1, + 'Sphere in front of the orthographic camera is intersected with reversed depth.' ); + + assert.strictEqual( raycaster.intersectObject( behind ).length, 0, + 'Sphere behind the orthographic camera is not intersected with reversed depth.' ); + + } ); + QUnit.test( 'Line intersection threshold', ( assert ) => { const raycaster = getRaycaster();