42static_assert(
sizeof(ShaderClosure) >=
sizeof(
ChiangHairBSDF),
"ChiangHairBSDF is too large!");
48 return 2.0f * p * gamma_t - 2.0f * gamma_o + p *
M_PI_F;
61 return v / (s *
sqr(1.0f +
v));
67 const float arg = -
x / s;
72 return 1.0f / (1.0f +
expf(arg));
79 float val = 1.0f + 0.25f *
x;
80 float pow_x_2i =
sqr(
x);
83 for (
int i = 2;
i < 10;
i++) {
85 const float newval = val + pow_x_2i / (pow_4_i * i_fac_2);
122 const float x = -s *
logf(1.0f / (u * (1.0f - 2.0f * cdf_minuspi) + cdf_minuspi) - 1.0f);
128 float phi,
const int p,
const float s,
float gamma_o,
const float gamma_t)
137 const float cos_theta_i,
138 const float sin_theta_o,
139 const float cos_theta_o,
142 const float inv_v = 1.0f /
v;
143 const float cos_arg = cos_theta_i * cos_theta_o * inv_v;
144 const float sin_arg = sin_theta_i * sin_theta_o * inv_v;
147 const float val =
expf(i0 - sin_arg - inv_v + 0.6931f +
logf(0.5f * inv_v));
152 const float val = (
expf(-sin_arg) * i0) / (
sinhf(inv_v) * 2.0f *
v);
162 bsdf->v =
clamp(bsdf->v, 0.001f, 1.0f);
163 bsdf->s =
clamp(bsdf->s, 0.001f, 1.0f);
165 bsdf->m0_roughness =
clamp(bsdf->m0_roughness * bsdf->v, 0.001f, 1.0f);
168 bsdf->v =
sqr(0.726f * bsdf->v + 0.812f *
sqr(bsdf->v) + 3.700f *
pow20(bsdf->v));
170 bsdf->m0_roughness =
sqr(0.726f * bsdf->m0_roughness + 0.812f *
sqr(bsdf->m0_roughness) +
171 3.700f *
pow20(bsdf->m0_roughness));
192 bsdf->alpha = -bsdf->alpha;
225 const float totweight = Ap_energy[0] + Ap_energy[1] + Ap_energy[2] + Ap_energy[3];
236 const float cos_theta_o,
240 const float sin_1alpha =
sinf(alpha);
242 const float sin_2alpha = 2.0f * sin_1alpha * cos_1alpha;
243 const float cos_2alpha =
sqr(cos_1alpha) -
sqr(sin_1alpha);
244 const float sin_4alpha = 2.0f * sin_2alpha * cos_2alpha;
245 const float cos_4alpha =
sqr(cos_2alpha) -
sqr(sin_2alpha);
247 angles[0] = sin_theta_o * cos_2alpha - cos_theta_o * sin_2alpha;
248 angles[1] =
fabsf(cos_theta_o * cos_2alpha + sin_theta_o * sin_2alpha);
249 angles[2] = sin_theta_o * cos_1alpha + cos_theta_o * sin_1alpha;
250 angles[3] =
fabsf(cos_theta_o * cos_1alpha - sin_theta_o * sin_1alpha);
251 angles[4] = sin_theta_o * cos_4alpha + cos_theta_o * sin_4alpha;
252 angles[5] =
fabsf(cos_theta_o * cos_4alpha - sin_theta_o * sin_4alpha);
275 const float sin_theta_o = local_O.
x;
277 const float phi_o =
atan2f(local_O.
z, local_O.
y);
279 const float sin_theta_t = sin_theta_o / bsdf->eta;
282 const float sin_gamma_o = bsdf->h;
284 const float gamma_o =
safe_asinf(sin_gamma_o);
286 const float sin_gamma_t = sin_gamma_o * cos_theta_o /
sqrtf(
sqr(bsdf->eta) -
sqr(sin_theta_o));
288 const float gamma_t =
safe_asinf(sin_gamma_t);
290 const Spectrum T =
exp(-bsdf->sigma * (2.0f * cos_gamma_t / cos_theta_t));
296 const float sin_theta_i = local_I.
x;
298 const float phi_i =
atan2f(local_I.
z, local_I.
y);
300 const float phi = phi_i - phi_o;
306 float F_energy = 0.0f;
309 for (
int i = 0;
i < 3;
i++) {
314 (
i == 0) ? bsdf->m0_roughness :
315 (
i == 1) ? 0.25f * bsdf->v :
318 F += Ap[
i] * Mp * Np;
319 F_energy += Ap_energy[
i] * Mp * Np;
326 sin_theta_i, cos_theta_i, sin_theta_o, cos_theta_o, 4.0f * bsdf->v);
328 F += Ap[3] * Mp * Np;
329 F_energy += Ap_energy[3] * Mp * Np;
349 *sampled_roughness =
make_float2(bsdf->m0_roughness, bsdf->m0_roughness);
360 const float sin_theta_o = local_O.
x;
362 const float phi_o =
atan2f(local_O.
z, local_O.
y);
364 const float sin_theta_t = sin_theta_o / bsdf->eta;
367 const float sin_gamma_o = bsdf->h;
369 const float gamma_o =
safe_asinf(sin_gamma_o);
371 const float sin_gamma_t = sin_gamma_o * cos_theta_o /
sqrtf(
sqr(bsdf->eta) -
sqr(sin_theta_o));
373 const float gamma_t =
safe_asinf(sin_gamma_t);
375 const Spectrum T =
exp(-bsdf->sigma * (2.0f * cos_gamma_t / cos_theta_t));
383 if (rand.
z < Ap_energy[p]) {
386 rand.
z -= Ap_energy[p];
388 rand.
z /= Ap_energy[p];
400 float sin_theta_o_tilted = sin_theta_o;
401 float cos_theta_o_tilted = cos_theta_o;
403 sin_theta_o_tilted = angles[2 * p];
404 cos_theta_o_tilted = angles[2 * p + 1];
406 rand.
z =
max(rand.
z, 1e-5f);
407 const float fac = 1.0f +
v *
logf(rand.
z + (1.0f - rand.
z) *
expf(-2.0f /
v));
408 const float sin_theta_i = -fac * sin_theta_o_tilted +
419 const float phi_i = phi_o + phi;
422 float F_energy = 0.0f;
425 for (
int i = 0;
i < 3;
i++) {
430 (
i == 0) ? bsdf->m0_roughness :
431 (
i == 1) ? 0.25f * bsdf->v :
434 F += Ap[
i] * Mp * Np;
435 F_energy += Ap_energy[
i] * Mp * Np;
442 sin_theta_i, cos_theta_i, sin_theta_o, cos_theta_o, 4.0f * bsdf->v);
444 F += Ap[3] * Mp * Np;
445 F_energy += Ap_energy[3] * Mp * Np;
461 bsdf->
v =
fmaxf(roughness, bsdf->v);
462 bsdf->s =
fmaxf(roughness, bsdf->s);
463 bsdf->m0_roughness =
fmaxf(roughness, bsdf->m0_roughness);
MINLINE float safe_divide(float a, float b)
MINLINE float safe_asinf(float a)
ATTR_WARN_UNUSED_RESULT const BMVert * v
ccl_device_inline void hair_attenuation(KernelGlobals kg, const float f, Spectrum T, ccl_private Spectrum *Ap, ccl_private float *Ap_energy)
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_inline float delta_phi(const int p, const float gamma_o, const float gamma_t)
ccl_device int bsdf_hair_chiang_sample(KernelGlobals kg, const ccl_private ShaderClosure *sc, ccl_private ShaderData *sd, float3 rand, ccl_private Spectrum *eval, ccl_private float3 *wo, ccl_private float *pdf, ccl_private float2 *sampled_roughness)
ccl_device_inline float trimmed_logistic(const float x, const float s)
ccl_device_inline void hair_alpha_angles(const float sin_theta_o, const float cos_theta_o, const float alpha, ccl_private float *angles)
ccl_device_inline float logistic_cdf(const float x, const float s)
ccl_device_inline float sample_trimmed_logistic(const float u, const float s)
ccl_device Spectrum bsdf_hair_chiang_eval(KernelGlobals kg, const ccl_private ShaderData *sd, const ccl_private ShaderClosure *sc, const float3 wo, ccl_private float *pdf)
ccl_device_inline float wrap_angle(const float a)
ccl_device_inline float logistic(const float x, const float s)
ccl_device_inline float bessel_I0(float x)
ccl_device void bsdf_hair_chiang_blur(ccl_private ShaderClosure *sc, const float roughness)
ccl_device_inline float azimuthal_scattering(float phi, const int p, const float s, float gamma_o, const float gamma_t)
ccl_device Spectrum bsdf_hair_chiang_albedo(const ccl_private ShaderData *sd, const ccl_private ShaderClosure *sc)
ccl_device_inline float log_bessel_I0(const float x)
ccl_device float fresnel_dielectric_cos(const float cosi, const float eta)
ccl_device_inline float bsdf_principled_hair_albedo_roughness_scale(const float azimuthal_roughness)
unsigned long long int uint64_t
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
ccl_device float3 spherical_cos_to_direction(const float cos_theta, const float phi)
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)
const ThreadKernelGlobalsCPU * KernelGlobals
#define ccl_device_inline
#define CCL_NAMESPACE_END
VecBase< float, 3 > cross(VecOp< float, 3 >, VecOp< float, 3 >) RET
constexpr T clamp(T, U, U) RET
@ CLOSURE_BSDF_HAIR_CHIANG_ID
@ SD_BSDF_HAS_TRANSMISSION
ccl_device float spectrum_to_gray(KernelGlobals kg, Spectrum c)
ccl_device_inline float pow22(const float a)
ccl_device_inline float sin_from_cos(const float c)
ccl_device_inline float pow20(const float a)
ccl_device_inline bool isfinite_safe(const float f)
ccl_device_inline float cos_from_sin(const float s)
ccl_device_inline float2 safe_normalize(const float2 a)