pbrt/shared/src/core/geometry/ray.rs
2026-05-21 15:05:36 +01:00

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,
}