190 lines
4.6 KiB
Rust
190 lines
4.6 KiB
Rust
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<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();
|
|
}
|
|
}
|
|
}
|
|
|
|
#[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()
|
|
}
|
|
}
|