347 lines
10 KiB
Rust
347 lines
10 KiB
Rust
use crate::bxdfs::{
|
|
CoatedConductorBxDF, CoatedDiffuseBxDF, ConductorBxDF, DielectricBxDF, DiffuseBxDF,
|
|
};
|
|
use crate::core::bsdf::BSDF;
|
|
use crate::core::bssrdf::BSSRDF;
|
|
use crate::core::bxdf::BxDF;
|
|
use crate::core::image::DeviceImage;
|
|
use crate::core::material::{Material, MaterialEvalContext, MaterialTrait};
|
|
use crate::core::scattering::TrowbridgeReitzDistribution;
|
|
use crate::core::spectrum::{Spectrum, SpectrumTrait};
|
|
use crate::core::texture::{GPUFloatTexture, GPUSpectrumTexture, TextureEvaluator};
|
|
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
|
use crate::utils::Ptr;
|
|
use crate::utils::math::clamp;
|
|
|
|
#[repr(C)]
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub struct CoatedDiffuseMaterial {
|
|
pub normal_map: Ptr<DeviceImage>,
|
|
pub displacement: Ptr<GPUFloatTexture>,
|
|
pub reflectance: Ptr<GPUSpectrumTexture>,
|
|
pub albedo: Ptr<GPUSpectrumTexture>,
|
|
pub u_roughness: Ptr<GPUFloatTexture>,
|
|
pub v_roughness: Ptr<GPUFloatTexture>,
|
|
pub thickness: Ptr<GPUFloatTexture>,
|
|
pub g: Ptr<GPUFloatTexture>,
|
|
pub eta: Ptr<Spectrum>,
|
|
pub max_depth: u32,
|
|
pub n_samples: u32,
|
|
pub remap_roughness: bool,
|
|
pub seed: i32,
|
|
}
|
|
|
|
impl CoatedDiffuseMaterial {
|
|
#[allow(clippy::too_many_arguments)]
|
|
pub fn new(
|
|
reflectance: Ptr<GPUSpectrumTexture>,
|
|
u_roughness: Ptr<GPUFloatTexture>,
|
|
v_roughness: Ptr<GPUFloatTexture>,
|
|
thickness: Ptr<GPUFloatTexture>,
|
|
albedo: Ptr<GPUSpectrumTexture>,
|
|
g: Ptr<GPUFloatTexture>,
|
|
eta: Ptr<Spectrum>,
|
|
displacement: Ptr<GPUFloatTexture>,
|
|
normal_map: Ptr<DeviceImage>,
|
|
remap_roughness: bool,
|
|
max_depth: u32,
|
|
n_samples: u32,
|
|
seed: i32,
|
|
) -> Self {
|
|
Self {
|
|
displacement,
|
|
normal_map,
|
|
reflectance,
|
|
albedo,
|
|
u_roughness,
|
|
v_roughness,
|
|
thickness,
|
|
g,
|
|
eta,
|
|
remap_roughness,
|
|
max_depth,
|
|
n_samples,
|
|
seed,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl MaterialTrait for CoatedDiffuseMaterial {
|
|
fn get_bsdf<T: TextureEvaluator>(
|
|
&self,
|
|
tex_eval: &T,
|
|
ctx: &MaterialEvalContext,
|
|
lambda: &SampledWavelengths,
|
|
) -> BSDF {
|
|
let r = SampledSpectrum::clamp(
|
|
&tex_eval.evaluate_spectrum(&self.reflectance, ctx, lambda),
|
|
0.,
|
|
1.,
|
|
);
|
|
|
|
let mut u_rough = tex_eval.evaluate_float(&self.u_roughness, ctx);
|
|
let mut v_rough = tex_eval.evaluate_float(&self.v_roughness, ctx);
|
|
|
|
if self.remap_roughness {
|
|
u_rough = TrowbridgeReitzDistribution::roughness_to_alpha(u_rough);
|
|
v_rough = TrowbridgeReitzDistribution::roughness_to_alpha(v_rough);
|
|
}
|
|
|
|
let distrib = TrowbridgeReitzDistribution::new(u_rough, v_rough);
|
|
|
|
let thick = tex_eval.evaluate_float(&self.thickness, ctx);
|
|
let mut sampled_eta = self.eta.evaluate(lambda[0]);
|
|
if self.eta.is_constant() {
|
|
let mut lambda = *lambda;
|
|
lambda.terminate_secondary_inplace();
|
|
}
|
|
|
|
if sampled_eta == 0. {
|
|
sampled_eta = 1.
|
|
}
|
|
|
|
let a = SampledSpectrum::clamp(
|
|
&tex_eval.evaluate_spectrum(&self.albedo, ctx, lambda),
|
|
0.,
|
|
1.,
|
|
);
|
|
|
|
let gg = clamp(tex_eval.evaluate_float(&self.g, ctx), -1., 1.);
|
|
let bxdf = BxDF::CoatedDiffuse(CoatedDiffuseBxDF::new(
|
|
DielectricBxDF::new(sampled_eta, distrib),
|
|
DiffuseBxDF::new(r),
|
|
thick,
|
|
a,
|
|
gg,
|
|
self.max_depth,
|
|
self.n_samples,
|
|
self.seed,
|
|
));
|
|
|
|
BSDF::new(ctx.ns, ctx.dpdus, Ptr::from(&bxdf))
|
|
}
|
|
|
|
fn get_bssrdf<T>(
|
|
&self,
|
|
_tex_eval: &T,
|
|
_ctx: &MaterialEvalContext,
|
|
_lambda: &SampledWavelengths,
|
|
) -> Option<BSSRDF> {
|
|
None
|
|
}
|
|
|
|
fn can_evaluate_textures(&self, tex_eval: &dyn TextureEvaluator) -> bool {
|
|
tex_eval.can_evaluate(
|
|
&[self.u_roughness, self.v_roughness, self.thickness, self.g],
|
|
&[self.reflectance, self.albedo],
|
|
)
|
|
}
|
|
|
|
fn get_normal_map(&self) -> Option<&DeviceImage> {
|
|
Some(&*self.normal_map)
|
|
}
|
|
|
|
fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
|
|
self.displacement
|
|
}
|
|
|
|
fn has_subsurface_scattering(&self) -> bool {
|
|
false
|
|
}
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub struct CoatedConductorMaterial {
|
|
normal_map: Ptr<DeviceImage>,
|
|
displacement: Ptr<GPUFloatTexture>,
|
|
interface_uroughness: Ptr<GPUFloatTexture>,
|
|
interface_vroughness: Ptr<GPUFloatTexture>,
|
|
thickness: Ptr<GPUFloatTexture>,
|
|
interface_eta: Ptr<Spectrum>,
|
|
g: Ptr<GPUFloatTexture>,
|
|
albedo: Ptr<GPUSpectrumTexture>,
|
|
conductor_uroughness: Ptr<GPUFloatTexture>,
|
|
conductor_vroughness: Ptr<GPUFloatTexture>,
|
|
conductor_eta: Ptr<GPUSpectrumTexture>,
|
|
k: Ptr<GPUSpectrumTexture>,
|
|
reflectance: Ptr<GPUSpectrumTexture>,
|
|
max_depth: u32,
|
|
n_samples: u32,
|
|
remap_roughness: bool,
|
|
seed: i32,
|
|
}
|
|
|
|
impl CoatedConductorMaterial {
|
|
#[allow(clippy::too_many_arguments)]
|
|
pub fn new(
|
|
normal_map: Ptr<DeviceImage>,
|
|
displacement: Ptr<GPUFloatTexture>,
|
|
interface_uroughness: Ptr<GPUFloatTexture>,
|
|
interface_vroughness: Ptr<GPUFloatTexture>,
|
|
thickness: Ptr<GPUFloatTexture>,
|
|
interface_eta: Ptr<Spectrum>,
|
|
g: Ptr<GPUFloatTexture>,
|
|
albedo: Ptr<GPUSpectrumTexture>,
|
|
conductor_uroughness: Ptr<GPUFloatTexture>,
|
|
conductor_vroughness: Ptr<GPUFloatTexture>,
|
|
conductor_eta: Ptr<GPUSpectrumTexture>,
|
|
k: Ptr<GPUSpectrumTexture>,
|
|
reflectance: Ptr<GPUSpectrumTexture>,
|
|
max_depth: u32,
|
|
n_samples: u32,
|
|
remap_roughness: bool,
|
|
seed: i32,
|
|
) -> Self {
|
|
Self {
|
|
displacement,
|
|
normal_map,
|
|
interface_uroughness,
|
|
interface_vroughness,
|
|
thickness,
|
|
interface_eta,
|
|
g,
|
|
albedo,
|
|
conductor_uroughness,
|
|
conductor_vroughness,
|
|
conductor_eta,
|
|
k,
|
|
reflectance,
|
|
remap_roughness,
|
|
max_depth,
|
|
n_samples,
|
|
seed,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl MaterialTrait for CoatedConductorMaterial {
|
|
fn get_bsdf<T: TextureEvaluator>(
|
|
&self,
|
|
tex_eval: &T,
|
|
ctx: &MaterialEvalContext,
|
|
lambda: &SampledWavelengths,
|
|
) -> BSDF {
|
|
let mut iurough = tex_eval.evaluate_float(&self.interface_uroughness, ctx);
|
|
let mut ivrough = tex_eval.evaluate_float(&self.interface_vroughness, ctx);
|
|
|
|
if self.remap_roughness {
|
|
iurough = TrowbridgeReitzDistribution::roughness_to_alpha(iurough);
|
|
ivrough = TrowbridgeReitzDistribution::roughness_to_alpha(ivrough);
|
|
}
|
|
let interface_distrib = TrowbridgeReitzDistribution::new(iurough, ivrough);
|
|
let thick = tex_eval.evaluate_float(&self.thickness, ctx);
|
|
|
|
let mut ieta = self.interface_eta.evaluate(lambda[0]);
|
|
if self.interface_eta.is_constant() {
|
|
let mut lambda = *lambda;
|
|
lambda.terminate_secondary_inplace();
|
|
}
|
|
|
|
if ieta == 0. {
|
|
ieta = 1.;
|
|
}
|
|
|
|
let (mut ce, mut ck) = if !self.conductor_eta.is_null() {
|
|
let k_tex = self.k;
|
|
let ce = tex_eval.evaluate_spectrum(&self.conductor_eta, ctx, lambda);
|
|
let ck = tex_eval.evaluate_spectrum(unsafe { k_tex.as_ref() }, ctx, lambda);
|
|
(ce, ck)
|
|
} else {
|
|
let r = SampledSpectrum::clamp(
|
|
&tex_eval.evaluate_spectrum(&self.reflectance, ctx, lambda),
|
|
0.,
|
|
0.9999,
|
|
);
|
|
let ce = SampledSpectrum::new(1.0);
|
|
let one_minus_r = SampledSpectrum::new(1.) - r;
|
|
let ck = 2. * r.sqrt() / SampledSpectrum::clamp_zero(&one_minus_r).sqrt();
|
|
(ce, ck)
|
|
};
|
|
|
|
ce /= ieta;
|
|
ck /= ieta;
|
|
|
|
let mut curough = tex_eval.evaluate_float(&self.conductor_uroughness, ctx);
|
|
let mut cvrough = tex_eval.evaluate_float(&self.conductor_vroughness, ctx);
|
|
|
|
if self.remap_roughness {
|
|
curough = TrowbridgeReitzDistribution::roughness_to_alpha(curough);
|
|
cvrough = TrowbridgeReitzDistribution::roughness_to_alpha(cvrough);
|
|
}
|
|
|
|
let conductor_distrib = TrowbridgeReitzDistribution::new(curough, cvrough);
|
|
let a = SampledSpectrum::clamp(
|
|
&tex_eval.evaluate_spectrum(&self.albedo, ctx, lambda),
|
|
0.,
|
|
1.,
|
|
);
|
|
|
|
let gg = clamp(tex_eval.evaluate_float(&self.g, ctx), -1., 1.);
|
|
let bxdf = BxDF::CoatedConductor(CoatedConductorBxDF::new(
|
|
DielectricBxDF::new(ieta, interface_distrib),
|
|
ConductorBxDF::new(&conductor_distrib, ce, ck),
|
|
thick,
|
|
a,
|
|
gg,
|
|
self.max_depth,
|
|
self.n_samples,
|
|
self.seed,
|
|
));
|
|
BSDF::new(ctx.ns, ctx.dpdus, Ptr::from(&bxdf))
|
|
}
|
|
|
|
fn get_bssrdf<T>(
|
|
&self,
|
|
_tex_eval: &T,
|
|
_ctx: &MaterialEvalContext,
|
|
_lambda: &SampledWavelengths,
|
|
) -> Option<BSSRDF> {
|
|
None
|
|
}
|
|
|
|
fn can_evaluate_textures(&self, tex_eval: &dyn TextureEvaluator) -> bool {
|
|
let float_textures = [
|
|
self.interface_uroughness,
|
|
self.interface_vroughness,
|
|
self.thickness,
|
|
self.g,
|
|
self.conductor_uroughness,
|
|
self.conductor_vroughness,
|
|
];
|
|
|
|
let mut spectrum_textures = [Ptr::null(); 4];
|
|
let mut n = 0;
|
|
|
|
spectrum_textures[n] = self.albedo;
|
|
n += 1;
|
|
|
|
if !self.conductor_eta.is_null() {
|
|
spectrum_textures[n] = self.conductor_eta;
|
|
n += 1;
|
|
}
|
|
|
|
if !self.k.is_null() {
|
|
spectrum_textures[n] = self.k;
|
|
n += 1;
|
|
}
|
|
|
|
if !self.conductor_eta.is_null() {
|
|
spectrum_textures[n] = self.reflectance;
|
|
}
|
|
|
|
tex_eval.can_evaluate(&float_textures, &spectrum_textures)
|
|
}
|
|
|
|
fn get_normal_map(&self) -> Option<&DeviceImage> {
|
|
Some(&*self.normal_map)
|
|
}
|
|
|
|
fn get_displacement(&self) -> Ptr<GPUFloatTexture> {
|
|
self.displacement
|
|
}
|
|
|
|
fn has_subsurface_scattering(&self) -> bool {
|
|
false
|
|
}
|
|
}
|