691 lines
21 KiB
Rust
691 lines
21 KiB
Rust
use crate::camera::{Camera, CameraTrait};
|
|
use crate::core::bssrdf::BSSRDF;
|
|
use crate::core::bxdf::{BSDF, BxDFFlags, DiffuseBxDF};
|
|
use crate::core::material::{
|
|
Material, MaterialEvalContext, MaterialTrait, NormalBumpEvalContext, bump_map, normal_map,
|
|
};
|
|
use crate::core::medium::{Medium, MediumInterface, PhaseFunction};
|
|
use crate::core::options::get_options;
|
|
use crate::core::pbrt::{Float, clamp_t};
|
|
use crate::core::sampler::{Sampler, SamplerTrait};
|
|
use crate::core::texture::{FloatTexture, UniversalTextureEvaluator};
|
|
use crate::geometry::{
|
|
Normal3f, Point2f, Point3f, Point3fi, Ray, RayDifferential, Vector3f, VectorLike,
|
|
};
|
|
use crate::image::Image;
|
|
use crate::lights::{Light, LightTrait};
|
|
use crate::shapes::Shape;
|
|
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
|
use crate::utils::math::{difference_of_products, square};
|
|
|
|
use bumpalo::Bump;
|
|
use enum_dispatch::enum_dispatch;
|
|
use std::any::Any;
|
|
use std::sync::Arc;
|
|
|
|
#[derive(Default, Clone, Debug)]
|
|
pub struct InteractionData {
|
|
pub pi: Point3fi,
|
|
pub n: Normal3f,
|
|
pub time: Float,
|
|
pub wo: Vector3f,
|
|
pub medium_interface: Option<MediumInterface>,
|
|
pub medium: Option<Arc<Medium>>,
|
|
}
|
|
|
|
#[enum_dispatch]
|
|
pub trait InteractionTrait: Send + Sync + std::fmt::Debug {
|
|
fn get_common(&self) -> &InteractionData;
|
|
fn get_common_mut(&mut self) -> &mut InteractionData;
|
|
|
|
fn p(&self) -> Point3f {
|
|
self.get_common().pi.into()
|
|
}
|
|
fn pi(&self) -> Point3fi {
|
|
self.get_common().pi
|
|
}
|
|
fn time(&self) -> Float {
|
|
self.get_common().time
|
|
}
|
|
fn wo(&self) -> Vector3f {
|
|
self.get_common().wo
|
|
}
|
|
|
|
fn n(&self) -> Normal3f {
|
|
self.get_common().n
|
|
}
|
|
|
|
fn is_surface_interaction(&self) -> bool {
|
|
false
|
|
}
|
|
|
|
fn is_medium_interaction(&self) -> bool {
|
|
false
|
|
}
|
|
|
|
fn get_medium(&self, w: Vector3f) -> Option<Arc<Medium>> {
|
|
let data = self.get_common();
|
|
if let Some(mi) = &data.medium_interface {
|
|
if w.dot(data.n.into()) > 0.0 {
|
|
mi.outside.clone()
|
|
} else {
|
|
mi.inside.clone()
|
|
}
|
|
} else {
|
|
data.medium.clone()
|
|
}
|
|
}
|
|
|
|
fn spawn_ray(&self, d: Vector3f) -> Ray {
|
|
let data = self.get_common();
|
|
let mut ray = Ray::spawn(&data.pi, &data.n, data.time, d);
|
|
|
|
ray.medium = self.get_medium(d);
|
|
ray
|
|
}
|
|
|
|
fn spawn_ray_to_point(&self, p2: Point3f) -> Ray {
|
|
let data = self.get_common();
|
|
let mut ray = Ray::spawn_to_point(&data.pi, &data.n, data.time, p2);
|
|
ray.medium = self.get_medium(ray.d);
|
|
ray
|
|
}
|
|
|
|
fn spawn_ray_to_interaction(&self, other: &dyn InteractionTrait) -> Ray {
|
|
let data = self.get_common();
|
|
let other_data = other.get_common();
|
|
|
|
let mut ray =
|
|
Ray::spawn_to_interaction(&data.pi, &data.n, data.time, &other_data.pi, &other_data.n);
|
|
ray.medium = self.get_medium(ray.d);
|
|
ray
|
|
}
|
|
|
|
fn offset_ray_vector(&self, w: Vector3f) -> Point3f {
|
|
Ray::offset_origin(&self.pi(), &self.n(), &w)
|
|
}
|
|
|
|
fn offset_ray_point(&self, pt: Point3f) -> Point3f {
|
|
self.offset_ray_vector(pt - self.p())
|
|
}
|
|
}
|
|
|
|
#[enum_dispatch(InteractionTrait)]
|
|
#[derive(Debug, Clone)]
|
|
pub enum Interaction {
|
|
Surface(SurfaceInteraction),
|
|
Medium(MediumInteraction),
|
|
Simple(SimpleInteraction),
|
|
}
|
|
|
|
impl Interaction {
|
|
pub fn set_medium_interface(&mut self, mi: Option<MediumInterface>) {
|
|
match self {
|
|
Interaction::Surface(si) => si.common.medium_interface = mi,
|
|
Interaction::Simple(si) => si.common.medium_interface = mi,
|
|
Interaction::Medium(_) => {} // Medium interactions don't usually sit on boundaries
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct SimpleInteraction {
|
|
pub common: InteractionData,
|
|
}
|
|
|
|
impl SimpleInteraction {
|
|
pub fn new(pi: Point3fi, time: Float, medium_interface: Option<MediumInterface>) -> Self {
|
|
Self {
|
|
common: InteractionData {
|
|
pi,
|
|
time,
|
|
medium_interface,
|
|
n: Normal3f::default(),
|
|
wo: Vector3f::default(),
|
|
medium: None,
|
|
},
|
|
}
|
|
}
|
|
|
|
pub fn new_interface(p: Point3f, medium_interface: Option<MediumInterface>) -> Self {
|
|
Self {
|
|
common: InteractionData {
|
|
pi: Point3fi::new_from_point(p),
|
|
n: Normal3f::zero(),
|
|
wo: Vector3f::zero(),
|
|
time: 0.0,
|
|
medium: None,
|
|
medium_interface,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl InteractionTrait for SimpleInteraction {
|
|
fn get_common(&self) -> &InteractionData {
|
|
&self.common
|
|
}
|
|
|
|
fn get_common_mut(&mut self) -> &mut InteractionData {
|
|
&mut self.common
|
|
}
|
|
}
|
|
|
|
#[derive(Default, Clone, Debug)]
|
|
pub struct ShadingGeometry {
|
|
pub n: Normal3f,
|
|
pub dpdu: Vector3f,
|
|
pub dpdv: Vector3f,
|
|
pub dndu: Normal3f,
|
|
pub dndv: Normal3f,
|
|
}
|
|
|
|
#[derive(Debug, Default, Clone)]
|
|
pub struct SurfaceInteraction {
|
|
pub common: InteractionData,
|
|
pub uv: Point2f,
|
|
pub dpdu: Vector3f,
|
|
pub dpdv: Vector3f,
|
|
pub dndu: Normal3f,
|
|
pub dndv: Normal3f,
|
|
pub shading: ShadingGeometry,
|
|
pub face_index: usize,
|
|
pub area_light: Option<Arc<Light>>,
|
|
pub material: Option<Arc<Material>>,
|
|
pub dpdx: Vector3f,
|
|
pub dpdy: Vector3f,
|
|
pub dudx: Float,
|
|
pub dvdx: Float,
|
|
pub dudy: Float,
|
|
pub dvdy: Float,
|
|
pub shape: Arc<Shape>,
|
|
}
|
|
|
|
impl SurfaceInteraction {
|
|
pub fn le(&self, w: Vector3f, lambda: &SampledWavelengths) -> SampledSpectrum {
|
|
if let Some(area_light) = &self.area_light {
|
|
area_light.l(self.p(), self.n(), self.uv, w, lambda)
|
|
} else {
|
|
SampledSpectrum::new(0.)
|
|
}
|
|
}
|
|
|
|
pub fn compute_differentials(&mut self, r: &Ray, camera: &Camera, samples_per_pixel: i32) {
|
|
let computed = if let Some(diff) = &r.differential {
|
|
let dot_rx = self.common.n.dot(diff.rx_direction.into());
|
|
let dot_ry = self.common.n.dot(diff.ry_direction.into());
|
|
|
|
if dot_rx != 0.0 && dot_ry != 0.0 {
|
|
// Estimate screen-space change in p using ray differentials>
|
|
let p_as_vec = Normal3f::new(self.p().x(), self.p().y(), self.p().z());
|
|
let d = -self.common.n.dot(p_as_vec);
|
|
|
|
// Compute t for x-auxiliary ray
|
|
let rx_origin_vec =
|
|
Normal3f::new(diff.rx_origin.x(), diff.rx_origin.y(), diff.rx_origin.z());
|
|
let tx = (-self.common.n.dot(rx_origin_vec) - d) / dot_rx;
|
|
|
|
// Compute intersection point px
|
|
let px = diff.rx_origin + diff.rx_direction * tx;
|
|
|
|
// Compute t for y-auxiliary ray
|
|
let ry_origin_vec =
|
|
Normal3f::new(diff.ry_origin.x(), diff.ry_origin.y(), diff.ry_origin.z());
|
|
let ty = (-self.common.n.dot(ry_origin_vec) - d) / dot_ry;
|
|
|
|
let py = diff.ry_origin + diff.ry_direction * ty;
|
|
|
|
self.dpdx = px - self.p();
|
|
self.dpdy = py - self.p();
|
|
|
|
true
|
|
} else {
|
|
false
|
|
}
|
|
} else {
|
|
false
|
|
};
|
|
|
|
if !computed {
|
|
camera.approximate_dp_dxy(
|
|
self.p(),
|
|
self.n(),
|
|
self.time(),
|
|
samples_per_pixel,
|
|
&mut self.dpdx,
|
|
&mut self.dpdy,
|
|
);
|
|
}
|
|
|
|
let ata00 = self.dpdu.dot(self.dpdu);
|
|
let ata01 = self.dpdu.dot(self.dpdv);
|
|
let ata11 = self.dpdv.dot(self.dpdv);
|
|
let mut inv_det = 1. / difference_of_products(ata00, ata11, ata01, ata01);
|
|
inv_det = if inv_det.is_finite() { inv_det } else { 0. };
|
|
let atb0x = self.dpdu.dot(self.dpdx);
|
|
let atb1x = self.dpdv.dot(self.dpdx);
|
|
let atb0y = self.dpdu.dot(self.dpdy);
|
|
let atb1y = self.dpdv.dot(self.dpdy);
|
|
// Compute u and v derivatives in x and y
|
|
self.dudx = difference_of_products(ata11, atb0x, ata01, atb1x) * inv_det;
|
|
self.dvdx = difference_of_products(ata00, atb1x, ata01, atb0x) * inv_det;
|
|
self.dudy = difference_of_products(ata11, atb0y, ata01, atb1y) * inv_det;
|
|
self.dvdy = difference_of_products(ata00, atb1y, ata01, atb0y) * inv_det;
|
|
// Clamp derivatives
|
|
self.dudx = if self.dudx.is_finite() {
|
|
clamp_t(self.dudx, -1e8, 1e8)
|
|
} else {
|
|
0.
|
|
};
|
|
self.dvdx = if self.dvdx.is_finite() {
|
|
clamp_t(self.dvdx, -1e8, 1e8)
|
|
} else {
|
|
0.
|
|
};
|
|
self.dudy = if self.dudy.is_finite() {
|
|
clamp_t(self.dudy, -1e8, 1e8)
|
|
} else {
|
|
0.
|
|
};
|
|
self.dvdy = if self.dvdy.is_finite() {
|
|
clamp_t(self.dvdy, -1e8, 1e8)
|
|
} else {
|
|
0.
|
|
};
|
|
}
|
|
|
|
pub fn skip_intersection(&self, ray: &mut Ray, t: Float) {
|
|
let new_ray = Ray::spawn(&self.pi(), &self.n(), ray.time, ray.d);
|
|
ray.o = new_ray.o;
|
|
// Skipping other variables, since they should not change when passing through surface
|
|
if let Some(diff) = &mut ray.differential {
|
|
diff.rx_origin += diff.rx_direction * t;
|
|
diff.ry_origin += diff.ry_direction * t;
|
|
}
|
|
}
|
|
|
|
pub fn get_bsdf<'a>(
|
|
&mut self,
|
|
r: &Ray,
|
|
lambda: &SampledWavelengths,
|
|
camera: &Camera,
|
|
scratch: &'a Bump,
|
|
sampler: &mut Sampler,
|
|
) -> Option<BSDF<'a>> {
|
|
self.compute_differentials(r, camera, sampler.samples_per_pixel() as i32);
|
|
|
|
let material = {
|
|
let root_mat = self.material.as_deref()?;
|
|
let mut active_mat: &Material = root_mat;
|
|
let tex_eval = UniversalTextureEvaluator;
|
|
while let Material::Mix(mix) = active_mat {
|
|
// We need a context to evaluate the 'amount' texture
|
|
let ctx = MaterialEvalContext::from(&*self);
|
|
active_mat = mix.choose_material(&tex_eval, &ctx);
|
|
}
|
|
active_mat.clone()
|
|
};
|
|
|
|
let ctx = MaterialEvalContext::from(&*self);
|
|
let tex_eval = UniversalTextureEvaluator;
|
|
let displacement = material.get_displacement();
|
|
let normal_map = material.get_normal_map();
|
|
if displacement.is_some() || normal_map.is_some() {
|
|
// This calls the function defined above
|
|
self.compute_bump_geometry(&tex_eval, displacement, normal_map);
|
|
}
|
|
|
|
let mut bsdf = material.get_bxdf(&tex_eval, &ctx, lambda, scratch);
|
|
if get_options().force_diffuse {
|
|
let r = bsdf.rho_wo(self.common.wo, &[sampler.get1d()], &[sampler.get2d()]);
|
|
let diff_bxdf = scratch.alloc(DiffuseBxDF::new(r));
|
|
bsdf = BSDF::new(self.shading.n, self.shading.dpdu, Some(diff_bxdf));
|
|
}
|
|
Some(bsdf)
|
|
}
|
|
|
|
pub fn get_bssrdf(
|
|
&self,
|
|
_ray: &Ray,
|
|
lambda: &SampledWavelengths,
|
|
_camera: &Camera,
|
|
_scratch: &Bump,
|
|
) -> Option<BSSRDF<'_>> {
|
|
let material = {
|
|
let root_mat = self.material.as_deref()?;
|
|
let mut active_mat: &Material = root_mat;
|
|
let tex_eval = UniversalTextureEvaluator;
|
|
while let Material::Mix(mix) = active_mat {
|
|
// We need a context to evaluate the 'amount' texture
|
|
let ctx = MaterialEvalContext::from(self);
|
|
active_mat = mix.choose_material(&tex_eval, &ctx);
|
|
}
|
|
active_mat.clone()
|
|
};
|
|
|
|
let ctx = MaterialEvalContext::from(self);
|
|
let tex_eval = UniversalTextureEvaluator;
|
|
material.get_bssrdf(&tex_eval, &ctx, lambda)
|
|
}
|
|
|
|
fn compute_bump_geometry(
|
|
&mut self,
|
|
tex_eval: &UniversalTextureEvaluator,
|
|
displacement: Option<FloatTexture>,
|
|
normal_image: Option<&Image>,
|
|
) {
|
|
let ctx = NormalBumpEvalContext::from(&*self);
|
|
let (dpdu, dpdv) = if let Some(disp) = displacement {
|
|
bump_map(tex_eval, &disp, &ctx)
|
|
} else if let Some(map) = normal_image {
|
|
normal_map(map, &ctx)
|
|
} else {
|
|
(self.shading.dpdu, self.shading.dpdv)
|
|
};
|
|
|
|
let mut ns = Normal3f::from(dpdu.cross(dpdv).normalize());
|
|
if ns.dot(self.n()) < 0.0 {
|
|
ns = -ns;
|
|
}
|
|
|
|
self.set_shading_geometry(ns, dpdu, dpdv, self.shading.dndu, self.shading.dndv, false);
|
|
}
|
|
|
|
pub fn spawn_ray_with_differentials(
|
|
&self,
|
|
ray_i: &Ray,
|
|
wi: Vector3f,
|
|
flags: BxDFFlags,
|
|
eta: Float,
|
|
) -> Ray {
|
|
let mut rd = self.spawn_ray(wi);
|
|
|
|
if let Some(diff_i) = &ray_i.differential {
|
|
let mut n = self.shading.n;
|
|
|
|
let mut dndx = self.shading.dndu * self.dudx + self.shading.dndv * self.dvdx;
|
|
let mut dndy = self.shading.dndu * self.dudy + self.shading.dndv * self.dvdy;
|
|
|
|
let dwodx = -diff_i.rx_direction - self.wo();
|
|
let dwody = -diff_i.ry_direction - self.wo();
|
|
|
|
let new_diff_rx_origin = self.p() + self.dpdx;
|
|
let new_diff_ry_origin = self.p() + self.dpdy;
|
|
let mut new_diff_rx_dir = Vector3f::default();
|
|
let mut new_diff_ry_dir = Vector3f::default();
|
|
|
|
let mut valid_differentials = false;
|
|
|
|
if flags.contains(BxDFFlags::SPECULAR_REFLECTION) {
|
|
valid_differentials = true;
|
|
|
|
let d_wo_dot_n_dx = dwodx.dot(n.into()) + self.wo().dot(dndx.into());
|
|
let d_wo_dot_n_dy = dwody.dot(n.into()) + self.wo().dot(dndy.into());
|
|
|
|
let wo_dot_n = self.wo().dot(n.into());
|
|
|
|
new_diff_rx_dir = wi - dwodx
|
|
+ (Vector3f::from(dndx) * wo_dot_n + Vector3f::from(n) * d_wo_dot_n_dx) * 2.0;
|
|
|
|
new_diff_ry_dir = wi - dwody
|
|
+ (Vector3f::from(dndy) * wo_dot_n + Vector3f::from(n) * d_wo_dot_n_dy) * 2.0;
|
|
} else if flags.contains(BxDFFlags::SPECULAR_TRANSMISSION) {
|
|
valid_differentials = true;
|
|
|
|
if self.wo().dot(n.into()) < 0.0 {
|
|
n = -n;
|
|
dndx = -dndx;
|
|
dndy = -dndy;
|
|
}
|
|
|
|
// Compute partial derivatives
|
|
let d_wo_dot_n_dx = dwodx.dot(n.into()) + self.wo().dot(dndx.into());
|
|
let d_wo_dot_n_dy = dwody.dot(n.into()) + self.wo().dot(dndy.into());
|
|
|
|
let wo_dot_n = self.wo().dot(n.into());
|
|
let wi_dot_n = wi.dot(Vector3f::from(n));
|
|
let abs_wi_dot_n = wi.abs_dot(n.into());
|
|
|
|
let mu = wo_dot_n / eta - abs_wi_dot_n;
|
|
|
|
let f_eta = 1.0 / eta;
|
|
let f_eta2 = 1.0 / square(eta);
|
|
|
|
let term = f_eta + (f_eta2 * wo_dot_n / wi_dot_n);
|
|
|
|
let dmudx = d_wo_dot_n_dx * term;
|
|
let dmudy = d_wo_dot_n_dy * term;
|
|
|
|
new_diff_rx_dir =
|
|
wi - dwodx * eta + (Vector3f::from(dndx) * mu + Vector3f::from(n) * dmudx);
|
|
new_diff_ry_dir =
|
|
wi - dwody * eta + (Vector3f::from(dndy) * mu + Vector3f::from(n) * dmudy);
|
|
}
|
|
|
|
if valid_differentials {
|
|
let threshold = 1e16;
|
|
|
|
if new_diff_rx_dir.norm_squared() > threshold
|
|
|| new_diff_ry_dir.norm_squared() > threshold
|
|
|| Vector3f::from(new_diff_rx_origin).norm_squared() > threshold
|
|
|| Vector3f::from(new_diff_ry_origin).norm_squared() > threshold
|
|
{
|
|
rd.differential = None;
|
|
} else {
|
|
rd.differential = Some(RayDifferential {
|
|
rx_origin: new_diff_rx_origin,
|
|
ry_origin: new_diff_ry_origin,
|
|
rx_direction: new_diff_rx_dir,
|
|
ry_direction: new_diff_ry_dir,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
rd
|
|
}
|
|
}
|
|
|
|
impl InteractionTrait for SurfaceInteraction {
|
|
fn get_common(&self) -> &InteractionData {
|
|
&self.common
|
|
}
|
|
|
|
fn get_common_mut(&mut self) -> &mut InteractionData {
|
|
&mut self.common
|
|
}
|
|
|
|
fn get_medium(&self, w: Vector3f) -> Option<Arc<Medium>> {
|
|
self.common.medium_interface.as_ref().and_then(|interface| {
|
|
if self.n().dot(w.into()) > 0.0 {
|
|
interface.outside.clone()
|
|
} else {
|
|
interface.inside.clone()
|
|
}
|
|
})
|
|
}
|
|
|
|
fn is_surface_interaction(&self) -> bool {
|
|
true
|
|
}
|
|
}
|
|
|
|
impl SurfaceInteraction {
|
|
pub fn new(
|
|
pi: Point3fi,
|
|
uv: Point2f,
|
|
wo: Vector3f,
|
|
dpdu: Vector3f,
|
|
dpdv: Vector3f,
|
|
dndu: Normal3f,
|
|
dndv: Normal3f,
|
|
time: Float,
|
|
flip: bool,
|
|
) -> Self {
|
|
let mut n = Normal3f::from(dpdu.cross(dpdv).normalize());
|
|
let mut shading_n = n;
|
|
|
|
if flip {
|
|
n *= -1.0;
|
|
shading_n *= -1.0;
|
|
}
|
|
|
|
Self {
|
|
common: InteractionData {
|
|
pi,
|
|
n,
|
|
time,
|
|
wo,
|
|
medium_interface: None,
|
|
medium: None,
|
|
},
|
|
uv,
|
|
dpdu,
|
|
dpdv,
|
|
dndu,
|
|
dndv,
|
|
shading: ShadingGeometry {
|
|
n: shading_n,
|
|
dpdu,
|
|
dpdv,
|
|
dndu,
|
|
dndv,
|
|
},
|
|
material: None,
|
|
face_index: 0,
|
|
area_light: None,
|
|
dpdx: Vector3f::zero(),
|
|
dpdy: Vector3f::zero(),
|
|
dudx: 0.0,
|
|
dudy: 0.0,
|
|
dvdx: 0.0,
|
|
dvdy: 0.0,
|
|
shape: Arc::new(Shape::default()),
|
|
}
|
|
}
|
|
|
|
pub fn new_with_face(
|
|
pi: Point3fi,
|
|
uv: Point2f,
|
|
wo: Vector3f,
|
|
dpdu: Vector3f,
|
|
dpdv: Vector3f,
|
|
dndu: Normal3f,
|
|
dndv: Normal3f,
|
|
time: Float,
|
|
flip: bool,
|
|
face_index: usize,
|
|
) -> Self {
|
|
let mut si = Self::new(pi, uv, wo, dpdu, dpdv, dndu, dndv, time, flip);
|
|
si.face_index = face_index;
|
|
si
|
|
}
|
|
|
|
pub fn set_shading_geometry(
|
|
&mut self,
|
|
ns: Normal3f,
|
|
dpdus: Vector3f,
|
|
dpdvs: Vector3f,
|
|
dndus: Normal3f,
|
|
dndvs: Normal3f,
|
|
orientation: bool,
|
|
) {
|
|
self.shading.n = ns;
|
|
if orientation {
|
|
self.common.n = self.n().face_forward(self.shading.n.into());
|
|
}
|
|
self.shading.dpdu = dpdus;
|
|
self.shading.dpdv = dpdvs;
|
|
self.shading.dndu = dndus;
|
|
self.shading.dndv = dndvs;
|
|
}
|
|
|
|
pub fn new_simple(pi: Point3fi, n: Normal3f, uv: Point2f) -> Self {
|
|
Self {
|
|
common: InteractionData {
|
|
pi,
|
|
n,
|
|
time: 0.,
|
|
wo: Vector3f::zero(),
|
|
medium_interface: None,
|
|
medium: None,
|
|
},
|
|
uv,
|
|
..Default::default()
|
|
}
|
|
}
|
|
|
|
pub fn new_minimal(pi: Point3fi, uv: Point2f) -> Self {
|
|
Self {
|
|
common: InteractionData {
|
|
pi,
|
|
..Default::default()
|
|
},
|
|
uv,
|
|
..Default::default()
|
|
}
|
|
}
|
|
|
|
pub fn set_intersection_properties(
|
|
&mut self,
|
|
mtl: Arc<Material>,
|
|
area: Arc<Light>,
|
|
prim_medium_interface: Option<MediumInterface>,
|
|
ray_medium: Arc<Medium>,
|
|
) {
|
|
self.material = Some(mtl);
|
|
self.area_light = Some(area);
|
|
if prim_medium_interface
|
|
.as_ref()
|
|
.is_some_and(|mi| mi.is_medium_transition())
|
|
{
|
|
self.common.medium_interface = prim_medium_interface;
|
|
} else {
|
|
self.common.medium = Some(ray_medium);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct MediumInteraction {
|
|
pub common: InteractionData,
|
|
pub medium: Arc<Medium>,
|
|
pub phase: PhaseFunction,
|
|
}
|
|
|
|
impl MediumInteraction {
|
|
pub fn new(
|
|
p: Point3f,
|
|
wo: Vector3f,
|
|
time: Float,
|
|
medium: Arc<Medium>,
|
|
phase: PhaseFunction,
|
|
) -> Self {
|
|
Self {
|
|
common: InteractionData {
|
|
pi: Point3fi::new_from_point(p),
|
|
n: Normal3f::default(),
|
|
time,
|
|
wo: wo.normalize(),
|
|
medium_interface: None,
|
|
medium: Some(medium.clone()),
|
|
},
|
|
medium,
|
|
phase,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl InteractionTrait for MediumInteraction {
|
|
fn is_medium_interaction(&self) -> bool {
|
|
true
|
|
}
|
|
|
|
fn get_common(&self) -> &InteractionData {
|
|
&self.common
|
|
}
|
|
|
|
fn get_common_mut(&mut self) -> &mut InteractionData {
|
|
&mut self.common
|
|
}
|
|
}
|