use crate::core::geometry::{ Bounds3f, Normal3f, Point2f, Point3f, Point3fi, Ray, Vector3f, VectorLike, }; use crate::core::interaction::{Interaction, InteractionBase, SimpleInteraction}; use crate::core::light::{LightBase, LightBounds, LightLiSample, LightSampleContext, LightTrait}; use crate::core::spectrum::SpectrumTrait; use crate::spectra::{DenselySampledSpectrum, SampledSpectrum, SampledWavelengths}; use crate::utils::Ptr; use crate::{Float, PI}; use num_traits::Float as NumFloat; #[repr(C)] #[derive(Clone, Copy, Debug)] pub struct DistantLight { pub base: LightBase, pub lemit: Ptr, pub scale: Float, pub scene_center: Point3f, pub scene_radius: Float, } impl DistantLight { pub fn sample_li_base( &self, ctx_p: Point3f, lambda: &SampledWavelengths, ) -> (SampledSpectrum, Vector3f, Float, Point3f) { let wi = self .base .render_from_light .apply_to_vector(Vector3f::new(0., 0., 1.)) .normalize(); let p_outside = ctx_p + wi * 2. * self.scene_radius; let li = self.scale * self.lemit.sample(lambda); (li, wi, 1.0, p_outside) } } impl LightTrait for DistantLight { fn base(&self) -> &LightBase { &self.base } fn phi(&self, lambda: SampledWavelengths) -> SampledSpectrum { self.scale * self.lemit.sample(&lambda) * PI * self.scene_radius.sqrt() } fn sample_li( &self, ctx: &LightSampleContext, _u: Point2f, lambda: &SampledWavelengths, _allow_incomplete_pdf: bool, ) -> Option { let wi = self .base .render_from_light .apply_to_vector(Vector3f::new(0., 0., 1.)) .normalize(); let p_outside = ctx.p() + wi * 2. * self.scene_radius; let li = self.scale * self.lemit.sample(lambda); let base = InteractionBase::new_boundary(p_outside, 0.0, self.base.medium_interface); let intr = SimpleInteraction::new(base); Some(LightLiSample::new(li, wi, 1., Interaction::Simple(intr))) } fn pdf_li( &self, _ctx: &LightSampleContext, _wi: Vector3f, _allow_incomplete_pdf: bool, ) -> Float { 0. } fn l( &self, _p: Point3f, _n: Normal3f, _uv: Point2f, _w: Vector3f, _lambda: &SampledWavelengths, ) -> SampledSpectrum { todo!() } fn le(&self, _ray: &Ray, _lambda: &SampledWavelengths) -> SampledSpectrum { todo!() } fn preprocess(&mut self, scene_bounds: &Bounds3f) { let (center, radius) = scene_bounds.bounding_sphere(); self.scene_center = center; self.scene_radius = radius; } fn bounds(&self) -> Option { None } }