use std::sync::Arc;
use crate::core::camera::Camera;
use crate::core::geometry::{vec3_abs_dot_nrmf, vec3_dot_nrmf};
use crate::core::geometry::{Bounds2i, Normal3f, Ray, RayDifferential, Vector3f};
use crate::core::integrator::{uniform_sample_all_lights, uniform_sample_one_light};
use crate::core::interaction::{Interaction, SurfaceInteraction};
use crate::core::material::TransportMode;
use crate::core::pbrt::{Float, Spectrum};
use crate::core::reflection::BxdfType;
use crate::core::sampler::Sampler;
use crate::core::scene::Scene;
#[derive(Debug, Clone, PartialEq)]
pub enum LightStrategy {
UniformSampleAll,
UniformSampleOne,
}
pub struct DirectLightingIntegrator {
pub camera: Arc<Camera>,
pub sampler: Box<Sampler>,
pixel_bounds: Bounds2i,
strategy: LightStrategy,
max_depth: u32,
n_light_samples: Vec<i32>,
}
impl DirectLightingIntegrator {
pub fn new(
strategy: LightStrategy,
max_depth: u32,
camera: Arc<Camera>,
sampler: Box<Sampler>,
pixel_bounds: Bounds2i,
) -> Self {
DirectLightingIntegrator {
camera,
sampler,
pixel_bounds,
strategy,
max_depth,
n_light_samples: Vec::new(),
}
}
pub fn preprocess(&mut self, scene: &Scene) {
if self.strategy == LightStrategy::UniformSampleAll {
for li in 0..scene.lights.len() {
let light = &scene.lights[li];
self.n_light_samples
.push(self.sampler.round_count(light.get_n_samples()));
}
for _i in 0..self.max_depth {
for j in 0..scene.lights.len() {
self.sampler.request_2d_array(self.n_light_samples[j]);
self.sampler.request_2d_array(self.n_light_samples[j]);
}
}
}
}
pub fn li(
&self,
ray: &Ray,
scene: &Scene,
sampler: &mut Sampler,
depth: i32,
) -> Spectrum {
let mut l: Spectrum = Spectrum::new(0.0 as Float);
let mut isect: SurfaceInteraction = SurfaceInteraction::default();
if scene.intersect(ray, &mut isect) {
let mode: TransportMode = TransportMode::Radiance;
isect.compute_scattering_functions(ray, false, mode);
if isect.bsdf.is_none() {
return self.li(&mut isect.spawn_ray(&ray.d), scene, sampler, depth);
}
let wo: Vector3f = isect.common.wo;
l += isect.le(&wo);
if !scene.lights.is_empty() {
if self.strategy == LightStrategy::UniformSampleAll {
l += uniform_sample_all_lights(
&isect,
scene,
sampler,
&self.n_light_samples,
false,
);
} else {
l += uniform_sample_one_light(&isect, scene, sampler, false, None);
}
}
if ((depth + 1_i32) as u32) < self.max_depth {
l += self.specular_reflect(
ray, &isect, scene, sampler, depth,
);
l += self.specular_transmit(
ray, &isect, scene, sampler, depth,
);
}
} else {
for light in &scene.lights {
l += light.le(ray);
}
}
l
}
pub fn get_camera(&self) -> Arc<Camera> {
self.camera.clone()
}
pub fn get_sampler(&self) -> &Sampler {
&self.sampler
}
pub fn get_pixel_bounds(&self) -> Bounds2i {
self.pixel_bounds
}
pub fn specular_reflect(
&self,
ray: &Ray,
isect: &SurfaceInteraction,
scene: &Scene,
sampler: &mut Sampler,
depth: i32,
) -> Spectrum {
let wo: Vector3f = isect.common.wo;
let mut wi: Vector3f = Vector3f::default();
let mut pdf: Float = 0.0 as Float;
let ns: Normal3f = isect.shading.n;
let mut sampled_type: u8 = 0_u8;
let bsdf_flags: u8 = BxdfType::BsdfReflection as u8 | BxdfType::BsdfSpecular as u8;
let f: Spectrum;
if let Some(ref bsdf) = isect.bsdf {
f = bsdf.sample_f(
&wo,
&mut wi,
&sampler.get_2d(),
&mut pdf,
bsdf_flags,
&mut sampled_type,
);
if pdf > 0.0 as Float && !f.is_black() && vec3_abs_dot_nrmf(&wi, &ns) != 0.0 as Float {
let mut rd: Ray = isect.spawn_ray(&wi);
if let Some(d) = ray.differential.iter().next() {
let dndx: Normal3f = isect.shading.dndu * isect.dudx.get()
+ isect.shading.dndv * isect.dvdx.get();
let dndy: Normal3f = isect.shading.dndu * isect.dudy.get()
+ isect.shading.dndv * isect.dvdy.get();
let dwodx: Vector3f = -d.rx_direction - wo;
let dwody: Vector3f = -d.ry_direction - wo;
let ddndx: Float = vec3_dot_nrmf(&dwodx, &ns) + vec3_dot_nrmf(&wo, &dndx);
let ddndy: Float = vec3_dot_nrmf(&dwody, &ns) + vec3_dot_nrmf(&wo, &dndy);
let diff: RayDifferential = RayDifferential {
rx_origin: isect.common.p + isect.dpdx.get(),
ry_origin: isect.common.p + isect.dpdy.get(),
rx_direction: wi - dwodx
+ Vector3f::from(dndx * vec3_dot_nrmf(&wo, &ns) + ns * ddndx)
* 2.0 as Float,
ry_direction: wi - dwody
+ Vector3f::from(dndy * vec3_dot_nrmf(&wo, &ns) + ns * ddndy)
* 2.0 as Float,
};
rd.differential = Some(diff);
}
f * self.li(&mut rd, scene, sampler, depth + 1)
* Spectrum::new(vec3_abs_dot_nrmf(&wi, &ns) / pdf)
} else {
Spectrum::new(0.0)
}
} else {
Spectrum::new(0.0)
}
}
pub fn specular_transmit(
&self,
ray: &Ray,
isect: &SurfaceInteraction,
scene: &Scene,
sampler: &mut Sampler,
depth: i32,
) -> Spectrum {
let wo: Vector3f = isect.common.wo;
let mut wi: Vector3f = Vector3f::default();
let mut pdf: Float = 0.0 as Float;
let ns: Normal3f = isect.shading.n;
let mut sampled_type: u8 = 0_u8;
let bsdf_flags: u8 = BxdfType::BsdfTransmission as u8 | BxdfType::BsdfSpecular as u8;
let f: Spectrum;
if let Some(ref bsdf) = isect.bsdf {
f = bsdf.sample_f(
&wo,
&mut wi,
&sampler.get_2d(),
&mut pdf,
bsdf_flags,
&mut sampled_type,
);
if pdf > 0.0 as Float && !f.is_black() && vec3_abs_dot_nrmf(&wi, &ns) != 0.0 as Float {
let mut rd: Ray = isect.spawn_ray(&wi);
if let Some(d) = ray.differential.iter().next() {
let mut eta: Float = bsdf.eta;
let w: Vector3f = -wo;
if vec3_dot_nrmf(&wo, &ns) < 0.0 as Float {
eta = 1.0 / eta;
}
let dndx: Normal3f = isect.shading.dndu * isect.dudx.get()
+ isect.shading.dndv * isect.dvdx.get();
let dndy: Normal3f = isect.shading.dndu * isect.dudy.get()
+ isect.shading.dndv * isect.dvdy.get();
let dwodx: Vector3f = -d.rx_direction - wo;
let dwody: Vector3f = -d.ry_direction - wo;
let ddndx: Float = vec3_dot_nrmf(&dwodx, &ns) + vec3_dot_nrmf(&wo, &dndx);
let ddndy: Float = vec3_dot_nrmf(&dwody, &ns) + vec3_dot_nrmf(&wo, &dndy);
let mu: Float = eta * vec3_dot_nrmf(&w, &ns) - vec3_dot_nrmf(&wi, &ns);
let dmudx: Float = (eta
- (eta * eta * vec3_dot_nrmf(&w, &ns)) / vec3_dot_nrmf(&wi, &ns))
* ddndx;
let dmudy: Float = (eta
- (eta * eta * vec3_dot_nrmf(&w, &ns)) / vec3_dot_nrmf(&wi, &ns))
* ddndy;
let diff: RayDifferential = RayDifferential {
rx_origin: isect.common.p + isect.dpdx.get(),
ry_origin: isect.common.p + isect.dpdy.get(),
rx_direction: wi + dwodx * eta - Vector3f::from(dndx * mu + ns * dmudx),
ry_direction: wi + dwody * eta - Vector3f::from(dndy * mu + ns * dmudy),
};
rd.differential = Some(diff);
}
f * self.li(&mut rd, scene, sampler, depth + 1)
* Spectrum::new(vec3_abs_dot_nrmf(&wi, &ns) / pdf)
} else {
Spectrum::new(0.0)
}
} else {
Spectrum::new(0.0)
}
}
}