use std::f32::consts::PI;
use std::sync::Arc;
use crate::core::geometry::{nrm_abs_dot_vec3f, nrm_dot_vec3f, vec3_coordinate_system};
use crate::core::geometry::{Normal3f, Point2f, Ray, Vector3f, XYEnum};
use crate::core::interaction::{Interaction, InteractionCommon};
use crate::core::light::{LightFlags, VisibilityTester};
use crate::core::medium::{Medium, MediumInterface};
use crate::core::pbrt::{Float, Spectrum};
use crate::core::rng::FLOAT_ONE_MINUS_EPSILON;
use crate::core::sampling::{cosine_hemisphere_pdf, cosine_sample_hemisphere};
use crate::core::scene::Scene;
use crate::core::shape::Shape;
use crate::core::transform::Transform;
pub struct DiffuseAreaLight {
pub l_emit: Spectrum,
pub shape: Arc<Shape>,
pub two_sided: bool,
pub area: Float,
pub flags: u8,
pub n_samples: i32,
pub medium_interface: MediumInterface,
}
impl DiffuseAreaLight {
pub fn new(
_light_to_world: &Transform,
medium_interface: &MediumInterface,
l_emit: &Spectrum,
n_samples: i32,
shape: Arc<Shape>,
two_sided: bool,
) -> Self {
let area: Float = shape.area();
let mut inside: Option<Arc<Medium>> = None;
let mut outside: Option<Arc<Medium>> = None;
if let Some(ref mi_inside) = medium_interface.inside {
inside = Some(mi_inside.clone());
}
if let Some(ref mi_outside) = medium_interface.outside {
outside = Some(mi_outside.clone());
}
DiffuseAreaLight {
l_emit: *l_emit,
shape,
two_sided,
area,
flags: LightFlags::Area as u8,
n_samples: std::cmp::max(1_i32, n_samples),
medium_interface: MediumInterface { inside, outside },
}
}
pub fn sample_li<'a, 'b>(
&'b self,
iref: &'a InteractionCommon,
light_intr: &'b mut InteractionCommon,
u: Point2f,
wi: &mut Vector3f,
pdf: &mut Float,
vis: &mut VisibilityTester<'a, 'b>,
) -> Spectrum {
*light_intr = self.shape.sample_with_ref_point(iref, u, pdf);
if *pdf == 0.0 as Float || (light_intr.p - iref.p).length_squared() == 0.0 as Float {
*pdf = 0.0 as Float;
return Spectrum::default();
}
*wi = (light_intr.p - iref.p).normalize();
vis.p0 = Some(&iref);
vis.p1 = Some(light_intr);
self.l(&light_intr, &-*wi)
}
pub fn power(&self) -> Spectrum {
let factor = if self.two_sided {
2.0 as Float
} else {
1.0 as Float
};
self.l_emit * factor * self.area * PI
}
pub fn preprocess(&self, _scene: &Scene) {
}
pub fn le(&self, _ray: &Ray) -> Spectrum {
Spectrum::default()
}
pub fn pdf_li(&self, iref: &dyn Interaction, wi: &Vector3f) -> Float {
self.shape.pdf_with_ref_point(iref, &wi)
}
pub fn sample_le(
&self,
u1: Point2f,
u2: Point2f,
_time: Float,
ray: &mut Ray,
n_light: &mut Normal3f,
pdf_pos: &mut Float,
pdf_dir: &mut Float,
) -> Spectrum {
let ic: InteractionCommon = self.shape.sample(u1, pdf_pos);
*n_light = ic.n;
let mut w: Vector3f;
if self.two_sided {
let mut u: Point2f = Point2f { x: u2.x, y: u2.y };
if u[XYEnum::X] < 0.5 as Float {
u[XYEnum::X] = (u[XYEnum::X] * 2.0 as Float).min(FLOAT_ONE_MINUS_EPSILON);
w = cosine_sample_hemisphere(&u);
} else {
u[XYEnum::X] =
((u[XYEnum::X] - 0.5 as Float) * 2.0 as Float).min(FLOAT_ONE_MINUS_EPSILON);
w = cosine_sample_hemisphere(&u);
w.z *= -1.0 as Float;
}
*pdf_dir = 0.5 as Float * cosine_hemisphere_pdf(w.z.abs());
} else {
w = cosine_sample_hemisphere(&u2);
*pdf_dir = cosine_hemisphere_pdf(w.z);
}
let n: Vector3f = Vector3f::from(ic.n);
let mut v1: Vector3f = Vector3f::default();
let mut v2: Vector3f = Vector3f::default();
vec3_coordinate_system(&n, &mut v1, &mut v2);
w = v1 * w.x + v2 * w.y + n * w.z;
*ray = ic.spawn_ray(&w);
self.l(&ic, &w)
}
pub fn pdf_le(&self, ray: &Ray, n: &Normal3f, pdf_pos: &mut Float, pdf_dir: &mut Float) {
*pdf_pos = self.shape.pdf(&InteractionCommon::default());
if self.two_sided {
*pdf_dir = 0.5 as Float * cosine_hemisphere_pdf(nrm_abs_dot_vec3f(&n, &ray.d));
} else {
*pdf_dir = cosine_hemisphere_pdf(nrm_dot_vec3f(&n, &ray.d));
}
}
pub fn get_flags(&self) -> u8 {
self.flags
}
pub fn get_n_samples(&self) -> i32 {
self.n_samples
}
pub fn l(&self, intr: &InteractionCommon, w: &Vector3f) -> Spectrum {
if self.two_sided || nrm_dot_vec3f(&intr.n, &w) > 0.0 as Float {
self.l_emit
} else {
Spectrum::new(0.0 as Float)
}
}
}