2
0
Эх сурвалжийг харах

OBB: Implement ray intersection test.

Mugen87 5 жил өмнө
parent
commit
54d0aa4135

+ 3 - 0
examples/jsm/math/OBB.d.ts

@@ -3,6 +3,7 @@ import {
 	Matrix3,
 	Matrix3,
 	Matrix4,
 	Matrix4,
 	Plane,
 	Plane,
+	Ray,
 	Sphere,
 	Sphere,
 	Vector3
 	Vector3
 } from '../../../src/Three';
 } from '../../../src/Three';
@@ -24,6 +25,8 @@ export class OBB {
 	intersectsSphere( sphere: Sphere ): boolean;
 	intersectsSphere( sphere: Sphere ): boolean;
 	intersectsOBB( obb: OBB, epsilon: number ): boolean;
 	intersectsOBB( obb: OBB, epsilon: number ): boolean;
 	intersectsPlane( plane: Plane ): boolean;
 	intersectsPlane( plane: Plane ): boolean;
+	intersectRay( ray: Ray, result: Vector3 ): Vector3 | null;
+	intersectsRay( ray: Ray ): boolean;
 	fromBox3( box3: Box3 ): this;
 	fromBox3( box3: Box3 ): this;
 	equals( obb: OBB ): boolean;
 	equals( obb: OBB ): boolean;
 	applyMatrix4( matrix: Matrix4 ): this;
 	applyMatrix4( matrix: Matrix4 ): this;

+ 82 - 0
examples/jsm/math/OBB.js

@@ -3,8 +3,11 @@
  */
  */
 
 
 import {
 import {
+	Box3,
 	MathUtils,
 	MathUtils,
+	Matrix4,
 	Matrix3,
 	Matrix3,
+	Ray,
 	Vector3
 	Vector3
 } from "../../../build/three.module.js";
 } from "../../../build/three.module.js";
 
 
@@ -30,8 +33,13 @@ var xAxis = new Vector3();
 var yAxis = new Vector3();
 var yAxis = new Vector3();
 var zAxis = new Vector3();
 var zAxis = new Vector3();
 var v1 = new Vector3();
 var v1 = new Vector3();
+var size = new Vector3();
 var closestPoint = new Vector3();
 var closestPoint = new Vector3();
 var rotationMatrix = new Matrix3();
 var rotationMatrix = new Matrix3();
+var aabb = new Box3();
+var matrix = new Matrix4();
+var inverse = new Matrix4();
+var localRay = new Ray();
 
 
 // OBB
 // OBB
 
 
@@ -302,6 +310,53 @@ Object.assign( OBB.prototype, {
 
 
 	},
 	},
 
 
+	/**
+	* Performs a ray/OBB intersection test and stores the intersection point
+	* to the given 3D vector. If no intersection is detected, *null* is returned.
+	*/
+	intersectRay: function ( ray, result ) {
+
+		// the idea is to perform the intersection test in the local space
+		// of the OBB.
+
+		this.getSize( size );
+		aabb.setFromCenterAndSize( v1.set( 0, 0, 0 ), size );
+
+		// create a 4x4 transformation matrix
+
+		matrix4FromRotationMatrix( matrix, this.rotation );
+		matrix.setPosition( this.center );
+
+		// transform ray to the local space of the OBB
+
+		localRay.copy( ray ).applyMatrix4( inverse.getInverse( matrix ) );
+
+		// perform ray <-> AABB intersection test
+
+		if ( localRay.intersectBox( aabb, result ) ) {
+
+			// transform the intersection point back to world space
+
+			return result.applyMatrix4( matrix );
+
+		} else {
+
+			return null;
+
+		}
+
+	},
+
+	/**
+	* Performs a ray/OBB intersection test. Returns either true or false if
+	* there is a intersection or not.
+	*/
+	intersectsRay: function ( ray ) {
+
+		return this.intersectRay( ray, v1 ) !== null;
+
+	},
+
 	fromBox3: function ( box3 ) {
 	fromBox3: function ( box3 ) {
 
 
 		box3.getCenter( this.center );
 		box3.getCenter( this.center );
@@ -366,6 +421,33 @@ Object.assign( OBB.prototype, {
 
 
 } );
 } );
 
 
+function matrix4FromRotationMatrix( matrix4, matrix3 ) {
+
+	var e = matrix4.elements;
+	var me = matrix3.elements;
+
+	e[ 0 ] = me[ 0 ];
+	e[ 1 ] = me[ 1 ];
+	e[ 2 ] = me[ 2 ];
+	e[ 3 ] = 0;
+
+	e[ 4 ] = me[ 3 ];
+	e[ 5 ] = me[ 4 ];
+	e[ 6 ] = me[ 5 ];
+	e[ 7 ] = 0;
+
+	e[ 8 ] = me[ 6 ];
+	e[ 9 ] = me[ 7 ];
+	e[ 10 ] = me[ 8 ];
+	e[ 11 ] = 0;
+
+	e[ 12 ] = 0;
+	e[ 13 ] = 0;
+	e[ 14 ] = 0;
+	e[ 15 ] = 1;
+
+}
+
 var obb = new OBB();
 var obb = new OBB();
 
 
 export { OBB };
 export { OBB };

+ 64 - 2
examples/webgl_math_obb.html

@@ -30,9 +30,9 @@
 
 
 			import Stats from './jsm/libs/stats.module.js';
 			import Stats from './jsm/libs/stats.module.js';
 
 
-			var camera, scene, renderer, clock, controls, stats;
+			var camera, scene, renderer, clock, controls, stats, raycaster, hitbox;
 
 
-			var objects = [];
+			var objects = [], mouse = new THREE.Vector2();
 
 
 			init();
 			init();
 			animate();
 			animate();
@@ -47,6 +47,8 @@
 
 
 				clock = new THREE.Clock();
 				clock = new THREE.Clock();
 
 
+				raycaster = new THREE.Raycaster();
+
 				var hemiLight = new THREE.HemisphereLight( 0xffffff, 0x222222, 1.5 );
 				var hemiLight = new THREE.HemisphereLight( 0xffffff, 0x222222, 1.5 );
 				hemiLight.position.set( 1, 1, 1 );
 				hemiLight.position.set( 1, 1, 1 );
 				scene.add( hemiLight );
 				scene.add( hemiLight );
@@ -86,6 +88,12 @@
 
 
 				}
 				}
 
 
+				//
+
+				hitbox = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: 0x000000, wireframe: true } ) );
+
+				//
+
 				renderer = new THREE.WebGLRenderer( { antialias: true } );
 				renderer = new THREE.WebGLRenderer( { antialias: true } );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
@@ -106,6 +114,60 @@
 
 
 				window.addEventListener( 'resize', onWindowResize, false );
 				window.addEventListener( 'resize', onWindowResize, false );
 
 
+				document.addEventListener( 'click', onClick, false );
+
+			}
+
+			function onClick( event ) {
+
+				event.preventDefault();
+
+				mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
+				mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
+
+				raycaster.setFromCamera( mouse, camera );
+
+				var intersectionPoint = new THREE.Vector3();
+				var intersections = [];
+
+				for ( var i = 0, il = objects.length; i < il; i ++ ) {
+
+					var object = objects[ i ];
+					var obb = object.userData.obb;
+
+					var ray = raycaster.ray;
+
+					if ( obb.intersectRay( ray, intersectionPoint ) !== null ) {
+
+						var distance = ray.origin.distanceTo( intersectionPoint );
+						intersections.push( { distance: distance, object: object } );
+
+					}
+
+				}
+
+				if ( intersections.length > 0 ) {
+
+					// determine closest intersection and highlight the respective 3D object
+
+					intersections.sort( sortIntersections );
+
+					intersections[ 0 ].object.add( hitbox );
+
+				} else {
+
+					var parent = hitbox.parent;
+
+					if ( parent ) parent.remove( hitbox );
+
+				}
+
+			}
+
+			function sortIntersections( a, b ) {
+
+				return a.distance - b.distance;
+
 			}
 			}
 
 
 			function onWindowResize() {
 			function onWindowResize() {