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)));
345 return (
dot(
v, h) > 0.0f &&
dot(
v, m) > 0.0f);
362 return (1.0f + lambdaI) / (1.0f + lambdaI + lambdaO);
372 if (bsdf->extra->R <= 0.0f) {
377 const float b = bsdf->aspect_ratio;
381 const float roughness = bsdf->roughness;
382 const float roughness2 =
sqr(roughness);
387 float res = roughness * 0.7f;
389 const float h_range = bsdf->extra->h.length();
392 const size_t intervals = 2 * (size_t)
ceilf(h_range / res * 0.5f);
395 res = h_range /
float(intervals);
398 float integral = 0.0f;
399 for (
size_t i = 0;
i <= intervals;
i++) {
400 const float h = bsdf->extra->h.min +
i * res;
405 const float jacobian =
d_gamma_d_h(sincos_phi_i, gamma_m,
b);
406 const float weight = ((
i == 0 ||
i == intervals) ? 0.5f : (
i % 2 + 1)) * jacobian;
407 const float cos_mi =
dot(wm, wi);
416 integral *= (2.0f / 3.0f * res);
428 const float T_avg =
max(1.0f -
R, 1e-5f);
443 if (bsdf->extra->TT <= 0.0f && bsdf->extra->TRT <= 0.0f) {
448 const float b = bsdf->aspect_ratio;
451 const float eta = bsdf->eta;
452 const float inv_eta = 1.0f / eta;
454 const float roughness = bsdf->roughness;
455 const float roughness2 =
sqr(roughness);
456 const float sqrt_roughness =
sqrtf(roughness);
460 float res = roughness * 0.8f;
461 const float h_range = bsdf->extra->h.length();
462 const size_t intervals = 2 * (size_t)
ceilf(h_range / res * 0.5f);
463 res = h_range / intervals;
468 for (
size_t i = 0;
i <= intervals;
i++) {
469 const float h = bsdf->extra->h.min +
i * res;
480 const float cos_hi1 =
dot(wi, wh1);
481 if (!(cos_hi1 > 0.0f)) {
485 const float cos_mi1 =
dot(wi, wmi);
492 const float phi_t =
dir_phi(wt);
493 const float gamma_mt = 2.0f *
to_phi(phi_t,
b) - gamma_mi;
497 const float cos_mo1 =
dot(-wt, wmi);
498 const float cos_mi2 =
dot(-wt, wmt);
499 const float G1o =
bsdf_Go(roughness2, cos_mi1, cos_mo1);
504 const float jacobian =
d_gamma_d_h(sincos_phi_i, gamma_mi,
b);
505 const float weight = ((
i == 0 ||
i == intervals) ? 0.5f : (
i % 2 + 1)) * jacobian;
509 2.0f *
cosf(gamma_mi - phi_t) :
515 if (bsdf->extra->TT > 0.0f) {
516 if (
dot(wo, wt) >= inv_eta - 1e-5f) {
517 float3 wh2 = -wt + inv_eta * wo;
518 const float rcp_norm_wh2 = 1.0f /
len(wh2);
520 const float cos_mh2 =
dot(wmt, wh2);
521 if (cos_mh2 >= 0.0f) {
522 const float cos_hi2 =
dot(-wt, wh2);
523 const float cos_ho2 =
dot(-wo, wh2);
524 const float cos_mo2 =
dot(-wo, wmt);
531 cos_mi1 * cos_hi2 * cos_ho2 *
sqr(rcp_norm_wh2);
541 if (bsdf->extra->TRT > 0.0f) {
546 const float cos_hi2 =
dot(-wt, wh2);
547 if (!(cos_hi2 > 0.0f)) {
553 if (
dot(-wtr, wo) < inv_eta - 1e-5f) {
563 const float phi_tr =
dir_phi(wtr);
568 float3 wh3 = wtr + inv_eta * wo;
569 const float rcp_norm_wh3 = 1.0f /
len(wh3);
571 const float cos_mh3 =
dot(wmtr, wh3);
579 const float cos_hi3 =
dot(wh3, wtr);
580 const float cos_ho3 =
dot(wh3, -wo);
581 const float cos_mi3 =
dot(wmtr, wtr);
592 const float cos_mo2 =
dot(wmt, -wtr);
593 const float G2o =
bsdf_Go(roughness2, cos_mi2, cos_mo2);
596 const Spectrum result = weight *
T1 * scale1 * R2 * scale2 *
T3 * D3 * G1o * G2o * G3 * A_t *
597 A_tr / (cos_mo1 * cos_mo2) * cos_mi1 * cos_mi2 * cos_hi3 * cos_ho3 *
601 S_trt += bsdf->extra->TRT *
result *
arc_length(bsdf->extra->e2, gamma_mtr);
615 const float simpson_coeff = 2.0f / 3.0f * res;
617 return ((S_tt + S_trt) *
sqr(inv_eta) + S_trrt *
M *
N *
M_2_PI_F) * simpson_coeff;
632 *sampled_roughness =
make_float2(roughness, roughness);
637 float sample_lobe = rand.
x;
638 const float sample_h = rand.
y;
646 const float3 wi = bsdf->extra->wi;
649 const float b = bsdf->aspect_ratio;
652 const float h_div_r =
is_nearfield(bsdf) ? bsdf->h / bsdf->extra->radius :
653 (sample_h * 2.0f - 1.0f);
664 const float cos_mi1 =
dot(wmi, wi);
666 if (cos_mi1 < 0.0f ||
dot(wmi_, wi) < 0.0f) {
673 const float roughness2 =
sqr(roughness);
674 const float sqrt_roughness =
sqrtf(roughness);
691 const float inv_eta = 1.0f / bsdf->eta;
693 const float phi_t =
dir_phi(wt);
695 const float gamma_mt = 2.0f *
to_phi(phi_t,
b) - gamma_mi;
711 const float cos_mi2 =
dot(-wt, wmt);
717 2.0f *
cosf(phi_t - gamma_mi) :
722 const float T1 = (1.0f - R1) * scale1 *
bsdf_Go(roughness2, cos_mi1,
dot(wmi, -wt));
723 const float T2 = 1.0f - R2;
729 TT = bsdf->extra->TT *
T1 * A_t *
T2 * scale2 *
bsdf_Go(roughness2, cos_mi2,
dot(wmt, -wtt));
733 const float phi_tr =
dir_phi(wtr);
735 wmtr =
sphg_dir(-bsdf->tilt, gamma_mtr,
b);
737 wh3 =
sample_wh(roughness, wtr, wmtr, sample_h3);
744 const float cos_mi3 =
dot(wmtr, wtr);
745 if (cos_mi3 > 0.0f) {
755 const float T3 = 1.0f - R3;
759 bsdf_Go(roughness2, cos_mi3,
dot(wmtr, -wtrt));
768 const float fac = 1.0f +
769 4.0f * bsdf->roughness *
770 logf(rand_theta + (1.0f - rand_theta) *
expf(-0.5f / bsdf->roughness));
771 const float sin_theta_o = -fac *
sin_theta(wi) +
783 wtrrt =
make_float3(sin_phi_o * cos_theta_o, sin_theta_o, cos_phi_o * cos_theta_o);
789 const float T_avg =
max(0.5f * (
T2 +
T3), 1e-5f);
799 const float trt =
average(TRT);
800 const float trrt =
average(TRRT);
801 const float total_energy = r + tt + trt + trrt;
803 if (total_energy == 0.0f) {
810 sample_lobe *= total_energy;
811 if (sample_lobe < r) {
815 else if (sample_lobe < (r + tt)) {
817 *eval = TT / tt * total_energy;
819 else if (sample_lobe < (r + tt + trt)) {
821 *eval = TRT / trt * total_energy;
829 *wo =
to_global(local_O, bsdf->N, bsdf->extra->Y, bsdf->extra->Z);
849 const float3 local_I = bsdf->extra->wi;
850 const float3 local_O =
to_local(wo, bsdf->N, bsdf->extra->Y, bsdf->extra->Z);
856 const float tan_tilt =
tanf(bsdf->tilt);
857 if (tan_tilt *
tan_theta(local_O) < -1.0f) {
867 const float r = bsdf->extra->radius;
868 const float b = bsdf->aspect_ratio;
872 phi_to_h(phi_i - half_span,
b, local_I)};
882 const float half_pixel = bsdf->extra->pixel_coverage;
886 dh = nearfield_h.
length() / r;
904 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_albedo(const ccl_private ShaderData *, const ccl_private ShaderClosure *sc)
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 float3 sample_wh(const float roughness, const float3 wi, const float3 wm, const float2 rand)
ccl_device_inline float dir_phi(const float3 w)
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_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 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 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