pbrt/src/core/primitive.rs
2025-11-19 21:59:15 +00:00

150 lines
4.8 KiB
Rust

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<Float>) -> Option<ShapeIntersection>;
fn intersect_p(&self, r: &Ray, t_max: Option<Float>) -> bool;
}
#[derive(Debug, Clone)]
pub struct GeometricPrimitive {
shape: Arc<Shape>,
material: Arc<dyn MaterialTrait>,
area_light: Arc<Light>,
medium_interface: Arc<MediumInterface>,
alpha: Option<Arc<dyn FloatTextureTrait>>,
}
impl PrimitiveTrait for GeometricPrimitive {
fn bounds(&self) -> Bounds3f {
self.shape.bounds()
}
fn intersect(&self, r: &Ray, t_max: Option<Float>) -> Option<ShapeIntersection> {
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::<SurfaceInteraction>() {
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<Float>) -> 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<Shape>,
material: Arc<dyn MaterialTrait>,
}
#[derive(Debug, Clone)]
pub struct TransformedPrimitive {
primitive: Arc<dyn PrimitiveTrait>,
render_from_primitive: Transform<Float>,
}
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<Float>) -> Option<ShapeIntersection> {
todo!()
}
fn intersect_p(&self, _r: &Ray, _t_max: Option<Float>) -> bool {
todo!()
}
}
#[derive(Debug, Clone)]
pub struct AnimatedPrimitive {
primitive: Arc<dyn PrimitiveTrait>,
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<Float>) -> Option<ShapeIntersection> {
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::<SurfaceInteraction>().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<f64>,
// }
//
//
// impl GeometricPrimitive {
// fn new(shape: Shape, material: Material, medium_interface: MediumInterface, alpha: Texture<f64>)
// }