pub fn ray_plane_intersection(
ray_origin: glam::Vec3,
ray_dir: glam::Vec3,
plane_normal: glam::Vec3,
plane_distance: f32,
) -> Option<glam::Vec3> {
let denom = plane_normal.dot(ray_dir);
if denom.abs() < 1e-6 {
return None;
}
let t = -(plane_normal.dot(ray_origin) + plane_distance) / denom;
if t < 0.0 {
return None;
}
Some(ray_origin + ray_dir * t)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ray_plane_intersection_hits() {
let origin = glam::Vec3::new(0.0, 5.0, 0.0);
let dir = glam::Vec3::new(0.0, -1.0, 0.0);
let hit = ray_plane_intersection(origin, dir, glam::Vec3::Y, -2.0);
assert!(hit.is_some());
let p = hit.unwrap();
assert!((p.y - 2.0).abs() < 1e-5);
}
#[test]
fn ray_plane_intersection_parallel_returns_none() {
let origin = glam::Vec3::new(0.0, 1.0, 0.0);
let dir = glam::Vec3::new(1.0, 0.0, 0.0);
assert!(ray_plane_intersection(origin, dir, glam::Vec3::Y, 0.0).is_none());
}
#[test]
fn ray_plane_intersection_behind_returns_none() {
let origin = glam::Vec3::new(0.0, 5.0, 0.0);
let dir = glam::Vec3::new(0.0, 1.0, 0.0);
assert!(ray_plane_intersection(origin, dir, glam::Vec3::Y, 0.0).is_none());
}
}