obvhs/ray.rs
1//! A ray in 3D space.
2
3use glam::{Vec3A, vec3a};
4
5/// Computes the inverse of `x` avoiding division by zero.
6pub fn safe_inverse(x: f32) -> f32 {
7 if x.abs() <= f32::EPSILON {
8 x.signum() / f32::EPSILON
9 } else {
10 1.0 / x
11 }
12}
13
14/// A struct representing a ray in 3D space.
15#[derive(Clone, Copy, Debug)]
16#[repr(C)]
17pub struct Ray {
18 /// The starting point of the ray.
19 pub origin: Vec3A,
20 /// The direction vector of the ray.
21 pub direction: Vec3A,
22 /// The inverse of the direction vector components.
23 /// Used to avoid division in ray/aabb tests. Seems to improve performance in
24 /// some cases on the cpu, but not the gpu in some others.
25 pub inv_direction: Vec3A,
26 /// The minimum `t` (distance) value for intersection tests.
27 pub tmin: f32,
28 /// The maximum `t` (distance) value for intersection tests.
29 pub tmax: f32,
30}
31
32impl Ray {
33 /// Creates a new `Ray` with the given origin, direction, and `t` (distance) range.
34 pub fn new(origin: Vec3A, direction: Vec3A, min: f32, max: f32) -> Self {
35 let ray = Ray {
36 origin,
37 direction,
38 inv_direction: vec3a(
39 safe_inverse(direction.x),
40 safe_inverse(direction.y),
41 safe_inverse(direction.z),
42 ),
43 tmin: min,
44 tmax: max,
45 };
46
47 debug_assert!(ray.inv_direction.is_finite());
48 debug_assert!(ray.direction.is_finite());
49 debug_assert!(origin.is_finite());
50
51 ray
52 }
53
54 /// Creates a new infinite `Ray` with the given origin, direction.
55 pub fn new_inf(origin: Vec3A, direction: Vec3A) -> Self {
56 Self::new(origin, direction, 0.0, f32::INFINITY)
57 }
58}
59
60/// A struct representing a hit record in ray tracing.
61/// A `Hit` record contains the IDs of the primitive, geometry and instance that
62/// were hit, as well as the `t` (distance) value at which the hit occurred.
63#[derive(Clone, Copy, Debug)]
64#[repr(C)]
65pub struct RayHit {
66 pub primitive_id: u32,
67 pub geometry_id: u32,
68 pub instance_id: u32,
69 pub t: f32,
70}
71
72pub const INVALID_ID: u32 = u32::MAX;
73
74impl RayHit {
75 /// Creates a new `RayHit` instance representing no hit.
76 pub fn none() -> Self {
77 Self {
78 primitive_id: INVALID_ID,
79 geometry_id: INVALID_ID,
80 instance_id: INVALID_ID,
81 t: f32::INFINITY,
82 }
83 }
84}