69static_assert(
sizeof(ShaderClosure) >=
sizeof(
HuangHairBSDF),
"HuangHairBSDF is too large!");
70static_assert(
sizeof(ShaderClosure) >=
sizeof(
HuangHairExtra),
"HuangHairExtra is too large!");
144 return atan2f(
b * sin_gamma, cos_gamma);
166 float sin_gamma, cos_gamma;
169 return -sin_cos_phi_i.
y * sin_gamma +
b * sin_cos_phi_i.
x * cos_gamma;
186 float sin_gamma, cos_gamma;
188 return safe_divide(1.0f, sincos_phi_i.
y * cos_gamma +
b * sincos_phi_i.
x * sin_gamma);
219 const float tan_gamma = sin_gamma / cos_gamma;
220 const float tan_phi =
b * tan_gamma;
229 return e2 == 0 ? 1.0f :
sqrtf(1.0f - e2 *
sqr(
sinf(gamma)));
234 return bsdf->extra->radius > bsdf->extra->pixel_coverage;
243 const uint32_t path_flag)
247 bsdf->roughness =
clamp(bsdf->roughness, 0.001f, 1.0f);
250 bsdf->tilt = -bsdf->tilt;
269 if (bsdf->aspect_ratio > 1.0f) {
271 bsdf->aspect_ratio = 1.0f / bsdf->aspect_ratio;
291 const float3 I =
to_local(sd->wi, bsdf->N, bsdf->extra->Y, bsdf->extra->Z);
293 bsdf->extra->e2 = 1.0f -
sqr(bsdf->aspect_ratio);
294 bsdf->extra->radius = bsdf->extra->e2 == 0 ?
299 if (
fabsf(bsdf->h) >= bsdf->extra->radius) {
302 sd->num_closure_left += 2;
319 const bool inv_table = (ior < 1.0f);
321 const float z =
sqrtf(
fabsf((ior - 1.0f) / (ior + 1.0f)));
343 return (
dot(
v, h) > 0.0f &&
dot(
v, m) > 0.0f);
360 return (1.0f + lambdaI) / (1.0f + lambdaI + lambdaO);
370 if (bsdf->extra->R <= 0.0f) {
375 const float b = bsdf->aspect_ratio;
379 const float roughness = bsdf->roughness;
380 const float roughness2 =
sqr(roughness);
385 float res = roughness * 0.7f;
387 const float h_range = bsdf->extra->h.length();
390 const size_t intervals = 2 * (size_t)
ceilf(h_range / res * 0.5f);
393 res = h_range / float(intervals);
396 float integral = 0.0f;
397 for (
size_t i = 0;
i <= intervals;
i++) {
398 const float h = bsdf->extra->h.min +
i * res;
403 const float jacobian =
d_gamma_d_h(sincos_phi_i, gamma_m,
b);
404 const float weight = ((
i == 0 ||
i == intervals) ? 0.5f : (
i % 2 + 1)) * jacobian;
405 const float cos_mi =
dot(wm, wi);
414 integral *= (2.0f / 3.0f * res);
426 const float T_avg =
max(1.0f -
R, 1e-5f);
441 if (bsdf->extra->TT <= 0.0f && bsdf->extra->TRT <= 0.0f) {
446 const float b = bsdf->aspect_ratio;
449 const float eta = bsdf->eta;
450 const float inv_eta = 1.0f / eta;
452 const float roughness = bsdf->roughness;
453 const float roughness2 =
sqr(roughness);
454 const float sqrt_roughness =
sqrtf(roughness);
458 float res = roughness * 0.8f;
459 const float h_range = bsdf->extra->h.length();
460 const size_t intervals = 2 * (size_t)
ceilf(h_range / res * 0.5f);
461 res = h_range / intervals;
466 for (
size_t i = 0;
i <= intervals;
i++) {
467 const float h = bsdf->extra->h.min +
i * res;
478 const float cos_hi1 =
dot(wi, wh1);
479 if (!(cos_hi1 > 0.0f)) {
483 const float cos_mi1 =
dot(wi, wmi);
490 const float phi_t =
dir_phi(wt);
491 const float gamma_mt = 2.0f *
to_phi(phi_t,
b) - gamma_mi;
495 const float cos_mo1 =
dot(-wt, wmi);
496 const float cos_mi2 =
dot(-wt, wmt);
497 const float G1o =
bsdf_Go(roughness2, cos_mi1, cos_mo1);
502 const float jacobian =
d_gamma_d_h(sincos_phi_i, gamma_mi,
b);
503 const float weight = ((
i == 0 ||
i == intervals) ? 0.5f : (
i % 2 + 1)) * jacobian;
507 2.0f *
cosf(gamma_mi - phi_t) :
513 if (bsdf->extra->TT > 0.0f) {
514 if (
dot(wo, wt) >= inv_eta - 1e-5f) {
515 float3 wh2 = -wt + inv_eta * wo;
516 const float rcp_norm_wh2 = 1.0f /
len(wh2);
518 const float cos_mh2 =
dot(wmt, wh2);
519 if (cos_mh2 >= 0.0f) {
520 const float cos_hi2 =
dot(-wt, wh2);
521 const float cos_ho2 =
dot(-wo, wh2);
522 const float cos_mo2 =
dot(-wo, wmt);
529 cos_mi1 * cos_hi2 * cos_ho2 *
sqr(rcp_norm_wh2);
539 if (bsdf->extra->TRT > 0.0f) {
544 const float cos_hi2 =
dot(-wt, wh2);
545 if (!(cos_hi2 > 0.0f)) {
551 if (
dot(-wtr, wo) < inv_eta - 1e-5f) {
561 const float phi_tr =
dir_phi(wtr);
566 float3 wh3 = wtr + inv_eta * wo;
567 const float rcp_norm_wh3 = 1.0f /
len(wh3);
569 const float cos_mh3 =
dot(wmtr, wh3);
577 const float cos_hi3 =
dot(wh3, wtr);
578 const float cos_ho3 =
dot(wh3, -wo);
579 const float cos_mi3 =
dot(wmtr, wtr);
590 const float cos_mo2 =
dot(wmt, -wtr);
591 const float G2o =
bsdf_Go(roughness2, cos_mi2, cos_mo2);
594 const Spectrum result = weight *
T1 * scale1 * R2 * scale2 *
T3 * D3 * G1o * G2o * G3 * A_t *
595 A_tr / (cos_mo1 * cos_mo2) * cos_mi1 * cos_mi2 * cos_hi3 * cos_ho3 *
599 S_trt += bsdf->extra->TRT *
result *
arc_length(bsdf->extra->e2, gamma_mtr);
613 const float simpson_coeff = 2.0f / 3.0f * res;
615 return ((S_tt + S_trt) *
sqr(inv_eta) + S_trrt *
M *
N *
M_2_PI_F) * simpson_coeff;
630 *sampled_roughness =
make_float2(roughness, roughness);
635 float sample_lobe = rand.
x;
636 const float sample_h = rand.
y;
644 const float3 wi = bsdf->extra->wi;
647 const float b = bsdf->aspect_ratio;
650 const float h_div_r =
is_nearfield(bsdf) ? bsdf->h / bsdf->extra->radius :
651 (sample_h * 2.0f - 1.0f);
662 const float cos_mi1 =
dot(wmi, wi);
664 if (cos_mi1 < 0.0f ||
dot(wmi_, wi) < 0.0f) {
671 const float roughness2 =
sqr(roughness);
672 const float sqrt_roughness =
sqrtf(roughness);
689 const float inv_eta = 1.0f / bsdf->eta;
691 const float phi_t =
dir_phi(wt);
693 const float gamma_mt = 2.0f *
to_phi(phi_t,
b) - gamma_mi;
709 const float cos_mi2 =
dot(-wt, wmt);
715 2.0f *
cosf(phi_t - gamma_mi) :
720 const float T1 = (1.0f - R1) * scale1 *
bsdf_Go(roughness2, cos_mi1,
dot(wmi, -wt));
721 const float T2 = 1.0f - R2;
727 TT = bsdf->extra->TT *
T1 * A_t *
T2 * scale2 *
bsdf_Go(roughness2, cos_mi2,
dot(wmt, -wtt));
731 const float phi_tr =
dir_phi(wtr);
733 wmtr =
sphg_dir(-bsdf->tilt, gamma_mtr,
b);
735 wh3 =
sample_wh(kg, roughness, wtr, wmtr, sample_h3);
742 const float cos_mi3 =
dot(wmtr, wtr);
743 if (cos_mi3 > 0.0f) {
753 const float T3 = 1.0f - R3;
757 bsdf_Go(roughness2, cos_mi3,
dot(wmtr, -wtrt));
766 const float fac = 1.0f +
767 4.0f * bsdf->roughness *
768 logf(rand_theta + (1.0f - rand_theta) *
expf(-0.5f / bsdf->roughness));
769 const float sin_theta_o = -fac *
sin_theta(wi) +
781 wtrrt =
make_float3(sin_phi_o * cos_theta_o, sin_theta_o, cos_phi_o * cos_theta_o);
787 const float T_avg =
max(0.5f * (
T2 +
T3), 1e-5f);
797 const float trt =
average(TRT);
798 const float trrt =
average(TRRT);
799 const float total_energy = r + tt + trt + trrt;
801 if (total_energy == 0.0f) {
808 sample_lobe *= total_energy;
809 if (sample_lobe < r) {
813 else if (sample_lobe < (r + tt)) {
815 *eval = TT / tt * total_energy;
817 else if (sample_lobe < (r + tt + trt)) {
819 *eval = TRT / trt * total_energy;
827 *wo =
to_global(local_O, bsdf->N, bsdf->extra->Y, bsdf->extra->Z);
847 const float3 local_I = bsdf->extra->wi;
848 const float3 local_O =
to_local(wo, bsdf->N, bsdf->extra->Y, bsdf->extra->Z);
854 const float tan_tilt =
tanf(bsdf->tilt);
855 if (tan_tilt *
tan_theta(local_O) < -1.0f) {
865 const float r = bsdf->extra->radius;
866 const float b = bsdf->aspect_ratio;
870 phi_to_h(phi_i - half_span,
b, local_I)};
880 const float half_pixel = bsdf->extra->pixel_coverage;
884 dh = nearfield_h.
length() / r;
902 const float projected_area =
cos_theta(local_I) * dh;
MINLINE float signf(float f)
MINLINE float safe_sqrtf(float a)
MINLINE float safe_divide(float a, float b)
ATTR_WARN_UNUSED_RESULT const BMVert * v
ccl_device_forceinline float3 microfacet_ggx_sample_vndf(const float3 wi, const float alpha_x, const float alpha_y, const float2 rand)
ccl_device_inline float bsdf_D(const float alpha2, const float cos_NH)
ccl_device_inline float bsdf_lambda(const float alpha2, const float cos_N)
ccl_device_inline float bsdf_G(const float alpha2, const float cos_N)
ccl_device_inline float longitudinal_scattering(float sin_theta_i, const float cos_theta_i, const float sin_theta_o, const float cos_theta_o, const float v)
ccl_device float2 sincos_phi(const float3 w)
ccl_device_inline float cos_theta(const float3 w)
ccl_device_inline float d_gamma_d_h(const float2 sincos_phi_i, const float gamma, const float b)
ccl_device_inline float arc_length(const float e2, const float gamma)
ccl_device Spectrum bsdf_hair_huang_eval_residual(KernelGlobals kg, const ccl_private ShaderClosure *sc, const float3 wi, const float3 wo, ccl_private uint *rng_quadrature)
ccl_device_inline bool is_nearfield(const ccl_private HuangHairBSDF *bsdf)
ccl_device_inline float bsdf_Go(const float alpha2, const float cos_NI, const float cos_NO)
ccl_device Spectrum bsdf_hair_huang_eval_r(KernelGlobals kg, const ccl_private ShaderClosure *sc, const float3 wi, const float3 wo)
ccl_device_inline float phi_to_h(const float phi, const float b, const float3 wi)
ccl_device_inline float3 sphg_dir(const float theta, const float gamma, const float b)
ccl_device_inline float2 to_point(const float gamma, const float b)
ccl_device_inline float to_gamma(const float phi, const float b)
ccl_device Spectrum bsdf_hair_huang_eval_trrt(const float T, const float R, const Spectrum A)
ccl_device_inline bool microfacet_visible(const float3 v, const float3 m, const float3 h)
ccl_device_inline float2 dir_sph(const float3 w)
ccl_device_inline float tan_theta(const float3 w)
ccl_device void bsdf_hair_huang_blur(ccl_private ShaderClosure *sc, const float roughness)
ccl_device_forceinline float bsdf_hair_huang_energy_scale(KernelGlobals kg, const float mu, const float rough, const float ior)
ccl_device float sin_phi(const float3 w)
ccl_device_inline float dir_phi(const float3 w)
ccl_device_inline float3 sample_wh(KernelGlobals kg, const float roughness, const float3 wi, const float3 wm, const float2 rand)
ccl_device int bsdf_hair_huang_sample(const KernelGlobals kg, const ccl_private ShaderClosure *sc, ccl_private ShaderData *sd, const float3 rand, ccl_private Spectrum *eval, ccl_private float3 *wo, ccl_private float *pdf, ccl_private float2 *sampled_roughness)
ccl_device Spectrum bsdf_hair_huang_eval(KernelGlobals kg, ccl_private ShaderData *sd, const ccl_private ShaderClosure *sc, const float3 wo, ccl_private float *pdf)
ccl_device_inline float sin_theta(const float3 w)
ccl_device_inline float to_phi(const float gamma, const float b)
ccl_device_inline bool is_circular(const float b)
ccl_device Spectrum bsdf_hair_huang_albedo(const ccl_private ShaderData *sd, const ccl_private ShaderClosure *sc)
ccl_device_inline float dir_theta(const float3 w)
ccl_device_inline float h_to_gamma(const float h_div_r, const float b, const float3 wi)
CCL_NAMESPACE_BEGIN ccl_device void bsdf_transparent_setup(ccl_private ShaderData *sd, const Spectrum weight, const uint32_t path_flag)
ccl_device float fresnel_dielectric_cos(const float cosi, const float eta)
ccl_device_forceinline float fresnel_dielectric(const float cos_theta_i, const float eta, ccl_private float *r_cos_theta_t)
ccl_device_inline float3 refract_angle(const float3 incident, const float3 normal, const float cos_theta_t, const float inv_eta)
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
ccl_device_inline T to_global(const float2 p, const T X, const T Y)
ccl_device_inline float2 to_local(const T p, const T X, const T Y)
#define kernel_assert(cond)
#define ccl_device_forceinline
const ThreadKernelGlobalsCPU * KernelGlobals
#define ccl_device_inline
#define CCL_NAMESPACE_END
VecBase< T, D > reflect(VecOp< T, D >, VecOp< T, D >) RET
VecBase< float, D > normalize(VecOp< float, D >) RET
VecBase< float, 3 > cross(VecOp< float, 3 >, VecOp< float, 3 >) RET
constexpr T clamp(T, U, U) RET
@ CLOSURE_BSDF_HAIR_HUANG_ID
@ SD_BSDF_HAS_TRANSMISSION
ccl_device float lcg_step_float(T rng)
ccl_device float lookup_table_read_3D(KernelGlobals kg, const float x, float y, float z, const int offset, const int xsize, const int ysize, const int zsize)
ccl_device_inline bool isnan_safe(const float f)
ccl_device_inline float sqr(const float a)
ccl_device_inline float inversesqrtf(const float f)
ccl_device_inline Interval< T > intervals_intersection(const ccl_private Interval< T > &first, const ccl_private Interval< T > &second)
ccl_device_inline bool isfinite_safe(const float f)
ccl_device_inline float cos_from_sin(const float s)
ccl_device void fast_sincosf(float x, ccl_private float *sine, ccl_private float *cosine)
ccl_device float fast_sinf(float x)
ccl_device float fast_cosf(float x)
ccl_device_inline bool is_zero(const float2 a)
ccl_device_inline float average(const float2 a)
ccl_device_inline float2 safe_normalize(const float2 a)
CCL_NAMESPACE_BEGIN ccl_device_inline float3 zero_float3()
ccl_device_inline void make_orthonormals(const float3 N, ccl_private float3 *a, ccl_private float3 *b)
ccl_private HuangHairExtra * extra
ccl_device_inline_method T length() const
ccl_device_inline_method bool is_empty() const