use super::*;
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Ray3<T> {
pub origin: Point3<T>,
pub direction: Vec3<T>,
pub distance: Interval<T>,
}
#[allow(non_snake_case)]
#[inline]
pub fn Ray3<T>(origin: Point3<T>, direction: Vec3<T>, distance: Interval<T>) -> Ray3<T> {
Ray3 { origin, direction, distance }
}
#[cfg(feature = "dataview")]
unsafe impl<T: dataview::Pod> dataview::Pod for Ray3<T> {}
impl<T> Ray3<T> {
#[inline]
pub fn new(origin: Point3<T>, direction: Vec3<T>, distance: Interval<T>) -> Ray3<T> where T: Float {
let direction = direction.norm();
Ray3 { origin, direction, distance }
}
}
impl<T: Float> Ray3<T> {
#[inline]
pub fn at(&self, distance: T) -> Point3<T> {
self.origin.mul_add(self.direction, distance)
}
#[inline]
pub fn reflect(&self, hit: &Hit3<T>) -> Ray3<T> {
let direction = (-self.direction).reflect(hit.normal);
let distance = Interval(self.distance.min, self.distance.max - hit.distance);
Ray3 { origin: hit.point, direction, distance }
}
}
impl<T: Float> ops::Mul<Ray3<T>> for Transform3<T> {
type Output = Ray3<T>;
#[inline]
fn mul(self, ray: Ray3<T>) -> Ray3<T> {
let origin = self * ray.origin;
let (direction, distance) = if ray.distance.max.is_finite() {
let end = self * ray.at(ray.distance.max);
let (direction, max_distance) = (end - origin).norm_len();
(direction, Interval(ray.distance.min * max_distance / ray.distance.max, max_distance))
}
else {
let dir = self.mat3() * ray.direction;
(dir.norm(), ray.distance)
};
Ray3 { origin, direction, distance }
}
}
#[derive(Copy, Clone, Debug, Default, PartialEq)]
pub struct Hit3<T> {
pub point: Point3<T>,
pub distance: T,
pub normal: Vec3<T>,
pub index: usize,
pub side: HitSide,
}
pub trait Trace3<T> {
fn inside(&self, pt: Point3<T>) -> bool;
fn trace(&self, ray: &Ray3<T>) -> Option<Hit3<T>>;
}
impl<T: Float, Shape: Trace3<T> + ?Sized> Trace3<T> for &Shape {
#[inline]
fn inside(&self, pt: Point3<T>) -> bool {
(*self).inside(pt)
}
#[inline]
fn trace(&self, ray: &Ray3<T>) -> Option<Hit3<T>> {
(*self).trace(ray)
}
}
impl<T: Float> Ray3<T> {
#[inline]
pub fn inside<U: Trace3<T> + ?Sized>(&self, shape: &U) -> bool {
shape.inside(self.origin)
}
#[inline]
pub fn inside_collection<Shape: Trace3<T>, I: IntoIterator<Item = Shape>>(&self, shapes: I) -> bool {
shapes.into_iter().any(|shape| shape.inside(self.origin))
}
#[inline]
pub fn trace<U: Trace3<T> + ?Sized>(&self, shape: &U) -> Option<Hit3<T>> {
shape.trace(self)
}
#[inline]
pub fn trace_collection<Shape: Trace3<T>, I: IntoIterator<Item = Shape>>(&self, shapes: I) -> Option<Hit3<T>> {
let mut ray = self.clone();
let mut result = None;
for (index, shape) in shapes.into_iter().enumerate() {
if let Some(hit) = shape.trace(&ray) {
result = Some(Hit3 { index, ..hit });
ray.distance.max = hit.distance;
}
}
result
}
}