Skip to content

Commit

Permalink
Additional HW closure improvements
Browse files Browse the repository at this point in the history
- Simplify references to closureData.occlusion across BSDFs.
- Merge and simplify code paths in chiang_hair_bsdf.
  • Loading branch information
jstone-lucasfilm committed Feb 12, 2025
1 parent 4e8deb3 commit f920f6e
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 105 deletions.
3 changes: 1 addition & 2 deletions libraries/pbrlib/genglsl/mx_burley_diffuse_bsdf.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ void mx_burley_diffuse_bsdf(ClosureData closureData, float weight, vec3 color, f

vec3 V = closureData.V;
vec3 L = closureData.L;
float occlusion = closureData.occlusion;

N = mx_forward_facing_normal(N, V);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
Expand All @@ -22,7 +21,7 @@ void mx_burley_diffuse_bsdf(ClosureData closureData, float weight, vec3 color, f
float NdotL = clamp(dot(N, L), M_FLOAT_EPS, 1.0);
float LdotH = clamp(dot(L, normalize(L + V)), M_FLOAT_EPS, 1.0);

bsdf.response = color * occlusion * weight * NdotL * M_PI_INV;
bsdf.response = color * closureData.occlusion * weight * NdotL * M_PI_INV;
bsdf.response *= mx_burley_diffuse(NdotV, NdotL, LdotH, roughness);
}
else if (closureData.closureType == CLOSURE_TYPE_INDIRECT)
Expand Down
161 changes: 69 additions & 92 deletions libraries/pbrlib/genglsl/mx_chiang_hair_bsdf.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -186,113 +186,90 @@ void mx_hair_attenuation(float f, vec3 T, out vec3 Ap[4]) // Ap
Ap[3] = Ap[2] * T * f / (vec3(1.0) - T * f);
}

vec3 mx_chiang_hair_bsdf_impl(
vec3 L,
vec3 V,
vec3 tint_R,
vec3 tint_TT,
vec3 tint_TRT,
float ior,
vec2 roughness_R,
vec2 roughness_TT,
vec2 roughness_TRT,
float cuticle_angle,
vec3 absorption_coefficient,
vec3 N,
vec3 X
)
{
N = mx_forward_facing_normal(N, V);
X = normalize(X - dot(X, N) * N);
vec3 Y = cross(N, X);

float sinThetaO = dot(V, X);
float sinThetaI = dot(L, X);
float cosThetaO = mx_hair_transform_sin_cos(sinThetaO);
float cosThetaI = mx_hair_transform_sin_cos(sinThetaI);

float y1 = dot(L, N);
float x1 = dot(L, Y);
float y2 = dot(V, N);
float x2 = dot(V, Y);
float phi = mx_atan(y1 * x2 - y2 * x1, x1 * x2 + y1 * y2);

vec3 k1_p = normalize(V - X * dot(V, X));
float cosGammaO = dot(N, k1_p);
float sinGammaO = mx_hair_transform_sin_cos(cosGammaO);
if (dot(k1_p, Y) > 0.0)
sinGammaO = -sinGammaO;
float gammaO = asin(sinGammaO);

float sinThetaT = sinThetaO / ior;
float cosThetaT = mx_hair_transform_sin_cos(sinThetaT);
float etaP = sqrt(max(ior * ior - sinThetaO * sinThetaO, 0.0)) / max(cosThetaO, 1e-8);
float sinGammaT = max(min(sinGammaO / etaP, 1.0), -1.0);
float cosGammaT = sqrt(1.0 - sinGammaT * sinGammaT);
float gammaT = asin(sinGammaT);

// attenuation
vec3 Ap[4];
float fresnel = mx_fresnel_dielectric(cosThetaO * cosGammaO, ior);
vec3 T = exp(-absorption_coefficient * (2.0 * cosGammaT / cosThetaT));
mx_hair_attenuation(fresnel, T, Ap);

// parameters for each lobe
vec2 angles[4];
float alpha = cuticle_angle * M_PI - (M_PI / 2.0); // remap [0, 1] to [-PI/2, PI/2]
mx_hair_alpha_angles(alpha, sinThetaI, cosThetaI, angles);

vec3 tint[4];
tint[0] = tint_R;
tint[1] = tint_TT;
tint[2] = tint_TRT;
tint[3] = tint_TRT;

roughness_R = clamp(roughness_R, 0.001, 1.0);
roughness_TT = clamp(roughness_TT, 0.001, 1.0);
roughness_TRT = clamp(roughness_TRT, 0.001, 1.0);

vec2 vs[4];
vs[0] = roughness_R;
vs[1] = roughness_TT;
vs[2] = roughness_TRT;
vs[3] = roughness_TRT;

// R, TT, TRT, TRRT+
vec3 F = vec3(0.0);
for (int i = 0; i <= 3; ++i)
{
tint[i] = max(tint[i], vec3(0.0));
float Mp = mx_hair_longitudinal_scattering(angles[i].x, angles[i].y, sinThetaO, cosThetaO, vs[i].x);
float Np = (i == 3) ? (1.0 / 2.0 * M_PI) : mx_hair_azimuthal_scattering(phi, i, vs[i].y, gammaO, gammaT);
F += Mp * Np * tint[i] * Ap[i];
}

return F;
}

void mx_chiang_hair_bsdf(ClosureData closureData, vec3 tint_R, vec3 tint_TT, vec3 tint_TRT, float ior,
vec2 roughness_R, vec2 roughness_TT, vec2 roughness_TRT, float cuticle_angle,
vec3 absorption_coefficient, vec3 N, vec3 X, inout BSDF bsdf)
{
vec3 V = closureData.V;
vec3 L = closureData.L;
float occlusion = closureData.occlusion;

N = mx_forward_facing_normal(N, V);

bsdf.throughput = vec3(0.0);

if (closureData.closureType == CLOSURE_TYPE_REFLECTION)
{
vec3 F = mx_chiang_hair_bsdf_impl(L, V, tint_R, tint_TT, tint_TRT, ior,
roughness_R, roughness_TT, roughness_TRT, cuticle_angle,
absorption_coefficient, N, X);
bsdf.response = F * occlusion * M_PI_INV;
X = normalize(X - dot(X, N) * N);
vec3 Y = cross(N, X);

float sinThetaO = dot(V, X);
float sinThetaI = dot(L, X);
float cosThetaO = mx_hair_transform_sin_cos(sinThetaO);
float cosThetaI = mx_hair_transform_sin_cos(sinThetaI);

float y1 = dot(L, N);
float x1 = dot(L, Y);
float y2 = dot(V, N);
float x2 = dot(V, Y);
float phi = mx_atan(y1 * x2 - y2 * x1, x1 * x2 + y1 * y2);

vec3 k1_p = normalize(V - X * dot(V, X));
float cosGammaO = dot(N, k1_p);
float sinGammaO = mx_hair_transform_sin_cos(cosGammaO);
if (dot(k1_p, Y) > 0.0)
sinGammaO = -sinGammaO;
float gammaO = asin(sinGammaO);

float sinThetaT = sinThetaO / ior;
float cosThetaT = mx_hair_transform_sin_cos(sinThetaT);
float etaP = sqrt(max(ior * ior - sinThetaO * sinThetaO, 0.0)) / max(cosThetaO, M_FLOAT_EPS);
float sinGammaT = max(min(sinGammaO / etaP, 1.0), -1.0);
float cosGammaT = sqrt(1.0 - sinGammaT * sinGammaT);
float gammaT = asin(sinGammaT);

// attenuation
vec3 Ap[4];
float fresnel = mx_fresnel_dielectric(cosThetaO * cosGammaO, ior);
vec3 T = exp(-absorption_coefficient * (2.0 * cosGammaT / cosThetaT));
mx_hair_attenuation(fresnel, T, Ap);

// parameters for each lobe
vec2 angles[4];
float alpha = cuticle_angle * M_PI - (M_PI / 2.0); // remap [0, 1] to [-PI/2, PI/2]
mx_hair_alpha_angles(alpha, sinThetaI, cosThetaI, angles);

vec3 tint[4];
tint[0] = tint_R;
tint[1] = tint_TT;
tint[2] = tint_TRT;
tint[3] = tint_TRT;

roughness_R = clamp(roughness_R, 0.001, 1.0);
roughness_TT = clamp(roughness_TT, 0.001, 1.0);
roughness_TRT = clamp(roughness_TRT, 0.001, 1.0);

vec2 vs[4];
vs[0] = roughness_R;
vs[1] = roughness_TT;
vs[2] = roughness_TRT;
vs[3] = roughness_TRT;

// R, TT, TRT, TRRT+
vec3 F = vec3(0.0);
for (int i = 0; i <= 3; ++i)
{
tint[i] = max(tint[i], vec3(0.0));
float Mp = mx_hair_longitudinal_scattering(angles[i].x, angles[i].y, sinThetaO, cosThetaO, vs[i].x);
float Np = (i == 3) ? (1.0 / 2.0 * M_PI) : mx_hair_azimuthal_scattering(phi, i, vs[i].y, gammaO, gammaT);
F += Mp * Np * tint[i] * Ap[i];
}

bsdf.response = F * closureData.occlusion * M_PI_INV;
}
else if (closureData.closureType == CLOSURE_TYPE_INDIRECT)
{
// This indirect term is a *very* rough approximation.

N = mx_forward_facing_normal(N, V);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
FresnelData fd = mx_init_fresnel_dielectric(ior, 0.0, 1.0);
vec3 F = mx_compute_fresnel(NdotV, fd);
Expand All @@ -301,7 +278,7 @@ void mx_chiang_hair_bsdf(ClosureData closureData, vec3 tint_R, vec3 tint_TT, vec
vec2 safeAlpha = clamp(roughness, M_FLOAT_EPS, 1.0);
float avgAlpha = mx_average_alpha(safeAlpha);

// Use GGX because the environment map for FIS is preintegrated with GGX.
// Use GGX to match the behavior of mx_environment_radiance.
float F0 = mx_ior_to_f0(ior);
vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F);
vec3 dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, F0, 1.0) * comp;
Expand Down
3 changes: 1 addition & 2 deletions libraries/pbrlib/genglsl/mx_conductor_bsdf.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ void mx_conductor_bsdf(ClosureData closureData, float weight, vec3 ior_n, vec3 i

vec3 V = closureData.V;
vec3 L = closureData.L;
float occlusion = closureData.occlusion;

N = mx_forward_facing_normal(N, V);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
Expand Down Expand Up @@ -40,7 +39,7 @@ void mx_conductor_bsdf(ClosureData closureData, float weight, vec3 ior_n, vec3 i
vec3 comp = mx_ggx_energy_compensation(NdotV, avgAlpha, F);

// Note: NdotL is cancelled out
bsdf.response = D * F * G * comp * occlusion * weight / (4.0 * NdotV);
bsdf.response = D * F * G * comp * closureData.occlusion * weight / (4.0 * NdotV);
}
else if (closureData.closureType == CLOSURE_TYPE_INDIRECT)
{
Expand Down
3 changes: 1 addition & 2 deletions libraries/pbrlib/genglsl/mx_dielectric_bsdf.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ void mx_dielectric_bsdf(ClosureData closureData, float weight, vec3 tint, float

vec3 V = closureData.V;
vec3 L = closureData.L;
float occlusion = closureData.occlusion;

N = mx_forward_facing_normal(N, V);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
Expand Down Expand Up @@ -45,7 +44,7 @@ void mx_dielectric_bsdf(ClosureData closureData, float weight, vec3 tint, float
vec3 dirAlbedo = mx_ggx_dir_albedo(NdotV, avgAlpha, F0, 1.0) * comp;
bsdf.throughput = 1.0 - dirAlbedo * weight;

bsdf.response = D * F * G * comp * safeTint * occlusion * weight / (4.0 * NdotV);
bsdf.response = D * F * G * comp * safeTint * closureData.occlusion * weight / (4.0 * NdotV);
}
else if (closureData.closureType == CLOSURE_TYPE_TRANSMISSION)
{
Expand Down
3 changes: 1 addition & 2 deletions libraries/pbrlib/genglsl/mx_generalized_schlick_bsdf.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ void mx_generalized_schlick_bsdf(ClosureData closureData, float weight, vec3 col

vec3 V = closureData.V;
vec3 L = closureData.L;
float occlusion = closureData.occlusion;

N = mx_forward_facing_normal(N, V);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
Expand Down Expand Up @@ -48,7 +47,7 @@ void mx_generalized_schlick_bsdf(ClosureData closureData, float weight, vec3 col
bsdf.throughput = vec3(1.0 - avgDirAlbedo * weight);

// Note: NdotL is cancelled out
bsdf.response = D * F * G * comp * occlusion * weight / (4.0 * NdotV);
bsdf.response = D * F * G * comp * closureData.occlusion * weight / (4.0 * NdotV);
}
else if (closureData.closureType == CLOSURE_TYPE_TRANSMISSION)
{
Expand Down
3 changes: 1 addition & 2 deletions libraries/pbrlib/genglsl/mx_oren_nayar_diffuse_bsdf.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ void mx_oren_nayar_diffuse_bsdf(ClosureData closureData, float weight, vec3 colo

vec3 V = closureData.V;
vec3 L = closureData.L;
float occlusion = closureData.occlusion;

N = mx_forward_facing_normal(N, V);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
Expand All @@ -25,7 +24,7 @@ void mx_oren_nayar_diffuse_bsdf(ClosureData closureData, float weight, vec3 colo
vec3 diffuse = energy_compensation ?
mx_oren_nayar_compensated_diffuse(NdotV, NdotL, LdotV, roughness, color) :
mx_oren_nayar_diffuse(NdotV, NdotL, LdotV, roughness) * color;
bsdf.response = diffuse * occlusion * weight * NdotL * M_PI_INV;
bsdf.response = diffuse * closureData.occlusion * weight * NdotL * M_PI_INV;
}
else if (closureData.closureType == CLOSURE_TYPE_INDIRECT)
{
Expand Down
5 changes: 2 additions & 3 deletions libraries/pbrlib/genglsl/mx_sheen_bsdf.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ void mx_sheen_bsdf(ClosureData closureData, float weight, vec3 color, float roug

vec3 V = closureData.V;
vec3 L = closureData.L;
float occlusion = closureData.occlusion;

N = mx_forward_facing_normal(N, V);
float NdotV = clamp(dot(N, V), M_FLOAT_EPS, 1.0);
Expand All @@ -30,15 +29,15 @@ void mx_sheen_bsdf(ClosureData closureData, float weight, vec3 color, float roug

// We need to include NdotL from the light integral here
// as in this case it's not cancelled out by the BRDF denominator.
bsdf.response = fr * NdotL * occlusion * weight;
bsdf.response = fr * NdotL * closureData.occlusion * weight;
}
else
{
roughness = clamp(roughness, 0.01, 1.0); // Clamp to range of original impl.

vec3 fr = color * mx_zeltner_sheen_brdf(L, V, N, NdotV, roughness);
dirAlbedo = mx_zeltner_sheen_dir_albedo(NdotV, roughness);
bsdf.response = dirAlbedo * fr * occlusion * weight;
bsdf.response = dirAlbedo * fr * closureData.occlusion * weight;
}
}
else if (closureData.closureType == CLOSURE_TYPE_INDIRECT)
Expand Down

0 comments on commit f920f6e

Please sign in to comment.