pbrt/shared/src/core/bsdf.rs
2026-01-18 16:29:27 +00:00

126 lines
3.3 KiB
Rust

use crate::Float;
use crate::core::bxdf::{BSDFSample, 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<BxDF>,
shading_frame: Frame,
}
impl BSDF {
pub fn new(ns: Normal3f, dpdus: Vector3f, bxdf: Ptr<BxDF>) -> 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<SampledSpectrum> {
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<BSDFSample> {
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();
}
}
}