use super::context::ExitSplitCtx;
use crate::optics::{
polarization::{MuellerMatrix, StokesVector},
raytracer::{
camera::Ray, environment::sample_environment_channel, intersect::intersect_polyhedron_soa,
},
};
use glam::Vec3;
pub(super) struct ChannelTransmissionInputs {
pub(super) n1k: f32,
pub(super) n2k: f32,
pub(super) cos_i: f32,
pub(super) cos_t_k: f32,
pub(super) r_unpol: f32,
pub(super) entering_anisotropic: bool,
pub(super) entry_mode_azimuth2: Option<(f32, f32)>,
pub(super) incident_stokes_k: StokesVector,
}
pub(super) fn compute_channel_transmission(
inputs: &ChannelTransmissionInputs,
) -> (StokesVector, f32) {
let &ChannelTransmissionInputs {
n1k,
n2k,
cos_i,
cos_t_k,
r_unpol,
entering_anisotropic,
entry_mode_azimuth2,
incident_stokes_k,
} = inputs;
let t_s_k = (2.0 * n1k * cos_i) / f32::mul_add(n2k, cos_t_k, n1k * cos_i);
let t_p_k = (2.0 * n1k * cos_i) / f32::mul_add(n1k, cos_t_k, n2k * cos_i);
let trans_matrix_k =
MuellerMatrix::fresnel_transmission(n1k, n2k, cos_i, cos_t_k, t_s_k, t_p_k);
let incident_k =
if entering_anisotropic && let Some((cos_2psi_x, sin_2psi_x)) = entry_mode_azimuth2 {
let i_k = incident_stokes_k.i;
StokesVector::new(i_k, i_k * cos_2psi_x, i_k * sin_2psi_x, 0.0)
} else {
incident_stokes_k
};
let transmitted = incident_k
.apply_matrix(&trans_matrix_k)
.scale(1.0 / (1.0 - r_unpol));
let r_s_k = f32::mul_add(n2k, -cos_t_k, n1k * cos_i) / f32::mul_add(n2k, cos_t_k, n1k * cos_i);
let r_p_k = f32::mul_add(n1k, -cos_t_k, n2k * cos_i) / f32::mul_add(n1k, cos_t_k, n2k * cos_i);
let r_unpol_k = (0.5 * r_p_k.mul_add(r_p_k, r_s_k * r_s_k)).clamp(1e-4, 1.0 - 1e-4);
(transmitted, r_unpol_k)
}
pub(super) fn try_split_exit_channel(
exit: &mut ExitSplitCtx<'_>,
hit_point: Vec3,
k: usize,
lambda_k: f32,
dir_k: Vec3,
transmitted_intensity: f32,
) {
let probe = Ray {
origin: hit_point + dir_k * 1e-4,
dir: dir_k,
};
if intersect_polyhedron_soa(probe, exit.plane_soa).is_some() {
return;
}
let env_spectral = sample_environment_channel(
exit.environment,
dir_k,
lambda_k,
exit.studio_rig.as_ref(),
exit.observer,
);
exit.split_radiance[k] = f32::mul_add(
transmitted_intensity.max(0.0),
env_spectral,
exit.split_radiance[k],
);
}