use super::sun::{SUN_SOLID_ANGLE, sun_cone_direction, sun_nee_pdf, sun_radiance_factor};
use super::{EnvironmentSource, LightingModel, LightingPreset};
use glam::Vec3;
pub(in super::super) struct EnvNeeSample {
pub(in super::super) dir: Vec3,
pub(in super::super) pdf: f32,
pub(in super::super) rgb: [f32; 3],
pub(in super::super) sun: Option<SunNeeRadiance>,
}
#[derive(Clone, Copy)]
pub(in super::super) struct SunNeeRadiance {
geometry: f32,
exposure: f32,
preset: LightingPreset,
}
impl EnvNeeSample {
#[must_use]
pub(in super::super) fn radiance(&self, lambda_nm: f32) -> f32 {
self.sun.map_or_else(
|| crate::renderer::env_map::rgb_to_spectral_radiance(self.rgb, lambda_nm),
|sun| sun.geometry * (sun.preset.spectral_power(lambda_nm) * sun.exposure),
)
}
}
#[must_use]
pub(in super::super) fn environment_supports_nee(environment: EnvironmentSource<'_>) -> bool {
match environment {
EnvironmentSource::Studio { preset, .. } => preset.model() == LightingModel::DaylightSun,
EnvironmentSource::HdrMap(_) => true,
}
}
#[must_use]
pub(in super::super) fn sample_environment_for_nee(
environment: EnvironmentSource<'_>,
u0: f32,
u1: f32,
) -> Option<EnvNeeSample> {
match environment {
EnvironmentSource::Studio {
preset,
exposure,
light_yaw,
light_pitch,
..
} if preset.model() == LightingModel::DaylightSun => {
let key_dir = key_dir_only(light_yaw, light_pitch);
Some(EnvNeeSample {
dir: sun_cone_direction(key_dir, u0, u1),
pdf: 1.0 / SUN_SOLID_ANGLE,
rgb: [0.0; 3],
sun: Some(SunNeeRadiance {
geometry: sun_radiance_factor(key_dir),
exposure,
preset,
}),
})
}
EnvironmentSource::Studio { .. } => None,
EnvironmentSource::HdrMap(map) => {
let (dir, rgb, pdf) = map.sample(u0, u1);
(pdf > 0.0).then_some(EnvNeeSample {
dir,
pdf,
rgb,
sun: None,
})
}
}
}
fn key_dir_only(light_yaw: f32, light_pitch: f32) -> Vec3 {
let cos_pitch = light_pitch.cos();
let sin_pitch = light_pitch.sin();
let cos_yaw = light_yaw.cos();
let sin_yaw = light_yaw.sin();
Vec3::new(cos_pitch * sin_yaw, sin_pitch, cos_pitch * cos_yaw).normalize()
}
#[cfg(test)]
pub(super) fn key_dir_only_for_test(light_yaw: f32, light_pitch: f32) -> Vec3 {
key_dir_only(light_yaw, light_pitch)
}
#[must_use]
pub(in super::super) fn environment_nee_pdf(environment: EnvironmentSource<'_>, dir: Vec3) -> f32 {
match environment {
EnvironmentSource::Studio {
preset,
light_yaw,
light_pitch,
..
} if preset.model() == LightingModel::DaylightSun => {
sun_nee_pdf(key_dir_only(light_yaw, light_pitch), dir)
}
EnvironmentSource::Studio { .. } => 0.0,
EnvironmentSource::HdrMap(map) => map.pdf(dir),
}
}