bevy/crates/bevy_math/src/ray.rs

65 lines
2 KiB
Rust
Raw Normal View History

use crate::Vec3;
/// A ray is an infinite line starting at `origin`, going in `direction`.
#[derive(Default, Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
pub struct Ray {
/// The origin of the ray.
pub origin: Vec3,
/// A normalized vector representing the direction of the ray.
pub direction: Vec3,
}
impl Ray {
/// Returns the distance to the plane if the ray intersects it.
#[inline]
pub fn intersect_plane(&self, plane_origin: Vec3, plane_normal: Vec3) -> Option<f32> {
let denominator = plane_normal.dot(self.direction);
if denominator.abs() > f32::EPSILON {
let distance = (plane_origin - self.origin).dot(plane_normal) / denominator;
if distance > f32::EPSILON {
return Some(distance);
}
}
None
}
/// Retrieve a point at the given distance along the ray.
#[inline]
pub fn get_point(&self, distance: f32) -> Vec3 {
self.origin + self.direction * distance
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn intersect_plane() {
let ray = Ray {
origin: Vec3::ZERO,
direction: Vec3::Z,
};
// Orthogonal, and test that an inverse plane_normal has the same result
assert_eq!(Some(1.), ray.intersect_plane(Vec3::Z, Vec3::Z));
assert_eq!(Some(1.), ray.intersect_plane(Vec3::Z, Vec3::NEG_Z));
assert_eq!(None, ray.intersect_plane(Vec3::NEG_Z, Vec3::Z));
assert_eq!(None, ray.intersect_plane(Vec3::NEG_Z, Vec3::NEG_Z));
// Diagonal
assert_eq!(Some(1.), ray.intersect_plane(Vec3::Z, Vec3::ONE));
assert_eq!(None, ray.intersect_plane(Vec3::NEG_Z, Vec3::ONE));
// Parallel
assert_eq!(None, ray.intersect_plane(Vec3::X, Vec3::X));
// Parallel with simulated rounding error
assert_eq!(
None,
ray.intersect_plane(Vec3::X, Vec3::X + Vec3::Z * f32::EPSILON)
);
}
}