use crate::core::interaction::{Interaction, SurfaceInteraction}; use crate::core::pbrt::Float; use crate::geometry::{Bounds3f, Ray}; use crate::shapes::{ShapeIntersection, Shape}; use crate::core::material::MaterialTrait; use crate::core::medium::MediumInterface; use crate::lights::Light; use crate::core::texture::{FloatTextureTrait, TextureEvalContext}; use crate::utils::hash::hash_float; use crate::utils::transform::{AnimatedTransform, Transform}; use std::sync::Arc; pub trait PrimitiveTrait: Send + Sync + std::fmt::Debug { fn bounds(&self) -> Bounds3f; fn intersect(&self, r: &Ray, t_max: Option) -> Option; fn intersect_p(&self, r: &Ray, t_max: Option) -> bool; } #[derive(Debug, Clone)] pub struct GeometricPrimitive { shape: Arc, material: Arc, area_light: Arc, medium_interface: Arc, alpha: Option>, } impl PrimitiveTrait for GeometricPrimitive { fn bounds(&self) -> Bounds3f { self.shape.bounds() } fn intersect(&self, r: &Ray, t_max: Option) -> Option { let mut si = self.shape.intersect(r, t_max)?; let ctx: TextureEvalContext = si.intr().into(); let Some(ref alpha) = self.alpha else { return None }; let a = alpha.evaluate(&ctx); if a < 1. { let u = if a <= 0. { 1. } else { hash_float((r.o, r.d)) }; if u > a { let r_next = si.intr().spawn_ray(r.d); let new_t_max = t_max.map(|t| t - si.t_hit())?; let mut si_next = self.intersect(&r_next, Some(new_t_max - si.t_hit()))?; si_next.set_t_hit(si_next.t_hit() + si.t_hit()); return Some(si_next) } } if let Some(si) = si.intr().downcast_mut::() { si.as_ref().set_intersection_properties(self.material.clone(), self.area_light.clone(), Some(self.medium_interface.clone()), r.medium.clone()?); } Some(si) } fn intersect_p(&self, r: &Ray, t_max: Option) -> bool { if self.alpha.is_some() { self.intersect(r, t_max).is_some() } else { self.shape.intersect_p(r, t_max) } } } #[derive(Debug, Clone)] pub struct SimplePrimitiv { shape: Arc, material: Arc, } #[derive(Debug, Clone)] pub struct TransformedPrimitive { primitive: Arc, render_from_primitive: Transform, } impl PrimitiveTrait for TransformedPrimitive { fn bounds(&self) -> Bounds3f { self.render_from_primitive.apply_to_bounds(self.primitive.bounds()) } fn intersect(&self, _r: &Ray, _t_max: Option) -> Option { todo!() } fn intersect_p(&self, _r: &Ray, _t_max: Option) -> bool { todo!() } } #[derive(Debug, Clone)] pub struct AnimatedPrimitive { primitive: Arc, render_from_primitive: AnimatedTransform } impl PrimitiveTrait for AnimatedPrimitive { fn bounds(&self) -> Bounds3f { self.render_from_primitive.motion_bounds(&self.primitive.bounds()) } fn intersect(&self, r: &Ray, t_max: Option) -> Option { let interp_render_from_primitive = self.render_from_primitive.interpolate(r.time); let ray = interp_render_from_primitive.apply_inverse_ray(r, t_max); let mut si = self.primitive.intersect(r, t_max) else { return None }; let new_render = interp_render_from_primitive.apply_to_interaction(si?.intr()); let transform = new_render.as_any().downcast_mut::().expect( "Failed to downcast Interaction to SurfaceInteraction. This should not happen." ); *si?.intr = new_render; si } } pub struct BVHAggregatePrimitive; pub struct KdTreeAggregate; pub enum Primitive { Geometric(GeometricPrimitive), Transformed(TransformedPrimitive), Animated(AnimatedPrimitive), BVH(BVHAggregatePrimitive), KdTree(KdTreeAggregate), } impl Primitive { // pub fn bounds(&self) -> Bounds3f { // match self { // Primitive::Geometric(primitive) => primitive.bounds(), // Primitive::Transformed(primitive) => primitive.bounds(), // Primitive::Animated(primitive) => primitive.bounds(), // Primitive::BVH(primitive) => primitive.bounds(), // Primitive::KdTree(primitive) => primitive.bounds(), // } // } } // struct GeometricPrimitive { // shape: Shape, // material: Material, // area_light: Light, // medium_interface: MediumInterface, // alpha: Texture, // } // // // impl GeometricPrimitive { // fn new(shape: Shape, material: Material, medium_interface: MediumInterface, alpha: Texture) // }