157 lines
4.6 KiB
Rust
157 lines
4.6 KiB
Rust
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<BSDFSample>;
|
|
|
|
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),
|
|
}
|