Ray Intersection

High-Level Functions

AsteroidShapeModels.intersect_ray_shapeFunction
intersect_ray_shape(shape::ShapeModel, origins::AbstractMatrix{<:Real}, directions::AbstractMatrix{<:Real}) -> Vector{RayShapeIntersectionResult}

Perform batch ray-shape intersection tests using the same interface as ImplicitBVH.traverse_rays.

This is the core implementation that all other intersect_ray_shape methods delegate to.

Note

As of v0.4.0, BVH must be pre-built before calling this function. Use either with_bvh=true when loading or call build_bvh!(shape) explicitly.

Arguments

  • shape : Shape model (must have BVH built via build_bvh!)
  • origins : 3×N matrix where each column is a ray origin
  • directions : 3×N matrix where each column is a ray direction

Returns

  • Vector of RayShapeIntersectionResult objects, one for each input ray

Throws

  • ArgumentError if BVH is not built. Call build_bvh!(shape) before using this function.

Notes

  • This function provides a convenient interface that matches ImplicitBVH.traverse_rays parameters
  • BVH must be pre-built using build_bvh!(shape) or by creating the shape with with_bvh=true
  • All rays are processed in a single batch for efficiency

Example

# Create ray data
n_rays = 100
origins = rand(3, n_rays) .* 1000  # Random origins
directions = normalize.(eachcol(rand(3, n_rays) .- 0.5))  # Random directions

# Convert directions back to matrix
directions = hcat(directions...)

# Perform batch intersection
results = intersect_ray_shape(shape, origins, directions)
source
intersect_ray_shape(ray::Ray, shape::ShapeModel) -> RayShapeIntersectionResult

Perform ray-shape intersection test using BVH acceleration. Uses the Möller–Trumbore algorithm for ray-triangle mesh intersection.

Note

As of v0.4.0, BVH must be pre-built before calling this function. Use either with_bvh=true when loading or call build_bvh!(shape) explicitly.

Arguments

  • ray : Ray with origin and direction
  • shape : Shape model (must have BVH built via build_bvh!)

Returns

  • RayShapeIntersectionResult object containing the intersection test result

Throws

  • ArgumentError if BVH is not built. Call build_bvh!(shape) before using this function.

Notes

  • BVH must be pre-built using build_bvh!(shape) or by creating the shape with with_bvh=true
  • To pre-build BVH, use load_shape_obj("path/to/shape.obj"; with_bvh=true)
  • Or for an existing ShapeModel: build_bvh!(shape)

Example

ray = Ray(SA[0.0, 0.0, 1000.0], SA[0.0, 0.0, -1.0])
result = intersect_ray_shape(ray, shape)

if result.hit
    println("Hit face $(result.face_idx) at distance $(result.distance)")
end
source
intersect_ray_shape(rays::AbstractVector{Ray}, shape::ShapeModel) -> Vector{RayShapeIntersectionResult}

Perform batch ray-shape intersection tests for multiple rays.

Note

As of v0.4.0, BVH must be pre-built before calling this function. Use either with_bvh=true when loading or call build_bvh!(shape) explicitly.

Arguments

  • rays : Vector of Ray objects
  • shape : Shape model (must have BVH built via build_bvh!)

Returns

  • Vector of RayShapeIntersectionResult objects, one for each input ray

Throws

  • ArgumentError if BVH is not built. Call build_bvh!(shape) before using this function.

Example

# Create a vector of rays
rays = [Ray(SA[x, 0.0, 1000.0], SA[0.0, 0.0, -1.0]) for x in -500:100:500]
results = intersect_ray_shape(rays, shape)

# Count hits
n_hits = count(r -> r.hit, results)
println("$n_hits out of $(length(rays)) rays hit the shape")
source
intersect_ray_shape(rays::AbstractMatrix{Ray}, shape::ShapeModel) -> Matrix{RayShapeIntersectionResult}

Perform batch ray-shape intersection tests for a matrix of rays. The output shape matches the input shape, preserving spatial arrangement.

Note

As of v0.4.0, BVH must be pre-built before calling this function. Use either with_bvh=true when loading or call build_bvh!(shape) explicitly.

Arguments

  • rays : Matrix of Ray objects
  • shape : Shape model (must have BVH built via build_bvh!)

Returns

  • Matrix of RayShapeIntersectionResult objects with the same size as input

Throws

  • ArgumentError if BVH is not built. Call build_bvh!(shape) before using this function.

Example

# Create a matrix of rays
rays = [Ray(SA[x, y, 1000.0], SA[0.0, 0.0, -1.0]) for x in -500:100:500, y in -500:100:500]
results = intersect_ray_shape(rays, shape)

# Process results while preserving grid structure
for i in 1:size(results, 1), j in 1:size(results, 2)
    if results[i, j].hit
        println("Ray at ($i, $j) hit at $(results[i, j].point)")
    end
end
source

Low-Level Functions

AsteroidShapeModels.intersect_ray_triangleFunction
intersect_ray_triangle(ray::Ray, v1::AbstractVector{<:Real}, v2::AbstractVector{<:Real}, v3::AbstractVector{<:Real}) -> RayTriangleIntersectionResult

Perform ray-triangle intersection test using the Möller–Trumbore algorithm.

Arguments

  • ray: Ray with origin and direction
  • v1: Triangle vertex 1
  • v2: Triangle vertex 2
  • v3: Triangle vertex 3

Returns

  • RayTriangleIntersectionResult object containing the intersection test result

Algorithm Details

This implementation has the following characteristics:

  • No backface culling: Triangles are hit from both sides (front and back)
  • Forward rays only: Only intersections in the ray direction are detected (distance > 0)
  • No self-intersection: Rays starting exactly on the triangle surface typically miss due to numerical precision

Example

# Ray from above hits triangle on XY plane
ray = Ray(SA[0.5, 0.5, 1.0], SA[0.0, 0.0, -1.0])
v1, v2, v3 = SA[0.0, 0.0, 0.0], SA[1.0, 0.0, 0.0], SA[0.0, 1.0, 0.0]
result = intersect_ray_triangle(ray, v1, v2, v3)
# result.hit == true, result.distance ≈ 1.0

# Ray from below also hits (no backface culling)
ray_below = Ray(SA[0.5, 0.5, -1.0], SA[0.0, 0.0, 1.0])
result = intersect_ray_triangle(ray_below, v1, v2, v3)
# result.hit == true

# Ray pointing away misses (backward intersection rejected)
ray_away = Ray(SA[0.5, 0.5, 1.0], SA[0.0, 0.0, 1.0])
result = intersect_ray_triangle(ray_away, v1, v2, v3)
# result.hit == false
source
intersect_ray_triangle(ray::Ray, shape::ShapeModel, face_idx::Integer) -> RayTriangleIntersectionResult

Perform ray-triangle intersection test for a specific face in a shape model.

Arguments

  • ray : Ray with origin and direction
  • shape : Shape model containing the triangle
  • face_idx : Index of the face to test (1-based)

Returns

  • RayTriangleIntersectionResult object containing the intersection test result

Algorithm Details

This function uses the same Möller-Trumbore algorithm as the base implementation:

  • No backface culling (triangles are hit from both sides)
  • Forward rays only (distance > 0)
  • Inlined for performance

Example

shape = load_shape_obj("asteroid.obj")
ray = Ray(SA[0.0, 0.0, 100.0], SA[0.0, 0.0, -1.0])
result = intersect_ray_triangle(ray, shape, 1)  # Test first face
source
intersect_ray_triangle(ray::Ray, nodes::AbstractVector, faces::AbstractVector, face_idx::Integer) -> RayTriangleIntersectionResult

Perform ray-triangle intersection test for a specific face given nodes and faces arrays.

Arguments

  • ray : Ray with origin and direction
  • nodes : Array of node positions (3D vectors)
  • faces : Array of face definitions (each face is an array of 3 node indices)
  • face_idx : Index of the face to test (1-based)

Returns

  • RayTriangleIntersectionResult object containing the intersection test result

Algorithm Details

This function uses the same Möller-Trumbore algorithm as the base implementation:

  • No backface culling (triangles are hit from both sides)
  • Forward rays only (distance > 0)
  • Inlined for performance

Notes

This is a lower-level interface useful when working directly with node and face arrays without a full ShapeModel structure.

source
AsteroidShapeModels.intersect_ray_sphereFunction
intersect_ray_sphere(
    ray_origin::SVector{3, Float64}, ray_direction::SVector{3, Float64}, 
    sphere_center::SVector{3, Float64}, sphere_radius::Float64,
) -> RaySphereIntersectionResult

Test if a ray intersects with a sphere.

Arguments

  • ray_origin : Starting point of the ray
  • ray_direction : Direction of the ray (will be normalized internally)
  • sphere_center : Center of the sphere
  • sphere_radius : Radius of the sphere

Returns

RaySphereIntersectionResult with fields:

  • hit::Bool : true if the ray intersects the sphere
  • distance1::Float64 : Distance to first intersection point (NaN if no intersection)
  • distance2::Float64 : Distance to second intersection point (NaN if no intersection)
  • point1::SVector{3, Float64} : First intersection point coordinates
  • point2::SVector{3, Float64} : Second intersection point coordinates

Special Cases

  • Ray origin inside sphere: When the ray starts inside the sphere, distance1 < 0 (behind the origin) and distance2 > 0 (in front of the origin). The ray will always hit the sphere from inside.
  • Ray origin on sphere surface: When the ray starts exactly on the sphere surface, distance1 ≈ 0.
  • Tangent ray: When the ray just touches the sphere, distance1 ≈ distance2.
  • Sphere behind ray: When both intersection points are behind the ray origin (distance2 < 0), the function returns no intersection as the sphere is not in the ray's forward direction.
  • Degenerate cases: Returns no intersection for zero or negative radius spheres, or zero-length ray directions.

Algorithm

Solves the quadratic equation for ray-sphere intersection: |rayorigin + t * raydirection - spherecenter|² = sphereradius²

Example

ray_origin    = SVector(0.0, 0.0, 0.0)
ray_direction = SVector(1.0, 0.0, 0.0)  # Normalization is handled internally
sphere_center = SVector(5.0, 0.0, 0.0)
sphere_radius = 2.0

result = intersect_ray_sphere(ray_origin, ray_direction, sphere_center, sphere_radius)
if result.hit
    println("Ray hits sphere at distances: ", result.distance1, " and ", result.distance2)
    println("Entry point : ", result.point1)
    println("Exit point  : ", result.point2)
end
source
intersect_ray_sphere(ray::Ray, sphere::Sphere) -> RaySphereIntersectionResult

Test if a ray intersects with a sphere using Ray and Sphere objects.

This is a convenience overload that extracts the parameters from the Ray and Sphere objects and calls the main implementation.

Arguments

  • ray : Ray object containing origin and direction
  • sphere : Sphere object containing center and radius

Returns

RaySphereIntersectionResult with intersection details

Example

ray = Ray([0.0, 0.0, 0.0], [1.0, 0.0, 0.0])
sphere = Sphere([5.0, 0.0, 0.0], 2.0)

result = intersect_ray_sphere(ray, sphere)
if result.hit
    println("Ray hits sphere at distances: ", result.distance1, " and ", result.distance2)
    println("Entry point : ", result.point1)
    println("Exit point  : ", result.point2)
end
source