use super::state::PathState; use shared::core::geometry::Ray; use shared::core::interaction::{Interaction, InteractionTrait}; use shared::core::light::{Light, LightTrait}; use shared::core::primitive::{Primitive, PrimitiveTrait}; use shared::core::shape::ShapeIntersection; use shared::lights::sampler::LightSampler; use shared::spectra::SampledWavelengths; use shared::utils::sampling::power_heuristic; use shared::{Float, SHADOW_EPSILON}; use std::sync::Arc; #[derive(Clone, Debug)] pub struct IntegratorBase { pub aggregate: Arc, pub lights: Vec>, pub infinite_lights: Vec>, } impl IntegratorBase { pub fn new(aggregate: Arc, lights: Vec>) -> Self { let infinite_lights = lights .iter() .filter(|light| light.light_type().is_infinite()) .cloned() .collect(); Self { aggregate, lights, infinite_lights, } } pub fn intersect(&self, ray: &Ray, t_max: Option) -> Option { self.aggregate.intersect(ray, t_max) } pub fn intersect_p(&self, ray: &Ray, t_max: Option) -> bool { self.aggregate.intersect_p(ray, t_max) } pub fn unoccluded(&self, p0: &Interaction, p1: &Interaction) -> bool { !self.intersect_p( &p0.spawn_ray_to_interaction(*p1.get_common()), Some(1. - SHADOW_EPSILON), ) } pub fn add_infinite_light_contribution( &self, state: &mut PathState, ray: &Ray, lambda: &SampledWavelengths, light_sampler: Option<&LightSampler>, use_mis: bool, ) { for light in &self.infinite_lights { let le = light.le(ray, lambda); if le.is_black() { continue; } if state.depth == 0 || state.specular_bounce || !use_mis { state.l += state.beta * le; } else if let Some(sampler) = light_sampler { let p_l = sampler.pmf_with_context(&state.prev_ctx, light) * light.pdf_li(&state.prev_ctx, ray.d, true); let w_b = power_heuristic(1, state.prev_pdf, 1, p_l); state.l += state.beta * w_b * le; } } } }