126 lines
3.6 KiB
Rust
126 lines
3.6 KiB
Rust
use super::{Normal3f, Point3f, Point3fi, Vector3f, VectorLike};
|
|
use crate::core::medium::Medium;
|
|
use crate::core::pbrt::Float;
|
|
use crate::utils::math::{next_float_down, next_float_up};
|
|
use crate::utils::ptr::Ptr;
|
|
|
|
#[repr(C)]
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub struct Ray {
|
|
pub o: Point3f,
|
|
pub d: Vector3f,
|
|
pub time: Float,
|
|
pub medium: Ptr<Medium>,
|
|
// We do this instead of creating a trait for Rayable or some gnarly thing like that
|
|
pub has_differentials: bool,
|
|
pub differential: RayDifferential,
|
|
}
|
|
|
|
impl Default for Ray {
|
|
fn default() -> Self {
|
|
Self {
|
|
o: Point3f::new(0.0, 0.0, 0.0),
|
|
d: Vector3f::new(0.0, 0.0, 0.0),
|
|
medium: Ptr::null(),
|
|
time: 0.0,
|
|
has_differentials: false,
|
|
differential: RayDifferential::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Ray {
|
|
pub fn new(o: Point3f, d: Vector3f, time: Option<Float>, medium: Ptr<Medium>) -> Self {
|
|
Self {
|
|
o,
|
|
d,
|
|
time: time.unwrap_or_else(|| Self::default().time),
|
|
medium,
|
|
..Self::default()
|
|
}
|
|
}
|
|
|
|
pub fn at(&self, t: Float) -> Point3f {
|
|
self.o + self.d * t
|
|
}
|
|
|
|
pub fn offset_origin(p: &Point3fi, n: &Normal3f, w: &Vector3f) -> Point3f {
|
|
let d: Float = Vector3f::from(n.abs()).dot(p.error());
|
|
let normal: Vector3f = Vector3f::from(*n);
|
|
|
|
let mut offset = p.midpoint();
|
|
if w.dot(normal) < 0.0 {
|
|
offset -= normal * d;
|
|
} else {
|
|
offset += normal * d;
|
|
}
|
|
|
|
for i in 0..3 {
|
|
if n[i] > 0.0 {
|
|
offset[i] = next_float_up(offset[i]);
|
|
} else if n[i] < 0.0 {
|
|
offset[i] = next_float_down(offset[i]);
|
|
}
|
|
}
|
|
offset
|
|
}
|
|
|
|
pub fn spawn(pi: &Point3fi, n: &Normal3f, time: Float, d: Vector3f) -> Ray {
|
|
let origin = Self::offset_origin(pi, n, &d);
|
|
Ray {
|
|
o: origin,
|
|
d,
|
|
time,
|
|
medium: Ptr::null(),
|
|
has_differentials: false,
|
|
differential: RayDifferential::default(),
|
|
}
|
|
}
|
|
|
|
pub fn spawn_to_point(p_from: &Point3fi, n: &Normal3f, time: Float, p_to: Point3f) -> Ray {
|
|
let d = p_to - p_from.midpoint();
|
|
Self::spawn(p_from, n, time, d)
|
|
}
|
|
|
|
pub fn spawn_to_interaction(
|
|
p_from: &Point3fi,
|
|
n_from: &Normal3f,
|
|
time: Float,
|
|
p_to: &Point3fi,
|
|
n_to: &Normal3f,
|
|
) -> Ray {
|
|
let dir_for_offset = p_to.midpoint() - p_from.midpoint();
|
|
let pf = Self::offset_origin(p_from, n_from, &dir_for_offset);
|
|
let pt = Self::offset_origin(p_to, n_to, &(pf - p_to.midpoint()));
|
|
|
|
let d = pt - pf;
|
|
|
|
Ray {
|
|
o: pf,
|
|
d,
|
|
time,
|
|
medium: Ptr::null(),
|
|
has_differentials: false,
|
|
differential: RayDifferential::default(),
|
|
}
|
|
}
|
|
|
|
pub fn scale_differentials(&mut self, s: Float) {
|
|
if self.has_differentials {
|
|
let differential = &mut self.differential;
|
|
differential.rx_origin = self.o + (differential.rx_origin - self.o) * s;
|
|
differential.ry_origin = self.o + (differential.ry_origin - self.o) * s;
|
|
differential.rx_direction = self.d + (differential.rx_direction - self.d) * s;
|
|
differential.ry_direction = self.d + (differential.ry_direction - self.d) * s;
|
|
}
|
|
}
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Debug, Default, Copy, Clone)]
|
|
pub struct RayDifferential {
|
|
pub rx_origin: Point3f,
|
|
pub ry_origin: Point3f,
|
|
pub rx_direction: Vector3f,
|
|
pub ry_direction: Vector3f,
|
|
}
|