pub mod bilinear; pub mod curves; pub mod cylinder; pub mod disk; pub mod sphere; pub mod triangle; use crate::core::interaction::{ Interaction, InteractionTrait, MediumInteraction, SurfaceInteraction, }; use crate::core::material::Material; use crate::core::medium::{Medium, MediumInterface}; use crate::core::pbrt::{Float, PI}; use crate::geometry::{ Bounds3f, DirectionCone, Normal3f, Point2f, Point3f, Point3fi, Ray, Vector2f, Vector3f, Vector3fi, VectorLike, }; use crate::lights::Light; use crate::utils::math::{next_float_down, next_float_up}; use crate::utils::transform::Transform; use enum_dispatch::enum_dispatch; use std::sync::{Arc, Mutex}; #[derive(Debug, Clone)] pub struct SphereShape { radius: Float, z_min: Float, z_max: Float, theta_z_min: Float, theta_z_max: Float, phi_max: Float, render_from_object: Arc>, object_from_render: Arc>, reverse_orientation: bool, transform_swap_handedness: bool, } impl Default for SphereShape { fn default() -> Self { Self::new( Transform::default().into(), Transform::default().into(), false, 1.0, -1.0, 1.0, 360.0, ) } } #[derive(Debug, Clone)] pub struct CylinderShape { radius: Float, z_min: Float, z_max: Float, phi_max: Float, render_from_object: Arc>, object_from_render: Arc>, reverse_orientation: bool, transform_swap_handedness: bool, } #[derive(Debug, Clone)] pub struct DiskShape { radius: Float, inner_radius: Float, height: Float, phi_max: Float, render_from_object: Arc>, object_from_render: Arc>, reverse_orientation: bool, transform_swap_handedness: bool, } #[derive(Debug, Clone)] pub struct TriangleShape { pub mesh_ind: usize, pub tri_index: usize, } #[derive(Debug, Clone)] pub struct BilinearPatchShape { mesh_index: usize, blp_index: usize, area: Float, rectangle: bool, } #[derive(Debug, Clone, PartialEq)] pub enum CurveType { Flat, Cylinder, Ribbon, } #[derive(Debug, Clone)] pub struct CurveCommon { curve_type: CurveType, cp_obj: [Point3f; 4], width: [Float; 2], n: [Normal3f; 2], normal_angle: Float, inv_sin_normal_angle: Float, render_from_object: Arc>, object_from_render: Arc>, reverse_orientation: bool, transform_swap_handedness: bool, } impl CurveCommon { #[allow(clippy::too_many_arguments)] pub fn new( c: &[Point3f], w0: Float, w1: Float, curve_type: CurveType, norm: &[Vector3f], render_from_object: Arc>, object_from_render: Arc>, reverse_orientation: bool, ) -> Self { let transform_swap_handedness = render_from_object.swaps_handedness(); let width = [w0, w1]; assert_eq!(c.len(), 4); let cp_obj: [Point3f; 4] = c[..4].try_into().unwrap(); let mut n = [Normal3f::default(); 2]; let mut normal_angle: Float = 0.; let mut inv_sin_normal_angle: Float = 0.; if norm.len() == 2 { n[0] = norm[0].normalize().into(); n[1] = norm[1].normalize().into(); normal_angle = n[0].angle_between(n[1]); inv_sin_normal_angle = 1. / normal_angle.sin(); } Self { curve_type, cp_obj, width, n, normal_angle, inv_sin_normal_angle, render_from_object, object_from_render, reverse_orientation, transform_swap_handedness, } } } #[derive(Debug, Clone)] pub struct CurveShape { common: CurveCommon, u_min: Float, u_max: Float, } // Define Intersection objects. This only varies for #[derive(Debug, Clone)] 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: Arc, area: Arc, prim_medium_interface: Option, ray_medium: Option>, ) { let ray_medium = ray_medium.expect("Ray medium must be defined for intersection"); self.intr .set_intersection_properties(mtl, area, prim_medium_interface, ray_medium); } } #[derive(Debug, Clone)] pub struct QuadricIntersection { t_hit: Float, p_obj: Point3f, phi: Float, } impl QuadricIntersection { pub fn new(t_hit: Float, p_obj: Point3f, phi: Float) -> Self { Self { t_hit, p_obj, phi } } } #[derive(Debug, Clone, Copy)] pub struct TriangleIntersection { b0: Float, b1: Float, b2: Float, t: Float, } impl TriangleIntersection { pub fn new(b0: Float, b1: Float, b2: Float, t: Float) -> Self { Self { b0, b1, b2, t } } } #[derive(Debug, Clone)] pub struct BilinearIntersection { uv: Point2f, t: Float, } impl BilinearIntersection { pub fn new(uv: Point2f, t: Float) -> Self { Self { uv, t } } } #[derive(Clone)] pub struct ShapeSample { pub intr: Arc, pub pdf: Float, } #[derive(Clone, Debug)] 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), None) } } #[enum_dispatch] pub trait ShapeTrait { fn bounds(&self) -> Bounds3f; fn normal_bounds(&self) -> DirectionCone; fn intersect(&self, ray: &Ray, t_max: Option) -> Option; fn intersect_p(&self, ray: &Ray, t_max: Option) -> bool; fn area(&self) -> Float; fn pdf(&self, interaction: &Interaction) -> Float; fn pdf_from_context(&self, ctx: &ShapeSampleContext, wi: Vector3f) -> Float; fn sample(&self, u: Point2f) -> Option; fn sample_from_context(&self, ctx: &ShapeSampleContext, u: Point2f) -> Option; } #[derive(Debug, Clone)] #[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()) } }