intersectRay method

Vector3? intersectRay(
  1. Ray ray,
  2. Matrix4 worldMatrix,
  3. bool closest,
  4. Vector3 intersectionPoint, [
  5. Vector3? normal,
])

Performs a ray intersection test with the geometry of the obstacle and stores the intersection point in the given result vector. If no intersection is detected, null is returned.

Implementation

Vector3? intersectRay(Ray ray, Matrix4 worldMatrix, bool closest, Vector3 intersectionPoint, [Vector3? normal]) {
	// check bounding sphere first in world space
	_boundingSphere.copy( boundingSphere ).applyMatrix4( worldMatrix );
	if ( ray.intersectsBoundingSphere( _boundingSphere ) ) {
		// transform the ray into the local space of the obstacle
		worldMatrix.getInverse( inverseMatrix );
		rayLocal.copy( ray ).applyMatrix4( inverseMatrix );
		// check AABB in local space since its more expensive to convert an AABB to world space than a bounding sphere
		if ( rayLocal.intersectsAABB( aabb ) ) {
			// now perform more expensive test with all triangles of the geometry
			final vertices = this.vertices;
			final indices = this.indices;

			double minDistance = double.infinity;
			bool found = false;

			if ( indices == null ) {
				// non-indexed geometry
				for ( int i = 0, l = vertices.length; i < l; i += 9 ) {
					triangle['a']?.set( vertices[ i ], vertices[ i + 1 ], vertices[ i + 2 ] );
					triangle['b']?.set( vertices[ i + 3 ], vertices[ i + 4 ], vertices[ i + 5 ] );
					triangle['c']?.set( vertices[ i + 6 ], vertices[ i + 7 ], vertices[ i + 8 ] );

					if ( rayLocal.intersectTriangle( triangle, backfaceCulling, intersectionPoint ) != null ) {
						if ( closest ) {
							final distance = intersectionPoint.squaredDistanceTo( rayLocal.origin );

							if ( distance < minDistance ) {
								minDistance = distance;

								closestIntersectionPoint.copy( intersectionPoint );
								closestTriangle['a']?.copy( triangle['a']! );
								closestTriangle['b']?.copy( triangle['b']! );
								closestTriangle['c']?.copy( triangle['c']! );
								found = true;
							}
						}
              else {
							found = true;
							break;
						}
					}
				}
			}
        else {
				// indexed geometry
				for ( int i = 0, l = indices.length; i < l; i += 3 ) {
					final a = indices[ i ];
					final b = indices[ i + 1 ];
					final c = indices[ i + 2 ];

					final stride = 3;

					triangle['a']?.set( vertices[ ( a * stride ) ], vertices[ ( a * stride ) + 1 ], vertices[ ( a * stride ) + 2 ] );
					triangle['b']?.set( vertices[ ( b * stride ) ], vertices[ ( b * stride ) + 1 ], vertices[ ( b * stride ) + 2 ] );
					triangle['c']?.set( vertices[ ( c * stride ) ], vertices[ ( c * stride ) + 1 ], vertices[ ( c * stride ) + 2 ] );

            if ( rayLocal.intersectTriangle( triangle, backfaceCulling, intersectionPoint ) != null ) {
						if ( closest ) {
							final distance = intersectionPoint.squaredDistanceTo( rayLocal.origin );

							if ( distance < minDistance ) {
								minDistance = distance;
								closestIntersectionPoint.copy( intersectionPoint );
								closestTriangle['a']?.copy( triangle['a']! );
								closestTriangle['b']?.copy( triangle['b']! );
								closestTriangle['c']?.copy( triangle['c']! );
								found = true;
							}
						}
              else {
							found = true;
							break;
						}
					}
				}
			}

			// intersection was found
			if ( found ) {
				if ( closest ) {
					// restore closest intersection point and triangle
					intersectionPoint.copy( closestIntersectionPoint );
					triangle['a']?.copy( closestTriangle['a']! );
					triangle['b']?.copy( closestTriangle['b']! );
					triangle['c']?.copy( closestTriangle['c']! );
				}

				// transform intersection point back to world space
				intersectionPoint.applyMatrix4( worldMatrix );

				// compute normal of triangle in world space if necessary
				if ( normal != null ) {
					plane.fromCoplanarPoints( triangle['a']!, triangle['b']!, triangle['c']! );
					normal.copy( plane.normal );
					normal.transformDirection( worldMatrix );
				}

				return intersectionPoint;
			}
		}
	}

	return null;
}