Fix #114780: Cycles: Importance sampling correction #115241

Open
Amine Bensalem wants to merge 8 commits from HamilcarR/blender:cycles-114780_chiang-hair into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
1 changed files with 33 additions and 29 deletions

View File

@ -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;
}
}
@ -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;
}
@ -224,12 +226,13 @@ 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,
/* Updates sin_theta_o and cos_theta_o to account for scale tilt for each bounce. */
HamilcarR marked this conversation as resolved Outdated

also change theta_i to theta_o in the comment.
BTW the comment is quite misleading, considering it's not generating angles but sin_angles and cos_angles.
I would prefer rewriting it as:
/* Update sin_theta_o and cos_theta_o to account for scale tilt in each bounces. */

also change `theta_i` to `theta_o` in the comment. BTW the comment is quite misleading, considering it's not generating angles but sin_angles and cos_angles. I would prefer rewriting it as: `/* Update sin_theta_o and cos_theta_o to account for scale tilt in each bounces. */`
ccl_device_inline void hair_alpha_angles(float sin_theta_o,
float cos_theta_o,
float alpha,
ccl_private float *angles)
{
float sin_1alpha = sinf(alpha);
float cos_1alpha = cos_from_sin(sin_1alpha);
float sin_2alpha = 2.0f * sin_1alpha * cos_1alpha;
@ -237,12 +240,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. */
@ -293,17 +296,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);
@ -347,7 +350,9 @@ 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));
const float3 local_O = make_float3(dot(sd->wi, X), dot(sd->wi, Y), dot(sd->wi, Z));
/* wo in pbrt. */
HamilcarR marked this conversation as resolved Outdated

Put this comment above the code, add a period at the end of sentence

Put this comment above the code, add a period at the end of sentence
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;
const float cos_theta_o = cos_from_sin(sin_theta_o);
@ -387,18 +392,19 @@ ccl_device int bsdf_hair_chiang_sample(KernelGlobals kg,
v *= 4.0f;
}
HamilcarR marked this conversation as resolved Outdated

This comment does not explain what sinThetaOp and cosThetaOp are. Maybe:
/* Updated sin_theta_o and cos_theta_o accounting for scale tilt in each bounce. */
Remember to use proper English sentence, starting with a captical letter and ending with a full-stop: https://developer.blender.org/docs/handbook/guidelines/c_cpp/#comments
I would also prefer putting this comment above the variable.

This comment does not explain what `sinThetaOp` and `cosThetaOp` are. Maybe: `/* Updated sin_theta_o and cos_theta_o accounting for scale tilt in each bounce. */` Remember to use proper English sentence, starting with a captical letter and ending with a full-stop: https://developer.blender.org/docs/handbook/guidelines/c_cpp/#comments I would also prefer putting this comment above the variable.
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;
HamilcarR marked this conversation as resolved Outdated

I do not like this naming, because this variable has a concrete meaning and is therefore not temp, and it does not following the naming convention of the nearby code.
I suggest sin_theta_o_tilted

I do not like this naming, because this variable has a concrete meaning and is therefore not temp, and it does not following the naming convention of the nearby code. I suggest `sin_theta_o_tilted`

agreed , this was poorly named.

agreed , this was poorly named.
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)); /*cosTheta*/
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) {
@ -409,17 +415,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);