155 lines
4 KiB
Rust
155 lines
4 KiB
Rust
use crate::core::geometry::{
|
|
Bounds3f, DirectionCone, Normal3f, Point2f, Point3f, Point3fi, Ray, Vector2f, Vector3f,
|
|
Vector3fi, VectorLike, ray,
|
|
};
|
|
use crate::core::interaction::{
|
|
Interaction, InteractionTrait, MediumInteraction, SurfaceInteraction,
|
|
};
|
|
use crate::core::{MaterialIdx, LightIdx};
|
|
use crate::core::light::Light;
|
|
use crate::core::material::Material;
|
|
use crate::core::medium::{Medium, MediumInterface};
|
|
use crate::shapes::*;
|
|
use crate::utils::math::{next_float_down, next_float_up};
|
|
use crate::utils::{Ptr, Transform};
|
|
use crate::{Float, PI};
|
|
use enum_dispatch::enum_dispatch;
|
|
|
|
// Define Intersection objects. This only varies for
|
|
#[repr(C)]
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub struct ShapeIntersection {
|
|
pub intr: SurfaceInteraction,
|
|
pub t_hit: Float,
|
|
}
|
|
|
|
impl ShapeIntersection {
|
|
pub fn new(intr: SurfaceInteraction, t_hit: Float) -> Self {
|
|
Self { intr, t_hit }
|
|
}
|
|
|
|
pub fn t_hit(&self) -> Float {
|
|
self.t_hit
|
|
}
|
|
|
|
pub fn set_t_hit(&mut self, new_t: Float) {
|
|
self.t_hit = new_t;
|
|
}
|
|
|
|
pub fn set_intersection_properties(
|
|
&mut self,
|
|
mtl: MaterialIdx,
|
|
area: LightIdx,
|
|
prim_medium_interface: MediumInterface,
|
|
ray_medium: Ptr<Medium>,
|
|
) {
|
|
self.intr
|
|
.set_intersection_properties(mtl, area, ray_medium, prim_medium_interface);
|
|
}
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub struct QuadricIntersection {
|
|
pub t_hit: Float,
|
|
pub p_obj: Point3f,
|
|
pub phi: Float,
|
|
}
|
|
|
|
impl QuadricIntersection {
|
|
pub fn new(t_hit: Float, p_obj: Point3f, phi: Float) -> Self {
|
|
Self { t_hit, p_obj, phi }
|
|
}
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub struct ShapeSample {
|
|
pub intr: Interaction,
|
|
pub pdf: Float,
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub struct ShapeSampleContext {
|
|
pub pi: Point3fi,
|
|
pub n: Normal3f,
|
|
pub ns: Normal3f,
|
|
pub time: Float,
|
|
}
|
|
|
|
impl ShapeSampleContext {
|
|
pub fn new(pi: Point3fi, n: Normal3f, ns: Normal3f, time: Float) -> Self {
|
|
Self { pi, n, ns, time }
|
|
}
|
|
|
|
pub fn new_from_interaction(si: &SurfaceInteraction) -> Self {
|
|
Self {
|
|
pi: si.pi(),
|
|
n: si.n(),
|
|
ns: si.shading.n,
|
|
time: si.time(),
|
|
}
|
|
}
|
|
|
|
pub fn p(&self) -> Point3f {
|
|
Point3f::from(self.pi)
|
|
}
|
|
|
|
pub fn offset_ray_origin(&self, w: Vector3f) -> Point3f {
|
|
let d = self.n.abs().dot(self.pi.error().into());
|
|
let mut offset = d * Vector3f::from(self.n);
|
|
if w.dot(self.n.into()) < 0.0 {
|
|
offset = -offset;
|
|
}
|
|
|
|
let mut po = Point3f::from(self.pi) + offset;
|
|
for i in 0..3 {
|
|
if offset[i] > 0.0 {
|
|
po[i] = next_float_up(po[i]);
|
|
} else {
|
|
po[i] = next_float_down(po[i]);
|
|
}
|
|
}
|
|
po
|
|
}
|
|
|
|
pub fn offset_ray_origin_from_point(&self, pt: Point3f) -> Point3f {
|
|
self.offset_ray_origin(pt - self.p())
|
|
}
|
|
|
|
pub fn spawn_ray(&self, w: Vector3f) -> Ray {
|
|
Ray::new(self.offset_ray_origin(w), w, Some(self.time), Ptr::null())
|
|
}
|
|
}
|
|
|
|
#[enum_dispatch]
|
|
pub trait ShapeTrait {
|
|
fn bounds(&self) -> Bounds3f;
|
|
fn normal_bounds(&self) -> DirectionCone;
|
|
fn area(&self) -> Float;
|
|
fn sample(&self, u: Point2f) -> Option<ShapeSample>;
|
|
fn sample_from_context(&self, ctx: &ShapeSampleContext, u: Point2f) -> Option<ShapeSample>;
|
|
fn intersect(&self, ray: &Ray, t_max: Option<Float>) -> Option<ShapeIntersection>;
|
|
fn intersect_p(&self, ray: &Ray, t_max: Option<Float>) -> bool;
|
|
fn pdf(&self, interaction: &Interaction) -> Float;
|
|
fn pdf_from_context(&self, ctx: &ShapeSampleContext, wi: Vector3f) -> Float;
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Debug, Clone, Copy)]
|
|
#[enum_dispatch(ShapeTrait)]
|
|
pub enum Shape {
|
|
Sphere(SphereShape),
|
|
Cylinder(CylinderShape),
|
|
Disk(DiskShape),
|
|
Triangle(TriangleShape),
|
|
BilinearPatch(BilinearPatchShape),
|
|
Curve(CurveShape),
|
|
}
|
|
|
|
impl Default for Shape {
|
|
fn default() -> Self {
|
|
Shape::Sphere(SphereShape::default())
|
|
}
|
|
}
|