115 template<
typename CONF,
116 typename Fresnel=fresnel::complex<CONF, Spectrum_t<CONF>>,
119 size_t NewtonRaphsonSteps=4,
120 size_t TaylorTerms=40,
121 bool AdaptiveTaylor=
true,
122 literal RoughApproxThreshold=std::numeric_limits<Scalar_t<CONF>>::max(),
123 string_literal NAME=
"He">
requires concepts::config<CONF> && concepts::fresnel<Fresnel> && concepts::matching_config<CONF, Fresnel>
150 if(bbm::none(mask))
return 0;
153 Value S_term =
S(in, out, mask);
156 Value G_term =
G(in, out, mask);
159 Spectrum D_term =
D(in, out, mask);
162 Value cosThetaHalf = bbm::safe_sqrt( (1 + bbm::dot(in, out)) / 2.0 );
163 Spectrum F_term = Fresnel::eval(
eta, cosThetaHalf, mask);
169 return bbm::select(mask, normalization * F_term * S_term * G_term * D_term, 0);
230 mask &= (
vec::z(out) > 0);
233 if(bbm::none(mask))
return 0;
236 return Fresnel::eval(
eta.value(),
vec::z(out), mask) / Constants::Pi() * 4.0;
248 inline constexpr Value
S(
const Vec3d& in,
const Vec3d& out, Mask mask=
true)
const
250 return S1(in, mask) *
S1(out, mask);
266 inline constexpr Value
S1(
const Vec3d& v, Mask mask=
true)
const
269 Mask smooth = (
roughness < Constants::Epsilon());
272 if(bbm::all(smooth))
return 1;
279 Value erfc = 0.5*bbm::erfc( scaledCot );
282 Value Lambda = 0.5 * Constants::InvSqrtPi() / scaledCot;
283 if constexpr (EQ25 ==
he_eq25::Errata) Lambda *= bbm::exp(-bbm::pow(scaledCot,2.0));
287 Value
S =
bbm::select(smooth, 1.0, (1.0 - erfc) / (Lambda + 1.0));
306 inline constexpr Value
G(
const Vec3d& in,
const Vec3d& out, Mask mask=
true)
const
312 Value v_scale = bbm::pow(bbm::squared_norm(v) /
vec::z(v), 2.0);
338 Value kikr = bbm::dot(-in, out);
346 Value denom = bbm::pow(1.0 - kikr*kikr, 2.0);
347 Value nom = (bbm::pow(sikr,2.0) + bbm::pow(pikr,2.0)) * (bbm::pow(srki,2.0) + bbm::pow(prki,2.0)) / (krxn2*kixn2);
348 Value g =
bbm::select(denom > Constants::Epsilon(), v_scale * nom / denom, 1.0);
365 inline constexpr Value
sigma(
const Vec3d& in,
const Vec3d& out, Mask mask=
true)
const
368 mask &= (
roughness > Constants::Epsilon());
371 if(bbm::none(mask))
return 0;
378 auto K = [&](
const Value& tanTheta) {
return tanTheta * bbm::erfc(
autocorrelation / (2 *
roughness * tanTheta) ); };
379 Value Ki =
bbm::select( tanTheta_i > Constants::Epsilon(), K(tanTheta_i), 0 );
380 Value Ko =
bbm::select( tanTheta_o > Constants::Epsilon(), K(tanTheta_o), 0 );
383 Value f0 = bbm::rsqrt(Constants::Pi(8.0)) * (Ki + Ko);
384 Value x =
bbm::select(f0 <= 1.0, f0, bbm::safe_sqrt(2.0*bbm::log(f0)));
387 for(
size_t step=0; step < NewtonRaphsonSteps; ++step)
390 Value expn = bbm::exp(0.5*x*x);
391 Value
eval = x*expn - f0;
392 Value grad = (1+x*x)*expn;
411 inline constexpr Spectrum
D(
const Vec3d& in,
const Vec3d& out, Mask mask=
true)
const
421 auto normalization = Constants::Pi2(0.25) * tau2 / bbm::pow(Config::wavelength(), 2.0);
424 Spectrum exp_base = v_xy2 * tau2 / 4;
425 if constexpr (EQ78 ==
he_eq78::Westin) exp_base *= Constants::Pi2(4) / bbm::pow(Config::wavelength(), 2.0);
428 Mask approx = mask && (bbm::hmin(g) > Scalar(RoughApproxThreshold));
429 Spectrum roughApprox = 0;
433 roughApprox = bbm::exp( -exp_base / g ) / g;
438 weight = bbm::clamp(bbm::hmin(g) - Scalar(RoughApproxThreshold), 0, 1);
444 Spectrum last=-1, term=0;
445 Mask converged = !mask || ((bbm::hmin(g)-1) > Scalar(RoughApproxThreshold));
446 for(
size_t m=1; m <= TaylorTerms && bbm::any(!converged); ++m)
453 term = bbm::exp(-g - exp_base / m) * gm / m;
459 if constexpr (AdaptiveTaylor) converged |= (bbm::hmin(term) < Constants::Epsilon()) && (bbm::hmin(term) < bbm::hmin(last));
463 auto result = bbm::lerp(sum, roughApprox, weight);
466 return bbm::select(mask, normalization * result, 0);
490 using he =
ndf_sampler<he_base<CONF, fresnel::complex<CONF, Spectrum_t<CONF>>,
he_eq25::WithoutExp,
he_eq78::Regular, 4, 64,
true, 18>, 90, 1, NAME>;
493 using hewestin =
ndf_sampler<he_base<CONF, fresnel::complex<CONF, Spectrum_t<CONF>>,
he_eq25::Errata,
he_eq78::Westin, 4, 64,
true, 18>, 90, 1, NAME>;
496 using heholzschuch =
ndf_sampler<he_base<CONF, fresnel::complex<CONF, Spectrum_t<CONF>>,
he_eq25::Errata,
he_eq78::Regular, 4, 10,
false>, 90, 1, NAME>;
All includes and helpers needed for declaring new bsdfmodels.
#define BBM_EXPORT_BSDFMODEL(BsdfModel)
Definition: bbm_fromstring.h:49
The directional specular component of the He et al. BSDF model.
Definition: he.h:125
Spectrum eval(const Vec3d &in, const Vec3d &out, BsdfFlag component=bsdf_flag::All, unit_t=unit_t::Radiance, Mask mask=true) const
Evaluate the BSDF for a given in and out direction.
Definition: he.h:141
BsdfSample sample(const Vec3d &out, const Vec2d &xi, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const
Sample the diffuse BSDF given a direction and two random variables.
Definition: he.h:182
constexpr Value S1(const Vec3d &v, Mask mask=true) const
Mono-directional shadowing term.
Definition: he.h:266
constexpr Value S(const Vec3d &in, const Vec3d &out, Mask mask=true) const
Shadowing term.
Definition: he.h:248
constexpr Value G(const Vec3d &in, const Vec3d &out, Mask mask=true) const
Compute the Geometrical factor.
Definition: he.h:306
BBM_BSDF_FORWARD
Definition: he.h:129
constexpr Value sigma(const Vec3d &in, const Vec3d &out, Mask mask=true) const
Compute the effective surface roughness.
Definition: he.h:365
Value pdf(const Vec3d &in, const Vec3d &out, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const
Compute the pdf given an in and out direction.
Definition: he.h:205
BBM_ATTRIBUTES(roughness, autocorrelation, eta)
Spectrum reflectance(const Vec3d &out, BsdfFlag component=bsdf_flag::All, unit_t=unit_t::Radiance, Mask mask=true) const
Return the (approximate) hemispherical reflectance of the BSDF.
Definition: he.h:224
BBM_DEFAULT_CONSTRUCTOR(he_base)
Default Constructor.
Definition: he.h:481
constexpr Spectrum D(const Vec3d &in, const Vec3d &out, Mask mask=true) const
Distribution Function.
Definition: he.h:411
fresnel_parameter< typename std::decay_t< Fresnel >::parameter_type > eta
Definition: he.h:475
bsdf_parameter< Value, bsdf_attr::SpecularParameter, 3.0 > autocorrelation
Definition: he.h:474
static constexpr string_literal name
Definition: he.h:128
bsdf_parameter< Value, bsdf_attr::SpecularParameter, 0.18 > roughness
Definition: he.h:473
Definition: ndf_sampler.h:25
bsdfmodel concept
Definition: bsdfmodel.h:33
config concept
Definition: config.h:31
The classic diffuse Lambertian BSDF model.
#define BBM_CHECK_CONCEPT(CONCEPTNAME, CLASSNAME,...)
Check a class for a concept with bbm::concepts::archetypes in the namespace.
Definition: macro.h:35
T cosTheta(const vec2d< T > &v)
Definition: spherical.h:109
T tanTheta(const vec2d< T > &v)
Definition: spherical.h:177
constexpr decltype(auto) y(bbm::vec3d< T > &v)
Definition: vec.h:23
constexpr decltype(auto) z(bbm::vec3d< T > &v)
Definition: vec.h:26
constexpr decltype(auto) x(bbm::vec3d< T > &v)
Definition: vec.h:20
constexpr const vec2d< T > xy(const vec3d< T > &v)
Definition: vec.h:47
Definition: aggregatebsdf.h:29
constexpr auto select(MASK &&mask, const A &a, const A &b)
Definition: backbone.h:255
he_eq78
Eq. 78 variants:
Definition: he.h:78
he_eq25
Masking term scale in Eq 25.
Definition: he.h:65
constexpr auto is_set(const FLAGNAME &a, const FLAG &flag)
Check if all in 'flag' are also set in 'a'; compatible with packet types.
Definition: flags.h:100
unit_t
Light Unit.
Definition: unit.h:21
Base declaration of attribute; further specialized below.
Definition: attribute.h:26
Replaces a(n isotrpic) BSDF model's importance sampling with a data-driven NDF based sampler.
The classic diffuse Lambertian BSDF model.
Definition: lambertian.h:24
BsdfSample sample(const Vec3d &out, const Vec2d &xi, BsdfFlag component=bsdf_flag::All, unit_t unit=unit_t::Radiance, Mask mask=true) const
Sample the diffuse BSDF given a direction and two random variables.
Definition: lambertian.h:76
Value pdf(const Vec3d &in, const Vec3d &out, BsdfFlag component=bsdf_flag::All, unit_t=unit_t::Radiance, Mask mask=true) const
Compute the pdf given an in and out direction.
Definition: lambertian.h:115
Definition: string_literal.h:16