Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add multibounce compensation #349

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/materials/PhysicalPathTracingMaterial.js
Original file line number Diff line number Diff line change
Expand Up @@ -810,7 +810,7 @@ export class PhysicalPathTracingMaterial extends MaterialBase {
// then we can just always assume this is a front face.
surfaceRec.frontFace = side == 1.0 || transmission == 0.0;
surfaceRec.eta = material.thinFilm || surfaceRec.frontFace ? 1.0 / material.ior : material.ior;
surfaceRec.f0 = iorRatioToF0( surfaceRec.eta );
surfaceRec.f0 = etaToF0( surfaceRec.eta );
surfaceRec.thinFilm = material.thinFilm;

// Compute the filtered roughness value to use during specular reflection computations.
Expand Down
30 changes: 30 additions & 0 deletions src/shader/shaderGGXFunctions.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,35 @@ float ggxPDF( vec3 wi, vec3 halfVector, float roughness ) {

return D * G1 * max( 0.0, dot( wi, halfVector ) ) / wi.z;

}

// https://github.com/AcademySoftwareFoundation/MaterialX/blob/main/libraries/pbrlib/genglsl/lib/mx_microfacet_specular.glsl#L113
// Rational quadratic fit to Monte Carlo data for GGX directional albedo.
vec3 ggxDirAlbedoAnalytic( float NdotV, float alpha, vec3 F0, vec3 F90 ) {

float x = NdotV;
float y = alpha;
float x2 = x * x;
float y2 = y * y;
vec4 r =
vec4( 0.1003, 0.9345, 1.0, 1.0 ) +
vec4( - 0.6303, - 2.323, - 1.765, 0.2281 ) * x +
vec4( 9.748, 2.229, 8.263, 15.94 ) * y +
vec4( - 2.038, - 3.748, 11.53, - 55.83 ) * x * y +
vec4( 29.34, 1.424, 28.96, 13.08 ) * x2 +
vec4( - 8.245, - 0.7684, - 7.507, 41.26 ) * y2 +
vec4( - 26.44, 1.436, - 36.11, 54.9 ) * x2 * y +
vec4( 19.99, 0.2913, 15.86, 300.2 ) * x * y2 +
vec4( - 5.448, 0.6286, 33.37, -285.1 ) * x2 * y2;
vec2 AB = clamp( r.xy / r.zw, 0.0, 1.0 );
return F0 * AB.x + F90 * AB.y;

}

vec3 ggxEnergyCompensation( float NdotV, float alpha, vec3 Fss ) {

float Ess = ggxDirAlbedoAnalytic( NdotV, alpha, vec3( 1.0 ), vec3( 1.0 ) ).r;
return 1.0 + Fss * ( 1.0 - Ess ) / Ess;

}
`;
7 changes: 4 additions & 3 deletions src/shader/shaderMaterialSampling.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,14 +129,15 @@ float specularEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRec surf, out vec3 color )
vec3 iridescenceF = evalIridescence( 1.0, surf.iridescenceIor, dot( wi, wh ), surf.iridescenceThickness, vec3( f0 ) );
vec3 iridescenceMix = mix( vec3( FM ), iridescenceF, surf.iridescence );
vec3 F = mix( specColor, vec3( 1.0 ), iridescenceMix );
vec3 comp = ggxEnergyCompensation( dot( wo, wh ), filteredRoughness, F );

color = mix( surf.specularIntensity, 1.0, surf.metalness ) * wi.z * F * G * D / ( 4.0 * abs( wi.z * wo.z ) );
color = mix( surf.specularIntensity, 1.0, surf.metalness ) * comp * wi.z * F * G * D / ( 4.0 * abs( wi.z * wo.z ) );

// PDF
// See 14.1.1 Microfacet BxDFs in https://www.pbr-book.org/
float incidentTheta = acos( wo.z );
float G1 = ggxShadowMaskG1( incidentTheta, filteredRoughness );
float ggxPdf = D * G1 * max( 0.0, abs( dot( wo, wh ) ) ) / abs ( wo.z );
float ggxPdf = D * G1 * max( 0.0, abs( dot( wo, wh ) ) ) / abs( wo.z );
return ggxPdf / ( 4.0 * dot( wo, wh ) );

}
Expand Down Expand Up @@ -242,11 +243,11 @@ vec3 transmissionDirection( vec3 wo, SurfaceRec surf ) {
float clearcoatEval( vec3 wo, vec3 wi, vec3 wh, SurfaceRec surf, inout vec3 color ) {

float ior = 1.5;
float f0 = iorRatioToF0( ior );
bool frontFace = surf.frontFace;
float filteredClearcoatRoughness = surf.filteredClearcoatRoughness;

float eta = frontFace ? 1.0 / ior : ior;
float f0 = etaToF0( eta );
float G = ggxShadowMaskG2( wi, wo, filteredClearcoatRoughness );
float D = ggxDistribution( wh, filteredClearcoatRoughness );
float F = schlickFresnel( dot( wi, wh ), f0 );
Expand Down
12 changes: 7 additions & 5 deletions src/shader/shaderUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ export const shaderUtils = /* glsl */`
// https://google.github.io/filament/Filament.md.html#materialsystem/diffusebrdf
float schlickFresnel( float cosine, float f0 ) {

return f0 + ( 1.0 - f0 ) * pow( 1.0 - cosine, 5.0 );
float f = pow( 1.0 - cosine, 5.0 );
return f + f0 * ( 1.0 - f );

}

vec3 schlickFresnel( float cosine, vec3 f0 ) {

return f0 + ( 1.0 - f0 ) * pow( 1.0 - cosine, 5.0 );
float f = pow( 1.0 - cosine, 5.0 );
return f + f0 * ( 1.0 - f );

}

Expand Down Expand Up @@ -45,10 +47,10 @@ export const shaderUtils = /* glsl */`

}

// https://raytracing.github.io/books/RayTracingInOneWeekend.html#dielectrics/schlickapproximation
float iorRatioToF0( float eta ) {
// https://google.github.io/filament/Filament.html#materialsystem/specularbrdf/fresnel(specularf)
float etaToF0( float eta ) {

return pow( ( 1.0 - eta ) / ( 1.0 + eta ), 2.0 );
return pow( eta - 1.0, 2.0 ) / pow( eta + 1.0, 2.0 );

}

Expand Down