Skip to content

Commit

Permalink
Merge pull request #556 from KhronosGroup/refactor/BRDF
Browse files Browse the repository at this point in the history
Refactor/brdf
  • Loading branch information
UX3D-labode authored Jul 23, 2024
2 parents 72357e9 + c22a47a commit 5e4e257
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 327 deletions.
52 changes: 19 additions & 33 deletions source/GltfState/gltf_state.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,8 @@ GltfState.DebugOutput = {
EMISSIVE: "Emissive",
},

/** output metallic roughness */
/** metallic roughness */
mr: {
/** output the combined metallic roughness */
METALLIC_ROUGHNESS: "Metallic Roughness",
/** output the base color value */
BASECOLOR: "Base Color",
/** output the metallic value from pbr metallic roughness */
Expand All @@ -161,69 +159,57 @@ GltfState.DebugOutput = {
ROUGHNESS: "Roughness",
},

/** output clearcoat lighting */
/** KHR_materials_clearcoat */
clearcoat: {
/** output the combined clear coat */
CLEARCOAT: "ClearCoat",
/** output the clear coat factor */
CLEARCOAT_FACTOR: "ClearCoat Factor",
/** output the clear coat strength */
CLEARCOAT_FACTOR: "ClearCoat Strength",
/** output the clear coat roughness */
CLEARCOAT_ROUGHNESS: "ClearCoat Roughness",
/** output the clear coat normal */
CLEARCOAT_NORMAL: "ClearCoat Normal",
},

/** output sheen lighting */
/** KHR_materials_sheen */
sheen: {
/** output the combined sheen */
SHEEN: "Sheen",
/** output the sheen color*/
SHEEN_COLOR: "Sheen Color",
/** output the sheen roughness*/
SHEEN_ROUGHNESS: "Sheen Roughness",
},

/** output specular lighting */
/** KHR_materials_specular */
specular: {
/** output the combined specular */
SPECULAR: "Specular",
/** output the specular factor*/
SPECULAR_FACTOR: "Specular Factor",
/** output the specular strength*/
SPECULAR_FACTOR: "Specular Strength",
/** output the specular color*/
SPECULAR_COLOR: "Specular Color",
},

/** output tranmission lighting */
/** KHR_materials_transmission */
transmission: {
/** output the combined transmission/volume */
TRANSMISSION_VOLUME: "Transmission/Volume",
/** output the transmission factor*/
TRANSMISSION_FACTOR: "Transmission Factor",
/** output the transmission strength*/
TRANSMISSION_FACTOR: "Transmission Strength",
/** output the volume thickness*/
VOLUME_THICKNESS: "Volume Thickness",
},

/** output diffuse tranmission lighting */
/** KHR_materials_diffuse_tranmission */
diffuseTransmission: {
/** output the combined diffuse tranmission */
DIFFUSE_TRANSMISSION: "Diffuse Transmission",
/** output the diffuse tranmission factor */
DIFFUSE_TRANSMISSION_FACTOR: "Diffuse Transmission Factor",
/** output the diffuse tranmission strength */
DIFFUSE_TRANSMISSION_FACTOR: "Diffuse Transmission Strength",
/** output the diffuse tranmission color factor */
DIFFUSE_TRANSMISSION_COLOR_FACTOR: "Diffuse Transmission Color Factor",
DIFFUSE_TRANSMISSION_COLOR_FACTOR: "Diffuse Transmission Color",
},

/** output iridescence */
/** KHR_materials_iridescence */
iridescence: {
/** output the combined iridescence */
IRIDESCENCE: "Iridescence",
/** output the iridescence factor*/
IRIDESCENCE_FACTOR: "Iridescence Factor",
/** output the iridescence strength*/
IRIDESCENCE_FACTOR: "Iridescence Strength",
/** output the iridescence thickness*/
IRIDESCENCE_THICKNESS: "Iridescence Thickness",
},

/** output anisotropy */
/** KHR_materials_anisotropy */
anisotropy: {
/** output the anisotropic strength*/
ANISOTROPIC_STRENGTH: "Anisotropic Strength",
Expand Down
48 changes: 7 additions & 41 deletions source/Renderer/shaders/brdf.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

// The following equation models the Fresnel reflectance term of the spec equation (aka F())
// Implementation of fresnel from [4], Equation 15
vec3 F_Schlick(vec3 f0, vec3 f90, float VdotH)
vec3 F_Schlick(vec3 f0, vec3 f90, float VdotH)
{
return f0 + (f90 - f0) * pow(clamp(1.0 - VdotH, 0.0, 1.0), 5.0);
}
Expand Down Expand Up @@ -149,54 +149,22 @@ float D_Charlie(float sheenRoughness, float NdotH)


//https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#acknowledgments AppendixB
vec3 BRDF_lambertian(vec3 f0, vec3 f90, vec3 diffuseColor, float specularWeight, float VdotH)
vec3 BRDF_lambertian(vec3 diffuseColor)
{
// see https://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/
return (1.0 - specularWeight * F_Schlick(f0, f90, VdotH)) * (diffuseColor / M_PI);
return (diffuseColor / M_PI);
}


#ifdef MATERIAL_IRIDESCENCE
//https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#acknowledgments AppendixB
vec3 BRDF_lambertianIridescence(vec3 f0, vec3 f90, vec3 iridescenceFresnel, float iridescenceFactor, vec3 diffuseColor, float specularWeight, float VdotH)
{
// Use the maximum component of the iridescence Fresnel color
// Maximum is used instead of the RGB value to not get inverse colors for the diffuse BRDF
vec3 iridescenceFresnelMax = vec3(max(max(iridescenceFresnel.r, iridescenceFresnel.g), iridescenceFresnel.b));

vec3 schlickFresnel = F_Schlick(f0, f90, VdotH);

// Blend default specular Fresnel with iridescence Fresnel
vec3 F = mix(schlickFresnel, iridescenceFresnelMax, iridescenceFactor);

// see https://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/
return (1.0 - specularWeight * F) * (diffuseColor / M_PI);
}
#endif


// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#acknowledgments AppendixB
vec3 BRDF_specularGGX(vec3 f0, vec3 f90, float alphaRoughness, float specularWeight, float VdotH, float NdotL, float NdotV, float NdotH)
vec3 BRDF_specularGGX(float alphaRoughness, float NdotL, float NdotV, float NdotH)
{
vec3 F = F_Schlick(f0, f90, VdotH);
float Vis = V_GGX(NdotL, NdotV, alphaRoughness);
float D = D_GGX(NdotH, alphaRoughness);

return specularWeight * F * Vis * D;
return vec3(Vis * D);
}


#ifdef MATERIAL_IRIDESCENCE
vec3 BRDF_specularGGXIridescence(vec3 f0, vec3 f90, vec3 iridescenceFresnel, float alphaRoughness, float iridescenceFactor, float specularWeight, float VdotH, float NdotL, float NdotV, float NdotH)
{
vec3 F = mix(F_Schlick(f0, f90, VdotH), iridescenceFresnel, iridescenceFactor);
float Vis = V_GGX(NdotL, NdotV, alphaRoughness);
float D = D_GGX(NdotH, alphaRoughness);

return specularWeight * F * Vis * D;
}
#endif

#ifdef MATERIAL_ANISOTROPY
// GGX Distribution Anisotropic (Same as Babylon.js)
// https://blog.selfshadow.com/publications/s2012-shading-course/burley/s2012_pbs_disney_brdf_notes_v3.pdf Addenda
Expand All @@ -218,7 +186,7 @@ float V_GGX_anisotropic(float NdotL, float NdotV, float BdotV, float TdotV, floa
return clamp(v, 0.0, 1.0);
}

vec3 BRDF_specularGGXAnisotropy(vec3 f0, vec3 f90, float alphaRoughness, float anisotropy, vec3 n, vec3 v, vec3 l, vec3 h, vec3 t, vec3 b)
vec3 BRDF_specularGGXAnisotropy(float alphaRoughness, float anisotropy, vec3 n, vec3 v, vec3 l, vec3 h, vec3 t, vec3 b)
{
// Roughness along the anisotropy bitangent is the material roughness, while the tangent roughness increases with anisotropy.
float at = mix(alphaRoughness, 1.0, anisotropy * anisotropy);
Expand All @@ -227,13 +195,11 @@ vec3 BRDF_specularGGXAnisotropy(vec3 f0, vec3 f90, float alphaRoughness, float a
float NdotL = clamp(dot(n, l), 0.0, 1.0);
float NdotH = clamp(dot(n, h), 0.001, 1.0);
float NdotV = dot(n, v);
float VdotH = clamp(dot(v, h), 0.0, 1.0);

float V = V_GGX_anisotropic(NdotL, NdotV, dot(b, v), dot(t, v), dot(t, l), dot(b, l), at, ab);
float D = D_GGX_anisotropic(NdotH, dot(t, h), dot(b, h), anisotropy, at, ab);

vec3 F = F_Schlick(f0, f90, VdotH);
return F * V * D;
return vec3(V * D);
}
#endif

Expand Down
7 changes: 7 additions & 0 deletions source/Renderer/shaders/functions.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,10 @@ float applyIorToRoughness(float roughness, float ior)
// an IOR of 1.5 results in the default amount of microfacet refraction.
return roughness * clamp(ior * 2.0 - 2.0, 0.0, 1.0);
}

vec3 rgb_mix(vec3 base, vec3 layer, vec3 rgb_alpha)
{
float rgb_alpha_max = max(rgb_alpha.r, max(rgb_alpha.g, rgb_alpha.b));
return (1.0 - rgb_alpha_max) * base + rgb_alpha * layer;
}

111 changes: 14 additions & 97 deletions source/Renderer/shaders/ibl.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -17,51 +17,36 @@ vec4 getSheenSample(vec3 reflection, float lod)
return textureLod(u_CharlieEnvSampler, u_EnvRotation * reflection, lod) * u_EnvIntensity;
}


vec3 getIBLRadianceGGX(vec3 n, vec3 v, float roughness, vec3 F0, float specularWeight)
vec3 getIBLGGXFresnel(vec3 n, vec3 v, float roughness, vec3 F0, float specularWeight)
{
// see https://bruop.github.io/ibl/#single_scattering_results at Single Scattering Results
// Roughness dependent fresnel, from Fdez-Aguera
float NdotV = clampedDot(n, v);
float lod = roughness * float(u_MipCount - 1);
vec3 reflection = normalize(reflect(-v, n));

vec2 brdfSamplePoint = clamp(vec2(NdotV, roughness), vec2(0.0, 0.0), vec2(1.0, 1.0));
vec2 f_ab = texture(u_GGXLUT, brdfSamplePoint).rg;
vec4 specularSample = getSpecularSample(reflection, lod);

vec3 specularLight = specularSample.rgb;

// see https://bruop.github.io/ibl/#single_scattering_results at Single Scattering Results
// Roughness dependent fresnel, from Fdez-Aguera
vec3 Fr = max(vec3(1.0 - roughness), F0) - F0;
vec3 k_S = F0 + Fr * pow(1.0 - NdotV, 5.0);
vec3 FssEss = k_S * f_ab.x + f_ab.y;
vec3 FssEss = specularWeight * (k_S * f_ab.x + f_ab.y);

return specularWeight * specularLight * FssEss;
}
// Multiple scattering, from Fdez-Aguera
float Ems = (1.0 - (f_ab.x + f_ab.y));
vec3 F_avg = specularWeight * (F0 + (1.0 - F0) / 21.0);
vec3 FmsEms = Ems * FssEss * F_avg / (1.0 - F_avg * Ems);

return FssEss + FmsEms;
}

#ifdef MATERIAL_IRIDESCENCE
vec3 getIBLRadianceGGXIridescence(vec3 n, vec3 v, float roughness, vec3 F0, vec3 iridescenceFresnel, float iridescenceFactor, float specularWeight)
vec3 getIBLRadianceGGX(vec3 n, vec3 v, float roughness)
{
float NdotV = clampedDot(n, v);
float lod = roughness * float(u_MipCount - 1);
vec3 reflection = normalize(reflect(-v, n));

vec2 brdfSamplePoint = clamp(vec2(NdotV, roughness), vec2(0.0, 0.0), vec2(1.0, 1.0));
vec2 f_ab = texture(u_GGXLUT, brdfSamplePoint).rg;
vec4 specularSample = getSpecularSample(reflection, lod);

vec3 specularLight = specularSample.rgb;

// see https://bruop.github.io/ibl/#single_scattering_results at Single Scattering Results
// Roughness dependent fresnel, from Fdez-Aguera
vec3 Fr = max(vec3(1.0 - roughness), F0) - F0;
vec3 k_S = mix(F0 + Fr * pow(1.0 - NdotV, 5.0), iridescenceFresnel, iridescenceFactor);
vec3 FssEss = k_S * f_ab.x + f_ab.y;

return specularWeight * specularLight * FssEss;
return specularLight;
}
#endif


#ifdef MATERIAL_TRANSMISSION
Expand Down Expand Up @@ -130,68 +115,8 @@ vec3 getIBLVolumeRefraction(vec3 n, vec3 v, float perceptualRoughness, vec3 base
#endif


// specularWeight is introduced with KHR_materials_specular
vec3 getIBLRadianceLambertian(vec3 n, vec3 v, float roughness, vec3 diffuseColor, vec3 F0, float specularWeight)
{
float NdotV = clampedDot(n, v);
vec2 brdfSamplePoint = clamp(vec2(NdotV, roughness), vec2(0.0, 0.0), vec2(1.0, 1.0));
vec2 f_ab = texture(u_GGXLUT, brdfSamplePoint).rg;

vec3 irradiance = getDiffuseLight(n);

// see https://bruop.github.io/ibl/#single_scattering_results at Single Scattering Results
// Roughness dependent fresnel, from Fdez-Aguera

vec3 Fr = max(vec3(1.0 - roughness), F0) - F0;
vec3 k_S = F0 + Fr * pow(1.0 - NdotV, 5.0);
vec3 FssEss = specularWeight * k_S * f_ab.x + f_ab.y; // <--- GGX / specular light contribution (scale it down if the specularWeight is low)

// Multiple scattering, from Fdez-Aguera
float Ems = (1.0 - (f_ab.x + f_ab.y));
vec3 F_avg = specularWeight * (F0 + (1.0 - F0) / 21.0);
vec3 FmsEms = Ems * FssEss * F_avg / (1.0 - F_avg * Ems);
vec3 k_D = diffuseColor * (1.0 - FssEss + FmsEms); // we use +FmsEms as indicated by the formula in the blog post (might be a typo in the implementation)

return (FmsEms + k_D) * irradiance;
}


#ifdef MATERIAL_IRIDESCENCE
// specularWeight is introduced with KHR_materials_specular
vec3 getIBLRadianceLambertianIridescence(vec3 n, vec3 v, float roughness, vec3 diffuseColor, vec3 F0, vec3 iridescenceF0, float iridescenceFactor, float specularWeight)
{
float NdotV = clampedDot(n, v);
vec2 brdfSamplePoint = clamp(vec2(NdotV, roughness), vec2(0.0, 0.0), vec2(1.0, 1.0));
vec2 f_ab = texture(u_GGXLUT, brdfSamplePoint).rg;

vec3 irradiance = getDiffuseLight(n);

// Use the maximum component of the iridescence Fresnel color
// Maximum is used instead of the RGB value to not get inverse colors for the diffuse BRDF
vec3 iridescenceF0Max = vec3(max(max(iridescenceF0.r, iridescenceF0.g), iridescenceF0.b));

// Blend between base F0 and iridescence F0
vec3 mixedF0 = mix(F0, iridescenceF0Max, iridescenceFactor);

// see https://bruop.github.io/ibl/#single_scattering_results at Single Scattering Results
// Roughness dependent fresnel, from Fdez-Aguera

vec3 Fr = max(vec3(1.0 - roughness), mixedF0) - mixedF0;
vec3 k_S = mixedF0 + Fr * pow(1.0 - NdotV, 5.0);
vec3 FssEss = specularWeight * k_S * f_ab.x + f_ab.y; // <--- GGX / specular light contribution (scale it down if the specularWeight is low)

// Multiple scattering, from Fdez-Aguera
float Ems = (1.0 - (f_ab.x + f_ab.y));
vec3 F_avg = specularWeight * (mixedF0 + (1.0 - mixedF0) / 21.0);
vec3 FmsEms = Ems * FssEss * F_avg / (1.0 - F_avg * Ems);
vec3 k_D = diffuseColor * (1.0 - FssEss + FmsEms); // we use +FmsEms as indicated by the formula in the blog post (might be a typo in the implementation)

return (FmsEms + k_D) * irradiance;
}
#endif

#ifdef MATERIAL_ANISOTROPY
vec3 getIBLRadianceAnisotropy(vec3 n, vec3 v, float roughness, float anisotropy, vec3 anisotropyDirection, vec3 F0, float specularWeight)
vec3 getIBLRadianceAnisotropy(vec3 n, vec3 v, float roughness, float anisotropy, vec3 anisotropyDirection)
{
float NdotV = clampedDot(n, v);

Expand All @@ -205,19 +130,11 @@ vec3 getIBLRadianceAnisotropy(vec3 n, vec3 v, float roughness, float anisotropy,
float lod = roughness * float(u_MipCount - 1);
vec3 reflection = normalize(reflect(-v, bentNormal));

vec2 brdfSamplePoint = clamp(vec2(NdotV, roughness), vec2(0.0, 0.0), vec2(1.0, 1.0));
vec2 f_ab = texture(u_GGXLUT, brdfSamplePoint).rg;
vec4 specularSample = getSpecularSample(reflection, lod);

vec3 specularLight = specularSample.rgb;

// see https://bruop.github.io/ibl/#single_scattering_results at Single Scattering Results
// Roughness dependent fresnel, from Fdez-Aguera
vec3 Fr = max(vec3(1.0 - roughness), F0) - F0;
vec3 k_S = F0 + Fr * pow(1.0 - NdotV, 5.0);
vec3 FssEss = k_S * f_ab.x + f_ab.y;

return specularWeight * specularLight * FssEss;
return specularLight;
}
#endif

Expand Down
Loading

0 comments on commit 5e4e257

Please sign in to comment.