@@ -6,6 +6,59 @@ use crate::Vec3;
66pub struct Ray {
77 /// The origin of the ray.
88 pub origin : Vec3 ,
9- /// The direction of the ray.
9+ /// A normalized vector representing the direction of the ray.
1010 pub direction : Vec3 ,
1111}
12+
13+ impl Ray {
14+ /// Returns the distance to the plane if the ray intersects it.
15+ #[ inline]
16+ pub fn intersect_plane ( & self , plane_origin : Vec3 , plane_normal : Vec3 ) -> Option < f32 > {
17+ let denominator = plane_normal. dot ( self . direction ) ;
18+ if denominator. abs ( ) > f32:: EPSILON {
19+ let distance = ( plane_origin - self . origin ) . dot ( plane_normal) / denominator;
20+ if distance >= f32:: EPSILON {
21+ return Some ( distance) ;
22+ }
23+ }
24+ None
25+ }
26+
27+ /// Retrieve a point at the given distance along the ray.
28+ #[ inline]
29+ pub fn get_point ( & self , distance : f32 ) -> Vec3 {
30+ self . origin + self . direction * distance
31+ }
32+ }
33+
34+ #[ cfg( test) ]
35+ mod test {
36+ use super :: * ;
37+
38+ #[ test]
39+ fn intersects_plane ( ) {
40+ let ray = Ray {
41+ origin : Vec3 :: ZERO ,
42+ direction : Vec3 :: Z ,
43+ } ;
44+
45+ // Orthogonal, and test that plane_normal direction doesn't matter
46+ assert_eq ! ( Some ( 1. ) , ray. intersect_plane( Vec3 :: Z , Vec3 :: Z ) ) ;
47+ assert_eq ! ( Some ( 1. ) , ray. intersect_plane( Vec3 :: Z , Vec3 :: NEG_Z ) ) ;
48+ assert_eq ! ( None , ray. intersect_plane( Vec3 :: NEG_Z , Vec3 :: Z ) ) ;
49+ assert_eq ! ( None , ray. intersect_plane( Vec3 :: NEG_Z , Vec3 :: NEG_Z ) ) ;
50+
51+ // Diagonal
52+ assert_eq ! ( Some ( 1. ) , ray. intersect_plane( Vec3 :: Z , Vec3 :: ONE ) ) ;
53+ assert_eq ! ( None , ray. intersect_plane( Vec3 :: NEG_Z , Vec3 :: ONE ) ) ;
54+
55+ // Parralel
56+ assert_eq ! ( None , ray. intersect_plane( Vec3 :: X , Vec3 :: X ) ) ;
57+
58+ // Parralel with simulated rounding error
59+ assert_eq ! (
60+ None ,
61+ ray. intersect_plane( Vec3 :: X , Vec3 :: X + Vec3 :: Z * f32 :: EPSILON )
62+ ) ;
63+ }
64+ }
0 commit comments