Skip to content

Commit

Permalink
Fix #114780: Cycles: Principled Chiang Hair importance sampling corre…
Browse files Browse the repository at this point in the history
…ction

Principled Chiang hair longitudinal importance sampling correction,
according to the new pbrt fix here :
mmp/pbrt-v3#256

Pull Request: https://projects.blender.org/blender/blender/pulls/115241
  • Loading branch information
HamilcarR authored and brechtvl committed Jun 26, 2024
1 parent 74d9161 commit 52039dd
Showing 1 changed file with 30 additions and 28 deletions.
58 changes: 30 additions & 28 deletions src/kernel/closure/bsdf_principled_hair_chiang.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,13 @@ ccl_device_inline float longitudinal_scattering(
if (v <= 0.1f) {
float i0 = log_bessel_I0(cos_arg);
float val = expf(i0 - sin_arg - inv_v + 0.6931f + logf(0.5f * inv_v));
kernel_assert(isfinite_safe(val));
return val;
}
else {
float i0 = bessel_I0(cos_arg);
float val = (expf(-sin_arg) * i0) / (sinhf(inv_v) * 2.0f * v);
kernel_assert(isfinite_safe(val));
return val;
}
}
Expand Down Expand Up @@ -185,7 +187,7 @@ ccl_device int bsdf_hair_chiang_setup(ccl_private ShaderData *sd, ccl_private Ch
kernel_assert(isfinite_safe(bsdf->h));

bsdf->N = Y;

bsdf->alpha = -bsdf->alpha;
return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_HAS_TRANSMISSION;
}

Expand Down Expand Up @@ -224,9 +226,9 @@ ccl_device_inline void hair_attenuation(
Ap_energy[3] *= fac;
}

/* Given the tilt angle, generate the rotated theta_i for the different bounces. */
ccl_device_inline void hair_alpha_angles(float sin_theta_i,
float cos_theta_i,
/* Update sin_theta_o and cos_theta_o to account for scale tilt for each bounce. */
ccl_device_inline void hair_alpha_angles(float sin_theta_o,
float cos_theta_o,
float alpha,
ccl_private float *angles)
{
Expand All @@ -237,12 +239,12 @@ ccl_device_inline void hair_alpha_angles(float sin_theta_i,
float sin_4alpha = 2.0f * sin_2alpha * cos_2alpha;
float cos_4alpha = sqr(cos_2alpha) - sqr(sin_2alpha);

angles[0] = sin_theta_i * cos_2alpha + cos_theta_i * sin_2alpha;
angles[1] = fabsf(cos_theta_i * cos_2alpha - sin_theta_i * sin_2alpha);
angles[2] = sin_theta_i * cos_1alpha - cos_theta_i * sin_1alpha;
angles[3] = fabsf(cos_theta_i * cos_1alpha + sin_theta_i * sin_1alpha);
angles[4] = sin_theta_i * cos_4alpha - cos_theta_i * sin_4alpha;
angles[5] = fabsf(cos_theta_i * cos_4alpha + sin_theta_i * sin_4alpha);
angles[0] = sin_theta_o * cos_2alpha - cos_theta_o * sin_2alpha;
angles[1] = fabsf(cos_theta_o * cos_2alpha + sin_theta_o * sin_2alpha);
angles[2] = sin_theta_o * cos_1alpha + cos_theta_o * sin_1alpha;
angles[3] = fabsf(cos_theta_o * cos_1alpha - sin_theta_o * sin_1alpha);
angles[4] = sin_theta_o * cos_4alpha + cos_theta_o * sin_4alpha;
angles[5] = fabsf(cos_theta_o * cos_4alpha - sin_theta_o * sin_4alpha);
}

/* Evaluation function for our shader. */
Expand Down Expand Up @@ -293,17 +295,17 @@ ccl_device Spectrum bsdf_hair_chiang_eval(KernelGlobals kg,
const float phi = phi_i - phi_o;

float angles[6];
hair_alpha_angles(sin_theta_i, cos_theta_i, bsdf->alpha, angles);
hair_alpha_angles(sin_theta_o, cos_theta_o, bsdf->alpha, angles);

Spectrum F = zero_spectrum();
float F_energy = 0.0f;

/* Primary specular (R), Transmission (TT) and Secondary Specular (TRT). */
for (int i = 0; i < 3; i++) {
const float Mp = longitudinal_scattering(angles[2 * i],
const float Mp = longitudinal_scattering(sin_theta_i,
cos_theta_i,
angles[2 * i],
angles[2 * i + 1],
sin_theta_o,
cos_theta_o,
(i == 0) ? bsdf->m0_roughness :
(i == 1) ? 0.25f * bsdf->v :
4.0f * bsdf->v);
Expand Down Expand Up @@ -347,6 +349,7 @@ ccl_device int bsdf_hair_chiang_sample(KernelGlobals kg,
kernel_assert(fabsf(dot(X, Y)) < 1e-3f);
const float3 Z = safe_normalize(cross(X, Y));

/* wo in pbrt. */
const float3 local_O = make_float3(dot(sd->wi, X), dot(sd->wi, Y), dot(sd->wi, Z));

const float sin_theta_o = local_O.x;
Expand Down Expand Up @@ -387,18 +390,19 @@ ccl_device int bsdf_hair_chiang_sample(KernelGlobals kg,
v *= 4.0f;
}

rand.z = max(rand.z, 1e-5f);
const float fac = 1.0f + v * logf(rand.z + (1.0f - rand.z) * expf(-2.0f / v));
float sin_theta_i = -fac * sin_theta_o +
cos_from_sin(fac) * cosf(M_2PI_F * rand.y) * cos_theta_o;
float cos_theta_i = cos_from_sin(sin_theta_i);

float angles[6];
hair_alpha_angles(sin_theta_o, cos_theta_o, bsdf->alpha, angles);
float sin_theta_o_tilted = sin_theta_o;
float cos_theta_o_tilted = cos_theta_o;
if (p < 3) {
hair_alpha_angles(sin_theta_i, cos_theta_i, -bsdf->alpha, angles);
sin_theta_i = angles[2 * p];
cos_theta_i = angles[2 * p + 1];
sin_theta_o_tilted = angles[2 * p];
cos_theta_o_tilted = angles[2 * p + 1];
}
rand.z = max(rand.z, 1e-5f);
const float fac = 1.0f + v * logf(rand.z + (1.0f - rand.z) * expf(-2.0f / v));
float sin_theta_i = -fac * sin_theta_o_tilted +
sin_from_cos(fac) * cosf(M_2PI_F * rand.y) * cos_theta_o_tilted;
float cos_theta_i = cos_from_sin(sin_theta_i);

float phi;
if (p < 3) {
Expand All @@ -409,17 +413,15 @@ ccl_device int bsdf_hair_chiang_sample(KernelGlobals kg,
}
const float phi_i = phi_o + phi;

hair_alpha_angles(sin_theta_i, cos_theta_i, bsdf->alpha, angles);

Spectrum F = zero_spectrum();
float F_energy = 0.0f;

/* Primary specular (R), Transmission (TT) and Secondary Specular (TRT). */
for (int i = 0; i < 3; i++) {
const float Mp = longitudinal_scattering(angles[2 * i],
const float Mp = longitudinal_scattering(sin_theta_i,
cos_theta_i,
angles[2 * i],
angles[2 * i + 1],
sin_theta_o,
cos_theta_o,
(i == 0) ? bsdf->m0_roughness :
(i == 1) ? 0.25f * bsdf->v :
4.0f * bsdf->v);
Expand Down

0 comments on commit 52039dd

Please sign in to comment.