150 lines
4.8 KiB
Rust
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>)
|
|
// }
|