Skip to content

Commit

Permalink
Merge pull request #12118 from CesiumGS/ibl-multiscatter
Browse files Browse the repository at this point in the history
Add multiscattering terms to diffuse BRDF in image-based lighting
  • Loading branch information
ggetz authored Aug 12, 2024
2 parents dca302b + fc4a437 commit 80bfb86
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 46 deletions.
60 changes: 38 additions & 22 deletions Apps/Sandcastle/gallery/glTF PBR Extensions.html
Original file line number Diff line number Diff line change
Expand Up @@ -173,28 +173,16 @@
onselect: () => loadModel(2584329),
},
{
text: "Specular Test",
onselect: () => loadModel(2572779),
},
{
text: "Anisotropy Strength Test",
onselect: () => loadModel(2583526),
},
{
text: "Anisotropy Disc Test",
onselect: () => loadModel(2583858),
},
{
text: "Anisotropy Rotation Test",
onselect: () => loadModel(2583859),
text: "Damaged Helmet",
onselect: () => loadModel(2681021),
},
{
text: "Clear Coat Test",
onselect: () => loadModel(2584326),
text: "Water Bottle",
onselect: () => loadModel(2654597),
},
{
text: "Clear Coat Car Paint",
onselect: () => loadModel(2584328),
text: "Antique Camera",
onselect: () => loadModel(2681022),
},
{
text: "Toy Car",
Expand All @@ -209,17 +197,45 @@
onselect: () => loadModel(2583726),
},
{
text: "Metal-Roughness Spheres",
onselect: () => loadModel(2635364),
text: "Duck",
onselect: () => loadModel(2681027),
},
{
text: "Water Bottle",
onselect: () => loadModel(2654597),
text: "Environment Test",
onselect: () => loadModel(2681028),
},
{
text: "Mirror Ball",
onselect: () => loadModel(2674524),
},
{
text: "Metal-Roughness Spheres",
onselect: () => loadModel(2635364),
},
{
text: "Specular Test",
onselect: () => loadModel(2572779),
},
{
text: "Anisotropy Strength Test",
onselect: () => loadModel(2583526),
},
{
text: "Anisotropy Disc Test",
onselect: () => loadModel(2583858),
},
{
text: "Anisotropy Rotation Test",
onselect: () => loadModel(2583859),
},
{
text: "Clear Coat Test",
onselect: () => loadModel(2584326),
},
{
text: "Clear Coat Car Paint",
onselect: () => loadModel(2584328),
},
];
Sandcastle.addToolbarMenu(modelOptions, "modelsToolbar");
loadModel(2584329);
Expand Down
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

- Fixed cube-mapping artifacts in image-based lighting. [#12100](https://github.com/CesiumGS/cesium/pull/12100)
- Fixed specular reflection artifact in PBR direct lighting. [#12116](https://github.com/CesiumGS/cesium/pull/12116)
- Added multiscattering terms to diffuse BRDF in image-based lighting. [#12118](https://github.com/CesiumGS/cesium/pull/12118)

##### Breaking Changes :mega:

Expand Down
59 changes: 36 additions & 23 deletions packages/engine/Source/Shaders/Model/ImageBasedLightingStageFS.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ float getSunLuminance(vec3 positionWC, vec3 normalEC, vec3 lightDirectionEC)
}

#ifdef DIFFUSE_IBL
vec3 computeDiffuseIBL(vec3 cubeDir)
vec3 sampleDiffuseEnvironment(vec3 cubeDir)
{
#ifdef CUSTOM_SPHERICAL_HARMONICS
return czm_sphericalHarmonics(cubeDir, model_sphericalHarmonicCoefficients);
Expand Down Expand Up @@ -189,33 +189,51 @@ vec3 computeSpecularIBL(vec3 cubeDir, float NdotV, vec3 f0, float roughness)

#if defined(DIFFUSE_IBL) || defined(SPECULAR_IBL)
/**
* Compute the light contributions from environment maps and spherical harmonic coefficients
* Compute the light contributions from environment maps and spherical harmonic coefficients.
* See Fdez-Aguera, https://www.jcgt.org/published/0008/01/03/paper.pdf, for explanation
* of the single- and multi-scattering terms.
*
* @param {vec3} viewDirectionEC Unit vector pointing from the fragment to the eye position
* @param {vec3} normalEC The surface normal in eye coordinates
* @param {vec3} lightDirectionEC Unit vector pointing to the light source in eye coordinates.
* @param {vec3} viewDirectionEC Unit vector pointing from the fragment to the eye position.
* @param {vec3} normalEC The surface normal in eye coordinates.
* @param {czm_modelMaterial} The material properties.
* @return {vec3} The computed HDR color
* @return {vec3} The computed HDR color.
*/
vec3 textureIBL(
vec3 viewDirectionEC,
vec3 normalEC,
vec3 lightDirectionEC,
czm_modelMaterial material
) {
vec3 textureIBL(vec3 viewDirectionEC, vec3 normalEC, czm_modelMaterial material) {
vec3 f0 = material.specular;
float roughness = material.roughness;
float specularWeight = 1.0;
#ifdef USE_SPECULAR
specularWeight = material.specularWeight;
#endif
float NdotV = clamp(dot(normalEC, viewDirectionEC), 0.0, 1.0);

// see https://bruop.github.io/ibl/ at Single Scattering Results
// Roughness dependent fresnel, from Fdez-Aguera
vec3 f90 = max(vec3(1.0 - roughness), f0);
vec3 singleScatterFresnel = fresnelSchlick2(f0, f90, NdotV);

vec2 brdfLut = texture(czm_brdfLut, vec2(NdotV, roughness)).rg;
vec3 FssEss = specularWeight * (singleScatterFresnel * brdfLut.x + brdfLut.y);

#ifdef DIFFUSE_IBL
vec3 normalMC = normalize(model_iblReferenceFrameMatrix * normalEC);
vec3 diffuseContribution = computeDiffuseIBL(normalMC) * material.diffuse;
vec3 irradiance = sampleDiffuseEnvironment(normalMC);

vec3 averageFresnel = f0 + (1.0 - f0) / 21.0;
float Ems = specularWeight * (1.0 - brdfLut.x - brdfLut.y);
vec3 FmsEms = FssEss * averageFresnel * Ems / (1.0 - averageFresnel * Ems);
vec3 dielectricScattering = (1.0 - FssEss - FmsEms) * material.diffuse;
vec3 diffuseContribution = irradiance * (FmsEms + dielectricScattering);
#else
vec3 diffuseContribution = vec3(0.0);
vec3 diffuseContribution = vec3(0.0);
#endif

#ifdef USE_ANISOTROPY
// Bend normal to account for anisotropic distortion of specular reflection
vec3 anisotropyDirection = material.anisotropicB;
vec3 anisotropicTangent = cross(anisotropyDirection, viewDirectionEC);
vec3 anisotropicNormal = cross(anisotropicTangent, anisotropyDirection);
float bendFactor = 1.0 - material.anisotropyStrength * (1.0 - material.roughness);
float bendFactor = 1.0 - material.anisotropyStrength * (1.0 - roughness);
float bendFactorPow4 = bendFactor * bendFactor * bendFactor * bendFactor;
vec3 bentNormal = normalize(mix(anisotropicNormal, normalEC, bendFactorPow4));
vec3 reflectEC = reflect(-viewDirectionEC, bentNormal);
Expand All @@ -225,15 +243,10 @@ vec3 textureIBL(

#ifdef SPECULAR_IBL
vec3 reflectMC = normalize(model_iblReferenceFrameMatrix * reflectEC);
float NdotV = clamp(dot(normalEC, viewDirectionEC), 0.0, 1.0);
vec3 f0 = material.specular;
vec3 specularContribution = computeSpecularIBL(reflectMC, NdotV, f0, material.roughness);
vec3 radiance = sampleSpecularEnvironment(reflectMC, roughness);
vec3 specularContribution = radiance * FssEss;
#else
vec3 specularContribution = vec3(0.0);
#endif

#ifdef USE_SPECULAR
specularContribution *= material.specularWeight;
vec3 specularContribution = vec3(0.0);
#endif

return diffuseContribution + specularContribution;
Expand Down
2 changes: 1 addition & 1 deletion packages/engine/Source/Shaders/Model/LightingStageFS.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ vec3 computeIBL(vec3 position, vec3 normal, vec3 lightDirection, vec3 lightColor
#if defined(DIFFUSE_IBL) || defined(SPECULAR_IBL)
// Environment maps were provided, use them for IBL
vec3 viewDirection = -normalize(position);
vec3 iblColor = textureIBL(viewDirection, normal, lightDirection, material);
vec3 iblColor = textureIBL(viewDirection, normal, material);
#else
// Use procedural IBL if there are no environment maps
vec3 imageBasedLighting = proceduralIBL(position, normal, lightDirection, material);
Expand Down

0 comments on commit 80bfb86

Please sign in to comment.