Updated Hair bsdf getter, added enum for clearer variant construction on absorption
This commit is contained in:
parent
0fcfcbd467
commit
f496c6721e
3 changed files with 101 additions and 41 deletions
|
|
@ -8,7 +8,7 @@ use crate::core::scattering::{
|
|||
TrowbridgeReitzDistribution, fr_complex_from_spectrum, fr_dielectric, fresnel_moment1, reflect,
|
||||
refract,
|
||||
};
|
||||
use crate::spectra::{DeviceStandardColorSpaces, RGBUnboundedSpectrum, SampledSpectrum};
|
||||
use crate::spectra::{N_SPECTRUM_SAMPLES, RGBColorSpace, RGBUnboundedSpectrum, SampledSpectrum};
|
||||
use crate::utils::gpu_array_from_fn;
|
||||
use crate::utils::math::{
|
||||
clamp, fast_exp, i0, lerp, log_i0, radians, safe_acos, safe_asin, safe_sqrt, sample_discrete,
|
||||
|
|
@ -17,7 +17,7 @@ use crate::utils::math::{
|
|||
use crate::utils::sampling::{
|
||||
cosine_hemisphere_pdf, sample_cosine_hemisphere, sample_trimmed_logistic,
|
||||
};
|
||||
use crate::{Float, INV_2_PI, INV_PI, PI};
|
||||
use crate::{Float, INV_2_PI, INV_PI, PI, Ptr};
|
||||
use core::any::Any;
|
||||
use num_traits::Float as NumFloat;
|
||||
|
||||
|
|
@ -34,7 +34,6 @@ pub struct HairBxDF {
|
|||
pub s: Float,
|
||||
pub sin_2k_alpha: [Float; P_MAX],
|
||||
pub cos_2k_alpha: [Float; P_MAX],
|
||||
pub colorspaces: DeviceStandardColorSpaces,
|
||||
}
|
||||
|
||||
impl HairBxDF {
|
||||
|
|
@ -45,7 +44,6 @@ impl HairBxDF {
|
|||
beta_m: Float,
|
||||
beta_n: Float,
|
||||
alpha: Float,
|
||||
colorspaces: DeviceStandardColorSpaces,
|
||||
) -> Self {
|
||||
let mut sin_2k_alpha = [0.; P_MAX];
|
||||
let mut cos_2k_alpha = [0.; P_MAX];
|
||||
|
|
@ -67,7 +65,6 @@ impl HairBxDF {
|
|||
s: 0.,
|
||||
sin_2k_alpha,
|
||||
cos_2k_alpha,
|
||||
colorspaces,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -141,12 +138,25 @@ impl HairBxDF {
|
|||
pub fn sigma_a_from_concentration(
|
||||
ce: Float,
|
||||
cp: Float,
|
||||
stdcs: DeviceStandardColorSpaces,
|
||||
srgb: Ptr<RGBColorSpace>,
|
||||
) -> RGBUnboundedSpectrum {
|
||||
let eumelanin_sigma_a = RGB::new(0.419, 0.697, 1.37);
|
||||
let pheomelanin_sigma_a = RGB::new(0.187, 0.4, 1.05);
|
||||
let sigma_a = ce * eumelanin_sigma_a + cp * pheomelanin_sigma_a;
|
||||
RGBUnboundedSpectrum::new(&stdcs.srgb, sigma_a)
|
||||
RGBUnboundedSpectrum::new(&srgb, sigma_a)
|
||||
}
|
||||
|
||||
pub fn sigma_a_from_reflectance(c: SampledSpectrum, beta_n: Float) -> SampledSpectrum {
|
||||
let mut sigma_a = SampledSpectrum::zero();
|
||||
for i in 0..N_SPECTRUM_SAMPLES {
|
||||
sigma_a[i] = square(
|
||||
c[i].ln()
|
||||
/ (5.969 - 0.215 * beta_n + 2.532 * square(beta_n) - 10.73 * beta_n.powf(3.)
|
||||
+ 5.574 * beta_n.powf(4.)
|
||||
+ 0.245 * beta_n.powf(5.)),
|
||||
);
|
||||
}
|
||||
sigma_a
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,46 +11,50 @@ use crate::core::material::{Material, MaterialEvalContext, MaterialTrait};
|
|||
use crate::core::scattering::TrowbridgeReitzDistribution;
|
||||
use crate::core::spectrum::{Spectrum, SpectrumTrait};
|
||||
use crate::core::texture::{FloatTexture, SpectrumTexture, TextureEvaluator};
|
||||
use crate::spectra::{SampledSpectrum, SampledWavelengths};
|
||||
use crate::spectra::{RGBColorSpace, SampledSpectrum, SampledWavelengths};
|
||||
use crate::textures::SpectrumMixTexture;
|
||||
use crate::utils::Ptr;
|
||||
use crate::utils::math::clamp;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum HairAbsorption {
|
||||
SigmaA(Ptr<SpectrumTexture>),
|
||||
Color(Ptr<SpectrumTexture>),
|
||||
Melanin {
|
||||
eumelanin: Ptr<FloatTexture>,
|
||||
pheomelanin: Ptr<FloatTexture>,
|
||||
},
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct HairMaterial {
|
||||
pub sigma_a: Ptr<SpectrumTexture>,
|
||||
pub color: Ptr<SpectrumTexture>,
|
||||
pub eumelanin: Ptr<FloatTexture>,
|
||||
pub pheomelanin: Ptr<FloatTexture>,
|
||||
pub hair_absorption: HairAbsorption,
|
||||
pub eta: Ptr<FloatTexture>,
|
||||
pub beta_m: Ptr<FloatTexture>,
|
||||
pub beta_n: Ptr<FloatTexture>,
|
||||
pub alpha: Ptr<FloatTexture>,
|
||||
pub colorspace: Ptr<RGBColorSpace>,
|
||||
}
|
||||
|
||||
impl HairMaterial {
|
||||
#[cfg(not(gpu))]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
sigma_a: Ptr<SpectrumTexture>,
|
||||
color: Ptr<SpectrumTexture>,
|
||||
eumelanin: Ptr<FloatTexture>,
|
||||
pheomelanin: Ptr<FloatTexture>,
|
||||
hair_absorption: HairAbsorption,
|
||||
eta: Ptr<FloatTexture>,
|
||||
beta_m: Ptr<FloatTexture>,
|
||||
beta_n: Ptr<FloatTexture>,
|
||||
alpha: Ptr<FloatTexture>,
|
||||
colorspace: Ptr<RGBColorSpace>,
|
||||
) -> Self {
|
||||
Self {
|
||||
sigma_a,
|
||||
color,
|
||||
eumelanin,
|
||||
pheomelanin,
|
||||
hair_absorption,
|
||||
eta,
|
||||
beta_m,
|
||||
beta_n,
|
||||
alpha,
|
||||
colorspace,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -58,19 +62,60 @@ impl HairMaterial {
|
|||
impl MaterialTrait for HairMaterial {
|
||||
fn get_bsdf<T: TextureEvaluator>(
|
||||
&self,
|
||||
_tex_eval: &T,
|
||||
_ctx: &MaterialEvalContext,
|
||||
_lambda: &mut SampledWavelengths,
|
||||
tex_eval: &T,
|
||||
ctx: &MaterialEvalContext,
|
||||
lambda: &mut SampledWavelengths,
|
||||
) -> BSDF {
|
||||
todo!()
|
||||
let bm = tex_eval.evaluate_float(&self.beta_m, ctx).clamp(1e-2, 1.0);
|
||||
let bn = tex_eval.evaluate_float(&self.beta_n, ctx).clamp(1e-2, 1.0);
|
||||
let a = tex_eval.evaluate_float(&self.alpha, ctx);
|
||||
let e = tex_eval.evaluate_float(&self.eta, ctx);
|
||||
let sig_a = match self.hair_absorption {
|
||||
// Absorption coefficient, not a reflectance, can be larger than 1
|
||||
HairAbsorption::SigmaA(sigma_a) => {
|
||||
SampledSpectrum::clamp_zero(&tex_eval.evaluate_spectrum(&sigma_a, ctx, lambda))
|
||||
}
|
||||
HairAbsorption::Color(color) => {
|
||||
let c = SampledSpectrum::clamp(
|
||||
&tex_eval.evaluate_spectrum(&color, ctx, lambda),
|
||||
0.,
|
||||
1.,
|
||||
);
|
||||
HairBxDF::sigma_a_from_reflectance(c, bn)
|
||||
}
|
||||
HairAbsorption::Melanin {
|
||||
eumelanin,
|
||||
pheomelanin,
|
||||
} => {
|
||||
debug_assert!(!eumelanin.is_null() || !pheomelanin.is_null());
|
||||
let eu = if !eumelanin.is_null() {
|
||||
tex_eval.evaluate_float(&eumelanin, ctx)
|
||||
} else {
|
||||
0.
|
||||
};
|
||||
let pheo = if !pheomelanin.is_null() {
|
||||
tex_eval.evaluate_float(&pheomelanin, ctx)
|
||||
} else {
|
||||
0.
|
||||
};
|
||||
|
||||
HairBxDF::sigma_a_from_concentration(eu.max(0.0), pheo.max(0.0), self.colorspace)
|
||||
.sample(lambda)
|
||||
}
|
||||
};
|
||||
|
||||
let h = -1. + 2. * ctx.uv[1];
|
||||
let bxdf = BxDF::Hair(HairBxDF::new(h, e, sig_a, bm, bn, a));
|
||||
BSDF::new(ctx.ns, ctx.dpdus, bxdf)
|
||||
}
|
||||
|
||||
fn get_bssrdf<T>(
|
||||
&self,
|
||||
_tex_eval: &T,
|
||||
_ctx: &MaterialEvalContext,
|
||||
_lambda: &SampledWavelengths,
|
||||
) -> Option<BSSRDF> {
|
||||
todo!()
|
||||
None
|
||||
}
|
||||
|
||||
fn can_evaluate_textures(&self, _tex_eval: &dyn TextureEvaluator) -> bool {
|
||||
|
|
|
|||
|
|
@ -29,31 +29,36 @@ impl CreateMaterial for HairMaterial {
|
|||
let eumelanin = parameters.get_float_texture_or_null("eumelanin")?;
|
||||
let pheomelanin = parameters.get_float_texture_or_null("pheomelanin")?;
|
||||
let has_melanin = eumelanin.is_some() || pheomelanin.is_some();
|
||||
|
||||
let sigma_a = if sigma_a.is_none() && reflectance.is_none() && !has_melanin {
|
||||
let stdcs = get_colorspace_device();
|
||||
let default_rgb = HairBxDF::sigma_a_from_concentration(1.3, 0.0, stdcs);
|
||||
let spectrum = Spectrum::RGBUnbounded(default_rgb);
|
||||
let texture = SpectrumTexture::Constant(SpectrumConstantTexture::new(spectrum));
|
||||
Some(Arc::new(texture))
|
||||
} else {
|
||||
sigma_a
|
||||
};
|
||||
|
||||
let eta = parameters.get_float_texture("eta", 1.55)?;
|
||||
let beta_m = parameters.get_float_texture("beta_m", 0.3)?;
|
||||
let beta_n = parameters.get_float_texture("beta_n", 0.3)?;
|
||||
let alpha = parameters.get_float_texture("alpha", 2.)?;
|
||||
|
||||
let stdcs = get_colorspace_device();
|
||||
|
||||
let absorption = if let Some(s) = sigma_a {
|
||||
HairAbsorption::SigmaA(arena.upload(s))
|
||||
} else if let Some(r) = reflectance {
|
||||
HairAbsorption::Color(arena.upload(r))
|
||||
} else if has_melanin {
|
||||
HairAbsorption::Melanin {
|
||||
eumelanin: arena.upload(eumelanin),
|
||||
pheomelanin: arena.upload(pheomelanin),
|
||||
}
|
||||
} else {
|
||||
let default_rgb = HairBxDF::sigma_a_from_concentration(1.3, 0.0, stdcs.srgb);
|
||||
let spectrum = Spectrum::RGBUnbounded(default_rgb);
|
||||
let texture = SpectrumTexture::Constant(SpectrumConstantTexture::new(spectrum));
|
||||
HairAbsorption::SigmaA(arena.upload(Arc::new(texture)))
|
||||
};
|
||||
|
||||
let material = HairMaterial::new(
|
||||
arena.upload(sigma_a),
|
||||
arena.upload(reflectance),
|
||||
arena.upload(eumelanin),
|
||||
arena.upload(pheomelanin),
|
||||
absorption,
|
||||
arena.upload(eta),
|
||||
arena.upload(beta_m),
|
||||
arena.upload(beta_n),
|
||||
arena.upload(alpha),
|
||||
stdcs.srgb,
|
||||
);
|
||||
|
||||
Ok(Material::Hair(material))
|
||||
|
|
|
|||
Loading…
Reference in a new issue