use crate::Float; use crate::core::bxdf::{BxDF, BxDFFlags, BxDFTrait, FArgs, TransportMode}; use crate::core::geometry::{Frame, Normal3f, Point2f, Vector3f, VectorLike}; use crate::spectra::SampledSpectrum; use crate::utils::Ptr; #[repr(C)] #[derive(Copy, Clone, Debug, Default)] pub struct BSDF { bxdf: Ptr, shading_frame: Frame, } impl BSDF { pub fn new(ns: Normal3f, dpdus: Vector3f, bxdf: Ptr) -> Self { Self { bxdf, shading_frame: Frame::new(dpdus.normalize(), Vector3f::from(ns)), } } pub fn is_valid(&self) -> bool { !self.bxdf.is_null() } pub fn flags(&self) -> BxDFFlags { if self.bxdf.is_null() { // Either this, or transmissive for seethrough return BxDFFlags::empty(); } self.bxdf.flags() } pub fn render_to_local(&self, v: Vector3f) -> Vector3f { self.shading_frame.to_local(v) } pub fn local_to_render(&self, v: Vector3f) -> Vector3f { self.shading_frame.from_local(v) } pub fn f( &self, wo_render: Vector3f, wi_render: Vector3f, mode: TransportMode, ) -> Option { if self.bxdf.is_null() { return None; } let wi = self.render_to_local(wi_render); let wo = self.render_to_local(wo_render); if wo.z() == 0.0 || wi.z() == 0.0 { return None; } Some(self.bxdf.f(wo, wi, mode)) } pub fn sample_f( &self, wo_render: Vector3f, u: Float, u2: Point2f, f_args: FArgs, ) -> Option { let bxdf = unsafe { self.bxdf.as_ref() }; let sampling_flags = BxDFFlags::from_bits_truncate(f_args.sample_flags.bits()); let wo = self.render_to_local(wo_render); if wo.z() == 0.0 || !bxdf.flags().contains(sampling_flags) { return None; } let mut sample = bxdf.sample_f(wo, u, u2, f_args)?; if sample.pdf > 0.0 && sample.wi.z() != 0.0 { sample.wi = self.local_to_render(sample.wi); return Some(sample); } None } pub fn pdf(&self, wo_render: Vector3f, wi_render: Vector3f, f_args: FArgs) -> Float { if self.bxdf.is_null() { return 0.0; } let sample_flags = BxDFFlags::from_bits_truncate(f_args.sample_flags.bits()); let wo = self.render_to_local(wo_render); let wi = self.render_to_local(wi_render); if wo.z() == 0.0 || !self.bxdf.flags().contains(sample_flags) { return 0.0; } self.bxdf.pdf(wo, wi, f_args) } pub fn rho_u(&self, u1: &[Point2f], uc: &[Float], u2: &[Point2f]) -> SampledSpectrum { if self.bxdf.is_null() { return SampledSpectrum::default(); } self.bxdf.rho_u(u1, uc, u2) } pub fn rho_wo(&self, wo_render: Vector3f, uc: &[Float], u: &[Point2f]) -> SampledSpectrum { if self.bxdf.is_null() { return SampledSpectrum::default(); } let wo = self.render_to_local(wo_render); self.bxdf.rho_wo(wo, uc, u) } pub fn regularize(&mut self) { if !self.bxdf.is_null() { let mut bxdf = unsafe { *self.bxdf.as_raw() }; bxdf.regularize(); } } } #[derive(Debug, Clone)] pub struct BSDFSample { pub f: SampledSpectrum, pub wi: Vector3f, pub pdf: Float, pub flags: BxDFFlags, pub eta: Float, pub pdf_is_proportional: bool, } impl Default for BSDFSample { fn default() -> Self { Self { f: SampledSpectrum::default(), wi: Vector3f::default(), pdf: 0.0, flags: BxDFFlags::empty(), eta: 1.0, pdf_is_proportional: false, } } } impl BSDFSample { pub fn new( f: SampledSpectrum, wi: Vector3f, pdf: Float, flags: BxDFFlags, eta: Float, pdf_is_proportional: bool, ) -> Self { Self { f, wi, pdf, flags, eta, pdf_is_proportional, } } #[inline] pub fn is_reflective(&self) -> bool { self.flags.is_reflective() } #[inline] pub fn is_transmissive(&self) -> bool { self.flags.is_transmissive() } #[inline] pub fn is_diffuse(&self) -> bool { self.flags.is_diffuse() } #[inline] pub fn is_glossy(&self) -> bool { self.flags.is_glossy() } #[inline] pub fn is_specular(&self) -> bool { self.flags.is_specular() } }