未验证 提交 efef2b3f 编写于 作者: G Garrett Johnson 提交者: GitHub

LineSegments2: Check bounding box and bounding sphere when raycasting (#21496)

* account for bounding box and sphere in Line2 raycast

* improve thick line raycast performance

* improve comment

* fix distance computation, adjust box margin application
上级 9eeefa69
......@@ -60,6 +60,10 @@ THREE.LineSegments2.prototype = Object.assign( Object.create( THREE.Mesh.prototy
var line = new THREE.Line3();
var closestPoint = new THREE.Vector3();
var box = new THREE.Box3();
var sphere = new THREE.Sphere();
var clipToWorldVector = new THREE.Vector4();
return function raycast( raycaster, intersects ) {
if ( raycaster.camera === null ) {
......@@ -74,6 +78,7 @@ THREE.LineSegments2.prototype = Object.assign( Object.create( THREE.Mesh.prototy
var camera = raycaster.camera;
var projectionMatrix = camera.projectionMatrix;
var matrixWorld = this.matrixWorld;
var geometry = this.geometry;
var material = this.material;
var resolution = material.resolution;
......@@ -85,6 +90,71 @@ THREE.LineSegments2.prototype = Object.assign( Object.create( THREE.Mesh.prototy
// camera forward is negative
var near = - camera.near;
// clip space is [ - 1, 1 ] so multiply by two to get the full
// width in clip space
var ssMaxWidth = 2.0 * Math.max( lineWidth / resolution.width, lineWidth / resolution.height );
//
// check if we intersect the sphere bounds
if ( geometry.boundingSphere === null ) {
geometry.computeBoundingSphere();
}
sphere.copy( geometry.boundingSphere ).applyMatrix4( matrixWorld );
var distanceToSphere = Math.max( camera.near, sphere.distanceToPoint( ray.origin ) );
// get the w component to scale the world space line width
clipToWorldVector.set( 0, 0, - distanceToSphere, 1.0 ).applyMatrix4( camera.projectionMatrix );
clipToWorldVector.multiplyScalar( 1.0 / clipToWorldVector.w );
clipToWorldVector.applyMatrix4( camera.projectionMatrixInverse );
// increase the sphere bounds by the worst case line screen space width
var sphereMargin = Math.abs( ssMaxWidth / clipToWorldVector.w ) * 0.5;
sphere.radius += sphereMargin;
if ( raycaster.ray.intersectsSphere( sphere ) === false ) {
return;
}
//
// check if we intersect the box bounds
if ( geometry.boundingBox === null ) {
geometry.computeBoundingBox();
}
box.copy( geometry.boundingBox ).applyMatrix4( matrixWorld );
var distanceToBox = Math.max( camera.near, box.distanceToPoint( ray.origin ) );
// get the w component to scale the world space line width
clipToWorldVector.set( 0, 0, - distanceToBox, 1.0 ).applyMatrix4( camera.projectionMatrix );
clipToWorldVector.multiplyScalar( 1.0 / clipToWorldVector.w );
clipToWorldVector.applyMatrix4( camera.projectionMatrixInverse );
// increase the sphere bounds by the worst case line screen space width
var boxMargin = Math.abs( ssMaxWidth / clipToWorldVector.w ) * 0.5;
box.max.x += boxMargin;
box.max.y += boxMargin;
box.max.z += boxMargin;
box.min.x -= boxMargin;
box.min.y -= boxMargin;
box.min.z -= boxMargin;
if ( raycaster.ray.intersectsBox( box ) === false ) {
return;
}
//
// pick a point 1 unit out along the ray to avoid the ray origin
// sitting at the camera origin which will cause "w" to be 0 when
// applying the projection matrix.
......@@ -103,7 +173,6 @@ THREE.LineSegments2.prototype = Object.assign( Object.create( THREE.Mesh.prototy
ssOrigin3.copy( ssOrigin );
var matrixWorld = this.matrixWorld;
mvMatrix.multiplyMatrices( camera.matrixWorldInverse, matrixWorld );
for ( var i = 0, l = instanceStart.count; i < l; i ++ ) {
......
import {
Box3,
InstancedInterleavedBuffer,
InterleavedBufferAttribute,
Line3,
MathUtils,
Matrix4,
Mesh,
Sphere,
Vector3,
Vector4
} from '../../../build/three.module.js';
......@@ -73,6 +75,10 @@ LineSegments2.prototype = Object.assign( Object.create( Mesh.prototype ), {
var line = new Line3();
var closestPoint = new Vector3();
var box = new Box3();
var sphere = new Sphere();
var clipToWorldVector = new Vector4();
return function raycast( raycaster, intersects ) {
if ( raycaster.camera === null ) {
......@@ -87,6 +93,7 @@ LineSegments2.prototype = Object.assign( Object.create( Mesh.prototype ), {
var camera = raycaster.camera;
var projectionMatrix = camera.projectionMatrix;
var matrixWorld = this.matrixWorld;
var geometry = this.geometry;
var material = this.material;
var resolution = material.resolution;
......@@ -98,6 +105,71 @@ LineSegments2.prototype = Object.assign( Object.create( Mesh.prototype ), {
// camera forward is negative
var near = - camera.near;
// clip space is [ - 1, 1 ] so multiply by two to get the full
// width in clip space
var ssMaxWidth = 2.0 * Math.max( lineWidth / resolution.width, lineWidth / resolution.height );
//
// check if we intersect the sphere bounds
if ( geometry.boundingSphere === null ) {
geometry.computeBoundingSphere();
}
sphere.copy( geometry.boundingSphere ).applyMatrix4( matrixWorld );
var distanceToSphere = Math.max( camera.near, sphere.distanceToPoint( ray.origin ) );
// get the w component to scale the world space line width
clipToWorldVector.set( 0, 0, - distanceToSphere, 1.0 ).applyMatrix4( camera.projectionMatrix );
clipToWorldVector.multiplyScalar( 1.0 / clipToWorldVector.w );
clipToWorldVector.applyMatrix4( camera.projectionMatrixInverse );
// increase the sphere bounds by the worst case line screen space width
var sphereMargin = Math.abs( ssMaxWidth / clipToWorldVector.w ) * 0.5;
sphere.radius += sphereMargin;
if ( raycaster.ray.intersectsSphere( sphere ) === false ) {
return;
}
//
// check if we intersect the box bounds
if ( geometry.boundingBox === null ) {
geometry.computeBoundingBox();
}
box.copy( geometry.boundingBox ).applyMatrix4( matrixWorld );
var distanceToBox = Math.max( camera.near, box.distanceToPoint( ray.origin ) );
// get the w component to scale the world space line width
clipToWorldVector.set( 0, 0, - distanceToBox, 1.0 ).applyMatrix4( camera.projectionMatrix );
clipToWorldVector.multiplyScalar( 1.0 / clipToWorldVector.w );
clipToWorldVector.applyMatrix4( camera.projectionMatrixInverse );
// increase the sphere bounds by the worst case line screen space width
var boxMargin = Math.abs( ssMaxWidth / clipToWorldVector.w ) * 0.5;
box.max.x += boxMargin;
box.max.y += boxMargin;
box.max.z += boxMargin;
box.min.x -= boxMargin;
box.min.y -= boxMargin;
box.min.z -= boxMargin;
if ( raycaster.ray.intersectsBox( box ) === false ) {
return;
}
//
// pick a point 1 unit out along the ray to avoid the ray origin
// sitting at the camera origin which will cause "w" to be 0 when
// applying the projection matrix.
......@@ -116,7 +188,6 @@ LineSegments2.prototype = Object.assign( Object.create( Mesh.prototype ), {
ssOrigin3.copy( ssOrigin );
var matrixWorld = this.matrixWorld;
mvMatrix.multiplyMatrices( camera.matrixWorldInverse, matrixWorld );
for ( var i = 0, l = instanceStart.count; i < l; i ++ ) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册