use crate::bxdfs::*; use crate::core::bsdf::BSDFSample; use crate::core::geometry::{Point2f, Vector3f, abs_cos_theta}; use crate::spectra::SampledSpectrum; use crate::utils::sampling::{sample_uniform_hemisphere, uniform_hemisphere_pdf}; use crate::{Float, PI}; use bitflags::bitflags; use core::any::Any; use core::ops::Not; use enum_dispatch::enum_dispatch; bitflags! { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct BxDFReflTransFlags: u8 { const REFLECTION = 1 << 0; const TRANSMISSION = 1 << 1; const ALL = Self::REFLECTION.bits() | Self::TRANSMISSION.bits(); } } bitflags! { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct BxDFFlags: u8 { const UNSET = 0; const REFLECTION = 1 << 0; const TRANSMISSION = 1 << 1; const DIFFUSE = 1 << 2; const GLOSSY = 1 << 3; const SPECULAR = 1 << 4; const DIFFUSE_REFLECTION = Self::DIFFUSE.bits() | Self::REFLECTION.bits(); const DIFFUSE_TRANSMISSION = Self::DIFFUSE.bits() | Self::TRANSMISSION.bits(); const GLOSSY_REFLECTION = Self::GLOSSY.bits() | Self::REFLECTION.bits(); const GLOSSY_TRANSMISSION = Self::GLOSSY.bits() | Self::TRANSMISSION.bits(); const SPECULAR_REFLECTION = Self::SPECULAR.bits() | Self::REFLECTION.bits(); const SPECULAR_TRANSMISSION = Self::SPECULAR.bits() | Self::TRANSMISSION.bits(); const SCATTERING = Self::DIFFUSE.bits() | Self::GLOSSY.bits() | Self::SPECULAR.bits(); const ALL = Self::REFLECTION.bits() | Self::TRANSMISSION.bits() | Self::SCATTERING.bits(); } } impl BxDFFlags { #[inline] pub fn is_reflective(&self) -> bool { self.contains(Self::REFLECTION) } #[inline] pub fn is_transmissive(&self) -> bool { self.contains(Self::TRANSMISSION) } #[inline] pub fn is_diffuse(&self) -> bool { self.contains(Self::DIFFUSE) } #[inline] pub fn is_glossy(&self) -> bool { self.contains(Self::GLOSSY) } #[inline] pub fn is_specular(&self) -> bool { self.contains(Self::SPECULAR) } #[inline] pub fn is_non_specular(&self) -> bool { self.intersects(Self::DIFFUSE | Self::GLOSSY) } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum TransportMode { Radiance, Importance, } impl Not for TransportMode { type Output = Self; fn not(self) -> Self::Output { match self { TransportMode::Radiance => TransportMode::Importance, TransportMode::Importance => TransportMode::Radiance, } } } #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct FArgs { pub mode: TransportMode, pub sample_flags: BxDFReflTransFlags, } impl Default for FArgs { fn default() -> Self { Self { mode: TransportMode::Radiance, sample_flags: BxDFReflTransFlags::ALL, } } } #[enum_dispatch] pub trait BxDFTrait: Any { fn flags(&self) -> BxDFFlags; fn f(&self, wo: Vector3f, wi: Vector3f, mode: TransportMode) -> SampledSpectrum; fn sample_f(&self, wo: Vector3f, uc: Float, u: Point2f, f_args: FArgs) -> Option; fn pdf(&self, wo: Vector3f, wi: Vector3f, f_args: FArgs) -> Float; fn rho_wo(&self, wo: Vector3f, uc: &[Float], u2: &[Point2f]) -> SampledSpectrum { let mut r = SampledSpectrum::new(0.); for i in 0..uc.len() { if let Some(bs) = self.sample_f(wo, uc[i], u2[i], FArgs::default()) { r += bs.f * abs_cos_theta(bs.wi) / bs.pdf; } } r / uc.len() as Float } fn rho_u(&self, u1: &[Point2f], uc: &[Float], u2: &[Point2f]) -> SampledSpectrum { let mut r = SampledSpectrum::new(0.); for i in 0..uc.len() { let wo = sample_uniform_hemisphere(u1[i]); if wo.z() == 0. { continue; } let pdfo = uniform_hemisphere_pdf(); if let Some(bs) = self.sample_f(wo, uc[i], u2[i], FArgs::default()) { r += bs.f * abs_cos_theta(bs.wi) * abs_cos_theta(wo) / (pdfo * bs.pdf); } } r / (PI * uc.len() as Float) } fn regularize(&mut self) { todo!(); } fn as_any(&self) -> &dyn Any; } #[repr(C)] #[enum_dispatch(BxDFTrait)] #[derive(Debug, Clone, Copy)] pub enum BxDF { Diffuse(DiffuseBxDF), Dielectric(DielectricBxDF), ThinDielectric(ThinDielectricBxDF), Conductor(ConductorBxDF), Measured(MeasuredBxDF), Hair(HairBxDF), CoatedDiffuse(CoatedDiffuseBxDF), CoatedConductor(CoatedConductorBxDF), NormalizedFresnel(NormalizedFresnelBxDF), }