intersectRay method
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;
}