Selaa lähdekoodia

update raycsting

Garrett Johnson 5 vuotta sitten
vanhempi
commit
70b14f14de
3 muutettua tiedostoa jossa 60 lisäystä ja 44 poistoa
  1. 1 1
      example/index.js
  2. 24 3
      src/three/TilesRenderer.js
  3. 35 40
      src/three/raycastTraverse.js

+ 1 - 1
example/index.js

@@ -221,7 +221,7 @@ function animate() {
 	}
 
 	raycaster.setFromCamera( mouse, camera );
-
+	raycaster.firstHitOnly = true;
 	const results = raycaster.intersectObject( tiles.group, true );
 	if ( results.length ) {
 

+ 24 - 3
src/three/TilesRenderer.js

@@ -106,7 +106,20 @@ export class TilesRenderer extends TilesRendererBase {
 
 		if ( ! this.root ) return;
 
-		raycastTraverse( this.root, this.group, this.activeSet, raycaster, intersects );
+		if ( raycaster.firstHitOnly ) {
+
+			const hit = raycastTraverseFirstHit( this.root, this.group, this.activeSet, raycaster, intersects );
+			if ( hit ) {
+
+				intersects.push( hit );
+
+			}
+
+		} else {
+
+			raycastTraverse( this.root, this.group, this.activeSet, raycaster, intersects );
+
+		}
 
 	}
 
@@ -420,6 +433,7 @@ export class TilesRenderer extends TilesRendererBase {
 				let error;
 				if ( cam.isOrthographic ) {
 
+					// TODO: account for error here
 					const w = cam.right - cam.left;
 					const h = cam.top - cam.bottom;
 					const pixelSize = Math.Max( h, w ) / Math.Max( resVector.width, resVector.height );
@@ -436,13 +450,20 @@ export class TilesRenderer extends TilesRendererBase {
 					tempVector.setFromMatrixScale( tempMat );
 					scale = tempVector.x;
 
+					if ( Math.abs( Math.max( tempVector.x - tempVector.y, tempVector.x - tempVector.z ) ) > 1e-6 ) {
+
+						console.warn( 'ThreeTilesRenderer : Non uniform scale used for tile which may cause issues when calculating screen space error.' );
+
+					}
+
+					// TODO: Is this necessary? We want error in screen space which should account for all scales
 					// account for parent group scale. Divide because this matrix has not been inverted like the previous one.
 					tempVector.setFromMatrixScale( group.matrixWorld );
 					scale /= tempVector.x;
 
-					if ( Math.abs( Math.max( scale.x - scale.y, scale.x - scale.z ) ) > 1e-6 ) {
+					if ( Math.abs( Math.max( tempVector.x - tempVector.y, tempVector.x - tempVector.z ) ) > 1e-6 ) {
 
-						console.warn( 'ThreeTilesRenderer : Non uniform scale used for tile which may cause issues when claculating screen space error.' );
+						console.warn( 'ThreeTilesRenderer : Non uniform scale used for tile which may cause issues when calculating screen space error.' );
 
 					}
 

+ 35 - 40
src/three/raycastTraverse.js

@@ -2,10 +2,9 @@ import { Matrix4, Sphere, Ray, Vector3, Box3Helper } from 'three';
 const _sphere = new Sphere();
 const _mat = new Matrix4();
 const _vec = new Vector3();
+const _vec2 = new Vector3();
 const _ray = new Ray();
 
-let _currIndex = 0;
-const _array = [];
 const _hitArray = [];
 
 function distanceSort( a, b ) {
@@ -32,6 +31,8 @@ function intersectTileScene( scene, raycaster, intersects ) {
 // Returns the closest hit when traversing the tree
 export function raycastTraverseFirstHit( root, group, activeSet, raycaster ) {
 
+	// TODO: see if we can avoid creating a new array here every time to save on memory
+	const array = [];
 	const children = root.children;
 	for ( let i = 0, l = children.length; i < l; i ++ ) {
 
@@ -68,24 +69,25 @@ export function raycastTraverseFirstHit( root, group, activeSet, raycaster ) {
 			_ray.copy( raycaster.ray ).applyMatrix4( _mat );
 			if ( _ray.intersectBox( boundingBox, _vec ) ) {
 
-				// if we intersect the box save the distance to the tile bounds
-				let data;
-				if ( _currIndex >= _array.length ) {
-
-					data = {
-						distance: Infinity,
-						tile: null
-					};
-					_array.push( data );
+				// account for tile scale
+				let scale;
+				_vec2.setFromMatrixScale( _mat );
+				scale = _vec2.x;
 
-				} else {
+				if ( Math.abs( Math.max( _vec2.x - _vec2.y, _vec2.x - _vec2.z ) ) > 1e-6 ) {
 
-					data = _array[ _currIndex ];
+					console.warn( 'ThreeTilesRenderer : Non uniform scale used for tile which may cause issues when raycasting.' );
 
 				}
-				_currIndex ++;
 
-				data.distance = _vec.distanceToSquared( _ray.origin );
+				// if we intersect the box save the distance to the tile bounds
+				let data = {
+					distance: Infinity,
+					tile: null
+				};
+				array.push( data );
+
+				data.distance = _vec.distanceToSquared( _ray.origin ) * scale * scale;
 				data.tile = tile;
 
 			} else {
@@ -99,15 +101,15 @@ export function raycastTraverseFirstHit( root, group, activeSet, raycaster ) {
 	}
 
 	// sort them by ascending distance
-	_array.sort( distanceSort );
+	array.sort( distanceSort );
 
 	// traverse until we find the best hit and early out if a tile bounds
 	// couldn't possible include a best hit
 	let bestDistanceSquared = Infinity;
 	let bestHit = null;
-	for ( let i = 0, l = _currIndex; i < l; i ++ ) {
+	for ( let i = 0, l = array.length; i < l; i ++ ) {
 
-		const data = _array[ i ];
+		const data = array[ i ];
 		const distanceSquared = data.distance;
 		if ( distanceSquared > bestDistanceSquared ) {
 
@@ -117,7 +119,9 @@ export function raycastTraverseFirstHit( root, group, activeSet, raycaster ) {
 
 			const tile = data.tile;
 			const scene = tile.cached.scene;
-			const tileChildren = tile.children;
+
+			let hit = null;
+
 			if ( activeSet.has( scene ) ) {
 
 				// save the hit if it's closer
@@ -130,41 +134,32 @@ export function raycastTraverseFirstHit( root, group, activeSet, raycaster ) {
 
 					}
 
-					const hit = _hitArray[ 0 ];
-					const hitDistanceSquared = hit.distance * hit.distance;
-					if ( hitDistanceSquared < bestDistanceSquared ) {
-
-						bestDistanceSquared = hitDistanceSquared;
-						bestHit = hit;
-
-					}
-					_hitArray.length = 0;
+					hit = _hitArray[ 0 ];
 
 				}
 
 			} else {
 
-				for ( let t = 0, tl = tileChildren; t < tl; t ++ ) {
+				hit = raycastTraverseFirstHit( tile, group, activeSet, raycaster );
 
-					raycastTraverseFirstHit( t, group, activeSet, raycaster );
+			}
 
-				}
+			if ( hit ) {
 
-			}
+				const hitDistanceSquared = hit.distance * hit.distance;
+				if ( hitDistanceSquared < bestDistanceSquared ) {
 
-		}
+					bestDistanceSquared = hitDistanceSquared;
+					bestHit = hit;
 
-	}
+				}
+				_hitArray.length = 0;
 
-	// reset the cached array for next use to save on object allocation
-	for ( let i = 0, l = _currIndex; i < l; i ++ ) {
+			}
 
-		const el = _array[ i ];
-		el.tile = null;
-		el.distance = Infinity;
+		}
 
 	}
-	_currIndex = 0;
 
 	return bestHit;