diff --git a/source/GltfState/gltf_state.js b/source/GltfState/gltf_state.js index ecea059c..ab1e6f4e 100644 --- a/source/GltfState/gltf_state.js +++ b/source/GltfState/gltf_state.js @@ -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 */ @@ -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", diff --git a/source/Renderer/shaders/brdf.glsl b/source/Renderer/shaders/brdf.glsl index dcb55ce5..da16c3d3 100644 --- a/source/Renderer/shaders/brdf.glsl +++ b/source/Renderer/shaders/brdf.glsl @@ -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); } @@ -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 @@ -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); @@ -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 diff --git a/source/Renderer/shaders/functions.glsl b/source/Renderer/shaders/functions.glsl index 1c7db9f0..b9179a0f 100644 --- a/source/Renderer/shaders/functions.glsl +++ b/source/Renderer/shaders/functions.glsl @@ -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; +} + diff --git a/source/Renderer/shaders/ibl.glsl b/source/Renderer/shaders/ibl.glsl index a2d2ff77..875fbed7 100644 --- a/source/Renderer/shaders/ibl.glsl +++ b/source/Renderer/shaders/ibl.glsl @@ -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 @@ -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); @@ -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 diff --git a/source/Renderer/shaders/material_info.glsl b/source/Renderer/shaders/material_info.glsl index d5b0a003..380c6689 100644 --- a/source/Renderer/shaders/material_info.glsl +++ b/source/Renderer/shaders/material_info.glsl @@ -68,12 +68,14 @@ struct MaterialInfo { float ior; float perceptualRoughness; // roughness value, as authored by the model creator (input to shader) - vec3 f0; // full reflectance color (n incidence angle) + vec3 f0_dielectric; float alphaRoughness; // roughness mapped to a more linear change in the roughness (proposed by [2]) - vec3 c_diff; + + float fresnel_w; vec3 f90; // reflectance color at grazing angle + vec3 f90_dielectric; float metallic; vec3 baseColor; @@ -218,17 +220,16 @@ vec4 getBaseColor() #ifdef MATERIAL_SPECULARGLOSSINESS MaterialInfo getSpecularGlossinessInfo(MaterialInfo info) { - info.f0 = u_SpecularFactor; + info.f0_dielectric = u_SpecularFactor; info.perceptualRoughness = u_GlossinessFactor; #ifdef HAS_SPECULAR_GLOSSINESS_MAP vec4 sgSample = texture(u_SpecularGlossinessSampler, getSpecularGlossinessUV()); info.perceptualRoughness *= sgSample.a ; // glossiness to roughness - info.f0 *= sgSample.rgb; // specular + info.f0_dielectric *= sgSample.rgb; // specular #endif // ! HAS_SPECULAR_GLOSSINESS_MAP info.perceptualRoughness = 1.0 - info.perceptualRoughness; // 1 - glossiness - info.c_diff = info.baseColor.rgb * (1.0 - max(max(info.f0.r, info.f0.g), info.f0.b)); return info; } #endif @@ -248,9 +249,6 @@ MaterialInfo getMetallicRoughnessInfo(MaterialInfo info) info.metallic *= mrSample.b; #endif - // Achromatic f0 based on IOR. - info.c_diff = mix(info.baseColor.rgb, vec3(0), info.metallic); - info.f0 = mix(info.f0, info.baseColor.rgb, info.metallic); return info; } #endif @@ -287,10 +285,9 @@ MaterialInfo getSpecularInfo(MaterialInfo info) specularTexture.rgb = texture(u_SpecularColorSampler, getSpecularColorUV()).rgb; #endif - vec3 dielectricSpecularF0 = min(info.f0 * u_KHR_materials_specular_specularColorFactor * specularTexture.rgb, vec3(1.0)); - info.f0 = mix(dielectricSpecularF0, info.baseColor.rgb, info.metallic); + info.f0_dielectric = min(info.f0_dielectric * u_KHR_materials_specular_specularColorFactor * specularTexture.rgb, vec3(1.0)); info.specularWeight = u_KHR_materials_specular_specularFactor * specularTexture.a; - info.c_diff = mix(info.baseColor.rgb, vec3(0), info.metallic); + info.f90_dielectric = vec3(info.specularWeight); return info; } #endif @@ -400,7 +397,7 @@ MaterialInfo getClearCoatInfo(MaterialInfo info, NormalInfo normalInfo) #ifdef MATERIAL_IOR MaterialInfo getIorInfo(MaterialInfo info) { - info.f0 = vec3(pow(( u_Ior - 1.0) / (u_Ior + 1.0), 2.0)); + info.f0_dielectric = vec3(pow(( u_Ior - 1.0) / (u_Ior + 1.0), 2.0)); info.ior = u_Ior; return info; } diff --git a/source/Renderer/shaders/pbr.frag b/source/Renderer/shaders/pbr.frag index ae6a1c1e..b285bf4b 100644 --- a/source/Renderer/shaders/pbr.frag +++ b/source/Renderer/shaders/pbr.frag @@ -40,6 +40,7 @@ void main() #if ALPHAMODE == ALPHAMODE_OPAQUE baseColor.a = 1.0; #endif + vec3 color = vec3(0); vec3 v = normalize(u_Camera - v_Position); NormalInfo normalInfo = getNormalInfo(v); @@ -56,9 +57,13 @@ void main() // The default index of refraction of 1.5 yields a dielectric normal incidence reflectance of 0.04. materialInfo.ior = 1.5; - materialInfo.f0 = vec3(0.04); + materialInfo.f0_dielectric = vec3(0.04); materialInfo.specularWeight = 1.0; + // Anything less than 2% is physically impossible and is instead considered to be shadowing. Compare to "Real-Time-Rendering" 4th editon on page 325. + materialInfo.f90 = vec3(1.0); + materialInfo.f90_dielectric = materialInfo.f90; + // If the MR debug output is selected, we have to enforce evaluation of the non-iridescence BRDF functions. #if DEBUG == DEBUG_METALLIC_ROUGHNESS #undef MATERIAL_IRIDESCENCE @@ -115,27 +120,28 @@ void main() // convert to material roughness by squaring the perceptual roughness. materialInfo.alphaRoughness = materialInfo.perceptualRoughness * materialInfo.perceptualRoughness; - // Compute reflectance. - float reflectance = max(max(materialInfo.f0.r, materialInfo.f0.g), materialInfo.f0.b); - - // Anything less than 2% is physically impossible and is instead considered to be shadowing. Compare to "Real-Time-Rendering" 4th editon on page 325. - materialInfo.f90 = vec3(1.0); // LIGHTING - vec3 f_specular = vec3(0.0); + vec3 f_specular_dielectric = vec3(0.0); + vec3 f_specular_metal = vec3(0.0); vec3 f_diffuse = vec3(0.0); + vec3 f_dielectric_brdf_ibl = vec3(0.0); + vec3 f_metal_brdf_ibl = vec3(0.0); vec3 f_emissive = vec3(0.0); - vec3 f_clearcoat = vec3(0.0); + vec3 clearcoat_brdf = vec3(0.0); vec3 f_sheen = vec3(0.0); vec3 f_specular_transmission = vec3(0.0); vec3 f_diffuse_transmission = vec3(0.0); + float clearcoatFactor = 0.0; + vec3 clearcoatFresnel = vec3(0); + float albedoSheenScaling = 1.0; float diffuseTransmissionThickness = 1.0; #ifdef MATERIAL_IRIDESCENCE - vec3 iridescenceFresnel = evalIridescence(1.0, materialInfo.iridescenceIor, NdotV, materialInfo.iridescenceThickness, materialInfo.f0); - vec3 iridescenceF0 = Schlick_to_F0(iridescenceFresnel, NdotV); + vec3 iridescenceFresnel_dielectric = evalIridescence(1.0, materialInfo.iridescenceIor, NdotV, materialInfo.iridescenceThickness, materialInfo.f0_dielectric); + vec3 iridescenceFresnel_metallic = evalIridescence(1.0, materialInfo.iridescenceIor, NdotV, materialInfo.iridescenceThickness, baseColor.rgb); if (materialInfo.iridescenceThickness == 0.0) { materialInfo.iridescenceFactor = 0.0; @@ -149,54 +155,83 @@ void main() #endif #endif +#ifdef MATERIAL_CLEARCOAT + clearcoatFactor = materialInfo.clearcoatFactor; + clearcoatFresnel = F_Schlick(materialInfo.clearcoatF0, materialInfo.clearcoatF90, clampedDot(materialInfo.clearcoatNormal, v)); +#endif + // Calculate lighting contribution from image based lighting source (IBL) #ifdef USE_IBL -#ifdef MATERIAL_IRIDESCENCE - f_specular += getIBLRadianceGGXIridescence(n, v, materialInfo.perceptualRoughness, materialInfo.f0, iridescenceFresnel, materialInfo.iridescenceFactor, materialInfo.specularWeight); - f_diffuse += getIBLRadianceLambertianIridescence(n, v, materialInfo.perceptualRoughness, materialInfo.c_diff, materialInfo.f0, iridescenceF0, materialInfo.iridescenceFactor, materialInfo.specularWeight); -#elif defined(MATERIAL_ANISOTROPY) - f_specular += getIBLRadianceAnisotropy(n, v, materialInfo.perceptualRoughness, materialInfo.anisotropyStrength, materialInfo.anisotropicB, materialInfo.f0, materialInfo.specularWeight); - f_diffuse += getIBLRadianceLambertian(n, v, materialInfo.perceptualRoughness, materialInfo.c_diff, materialInfo.f0, materialInfo.specularWeight); -#else - f_specular += getIBLRadianceGGX(n, v, materialInfo.perceptualRoughness, materialInfo.f0, materialInfo.specularWeight); - f_diffuse += getIBLRadianceLambertian(n, v, materialInfo.perceptualRoughness, materialInfo.c_diff, materialInfo.f0, materialInfo.specularWeight); -#endif + + f_diffuse = getDiffuseLight(n) * baseColor.rgb ; #ifdef MATERIAL_DIFFUSE_TRANSMISSION - vec3 diffuseTransmissionIBL = getIBLRadianceLambertian(-n, -v, materialInfo.perceptualRoughness, materialInfo.diffuseTransmissionColorFactor, materialInfo.f0, materialInfo.specularWeight); + vec3 diffuseTransmissionIBL = getDiffuseLight(-n) * materialInfo.diffuseTransmissionColorFactor; #ifdef MATERIAL_VOLUME diffuseTransmissionIBL = applyVolumeAttenuation(diffuseTransmissionIBL, diffuseTransmissionThickness, materialInfo.attenuationColor, materialInfo.attenuationDistance); #endif - f_diffuse_transmission += diffuseTransmissionIBL; + f_diffuse = mix(f_diffuse, diffuseTransmissionIBL, materialInfo.diffuseTransmissionFactor); +#endif + + +#if defined(MATERIAL_TRANSMISSION) + f_specular_transmission = getIBLVolumeRefraction( + n, v, + materialInfo.perceptualRoughness, + baseColor.rgb, materialInfo.f0_dielectric, materialInfo.f90, + v_Position, u_ModelMatrix, u_ViewMatrix, u_ProjectionMatrix, + materialInfo.ior, materialInfo.thickness, materialInfo.attenuationColor, materialInfo.attenuationDistance, materialInfo.dispersion); + f_diffuse = mix(f_diffuse, f_specular_transmission, materialInfo.transmissionFactor); +#endif + +#ifdef MATERIAL_ANISOTROPY + f_specular_metal = getIBLRadianceAnisotropy(n, v, materialInfo.perceptualRoughness, materialInfo.anisotropyStrength, materialInfo.anisotropicB); + f_specular_dielectric = f_specular_metal; +#else + f_specular_metal = getIBLRadianceGGX(n, v, materialInfo.perceptualRoughness); + f_specular_dielectric = f_specular_metal; #endif + // Calculate fresnel mix for IBL + + vec3 f_metal_fresnel_ibl = getIBLGGXFresnel(n, v, materialInfo.perceptualRoughness, baseColor.rgb, 1.0); + f_metal_brdf_ibl = f_metal_fresnel_ibl * f_specular_metal; + + vec3 f_dielectric_fresnel_ibl = getIBLGGXFresnel(n, v, materialInfo.perceptualRoughness, materialInfo.f0_dielectric, materialInfo.specularWeight); + f_dielectric_brdf_ibl = mix(f_diffuse, f_specular_dielectric, f_dielectric_fresnel_ibl); + +#ifdef MATERIAL_IRIDESCENCE + f_metal_brdf_ibl = mix(f_metal_brdf_ibl, f_specular_metal * iridescenceFresnel_metallic, materialInfo.iridescenceFactor); + f_dielectric_brdf_ibl = mix(f_dielectric_brdf_ibl, rgb_mix(f_diffuse, f_specular_dielectric, iridescenceFresnel_dielectric), materialInfo.iridescenceFactor); +#endif + + #ifdef MATERIAL_CLEARCOAT - f_clearcoat += getIBLRadianceGGX(materialInfo.clearcoatNormal, v, materialInfo.clearcoatRoughness, materialInfo.clearcoatF0, 1.0); + clearcoat_brdf = getIBLRadianceGGX(materialInfo.clearcoatNormal, v, materialInfo.clearcoatRoughness); #endif #ifdef MATERIAL_SHEEN - f_sheen += getIBLRadianceCharlie(n, v, materialInfo.sheenRoughnessFactor, materialInfo.sheenColorFactor); + f_sheen = getIBLRadianceCharlie(n, v, materialInfo.sheenRoughnessFactor, materialInfo.sheenColorFactor); albedoSheenScaling = 1.0 - max3(materialInfo.sheenColorFactor) * albedoSheenScalingLUT(NdotV, materialInfo.sheenRoughnessFactor); #endif -#endif -#if defined(MATERIAL_TRANSMISSION) && defined(USE_IBL) - f_specular_transmission += getIBLVolumeRefraction( - n, v, - materialInfo.perceptualRoughness, - materialInfo.c_diff, materialInfo.f0, materialInfo.f90, - v_Position, u_ModelMatrix, u_ViewMatrix, u_ProjectionMatrix, - materialInfo.ior, materialInfo.thickness, materialInfo.attenuationColor, materialInfo.attenuationDistance, materialInfo.dispersion); + color = mix(f_dielectric_brdf_ibl, f_metal_brdf_ibl, materialInfo.metallic); + color = f_sheen + color * albedoSheenScaling; + color = mix(color, clearcoat_brdf, clearcoatFactor * clearcoatFresnel); + +#ifdef HAS_OCCLUSION_MAP + float ao = 1.0; + ao = texture(u_OcclusionSampler, getOcclusionUV()).r; + color = color * (1.0 + u_OcclusionStrength * (ao - 1.0)); #endif - vec3 f_diffuse_ibl = f_diffuse; - vec3 f_specular_ibl = f_specular; - vec3 f_sheen_ibl = f_sheen; - vec3 f_clearcoat_ibl = f_clearcoat; +#endif //end USE_IBL + f_diffuse = vec3(0.0); - f_specular = vec3(0.0); - f_sheen = vec3(0.0); - f_clearcoat = vec3(0.0); + f_specular_dielectric = vec3(0.0); + f_specular_metal = vec3(0.0); + vec3 f_dielectric_brdf = vec3(0.0); + vec3 f_metal_brdf = vec3(0.0); #ifdef USE_PUNCTUAL for (int i = 0; i < LIGHT_COUNT; ++i) @@ -221,41 +256,32 @@ void main() float NdotH = clampedDot(n, h); float LdotH = clampedDot(l, h); float VdotH = clampedDot(v, h); - if (NdotL > 0.0 || NdotV > 0.0) - { - // Calculation of analytical light - // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#acknowledgments AppendixB - vec3 intensity = getLighIntensity(light, pointToLight); - vec3 l_diffuse = vec3(0.0); - vec3 l_specular = vec3(0.0); -#ifdef MATERIAL_IRIDESCENCE - l_diffuse += intensity * NdotL * BRDF_lambertianIridescence(materialInfo.f0, materialInfo.f90, iridescenceFresnel, materialInfo.iridescenceFactor, materialInfo.c_diff, materialInfo.specularWeight, VdotH); - l_specular += intensity * NdotL * BRDF_specularGGXIridescence(materialInfo.f0, materialInfo.f90, iridescenceFresnel, materialInfo.alphaRoughness, materialInfo.iridescenceFactor, materialInfo.specularWeight, VdotH, NdotL, NdotV, NdotH); -#elif defined(MATERIAL_ANISOTROPY) - l_diffuse += intensity * NdotL * BRDF_lambertian(materialInfo.f0, materialInfo.f90, materialInfo.c_diff, materialInfo.specularWeight, VdotH); - l_specular += intensity * NdotL * BRDF_specularGGXAnisotropy(materialInfo.f0, materialInfo.f90, materialInfo.alphaRoughness, materialInfo.anisotropyStrength, n, v, l, h, materialInfo.anisotropicT, materialInfo.anisotropicB); -#else - l_diffuse += intensity * NdotL * BRDF_lambertian(materialInfo.f0, materialInfo.f90, materialInfo.c_diff, materialInfo.specularWeight, VdotH); - l_specular += intensity * NdotL * BRDF_specularGGX(materialInfo.f0, materialInfo.f90, materialInfo.alphaRoughness, materialInfo.specularWeight, VdotH, NdotL, NdotV, NdotH); -#endif -#ifdef MATERIAL_SHEEN - f_sheen += intensity * getPunctualRadianceSheen(materialInfo.sheenColorFactor, materialInfo.sheenRoughnessFactor, NdotL, NdotV, NdotH); - float l_albedoSheenScaling = min(1.0 - max3(materialInfo.sheenColorFactor) * albedoSheenScalingLUT(NdotV, materialInfo.sheenRoughnessFactor), - 1.0 - max3(materialInfo.sheenColorFactor) * albedoSheenScalingLUT(NdotL, materialInfo.sheenRoughnessFactor)); - l_diffuse *= l_albedoSheenScaling; - l_specular *= l_albedoSheenScaling; -#endif - f_diffuse += l_diffuse; - f_specular += l_specular; + vec3 dielectric_fresnel = F_Schlick(materialInfo.f0_dielectric * materialInfo.specularWeight, materialInfo.f90_dielectric, abs(VdotH)); + vec3 metal_fresnel = F_Schlick(baseColor.rgb, vec3(1.0), abs(VdotH)); + + vec3 lightIntensity = getLighIntensity(light, pointToLight); + + vec3 l_diffuse = lightIntensity * NdotL * BRDF_lambertian(baseColor.rgb); + vec3 l_specular_dielectric = vec3(0.0); + vec3 l_specular_metal = vec3(0.0); + vec3 l_dielectric_brdf = vec3(0.0); + vec3 l_metal_brdf = vec3(0.0); + vec3 l_clearcoat_brdf = vec3(0.0); + vec3 l_sheen = vec3(0.0); + float l_albedoSheenScaling = 1.0; -#ifdef MATERIAL_CLEARCOAT - f_clearcoat += intensity * getPunctualRadianceClearCoat(materialInfo.clearcoatNormal, v, l, h, VdotH, - materialInfo.clearcoatF0, materialInfo.clearcoatF90, materialInfo.clearcoatRoughness); -#endif - } - vec3 lightIntensity = getLighIntensity(light, pointToLight); + + +#ifdef MATERIAL_DIFFUSE_TRANSMISSION + vec3 diffuse_btdf = lightIntensity * clampedDot(-n, l) * BRDF_lambertian(materialInfo.diffuseTransmissionColorFactor); + +#ifdef MATERIAL_VOLUME + diffuse_btdf = applyVolumeAttenuation(diffuse_btdf, diffuseTransmissionThickness, materialInfo.attenuationColor, materialInfo.attenuationDistance); +#endif + l_diffuse = mix(l_diffuse, diffuse_btdf, materialInfo.diffuseTransmissionFactor); +#endif // MATERIAL_DIFFUSE_TRANSMISSION // BTDF (Bidirectional Transmittance Distribution Function) #ifdef MATERIAL_TRANSMISSION @@ -265,26 +291,49 @@ void main() pointToLight -= transmissionRay; l = normalize(pointToLight); - vec3 transmittedLight = lightIntensity * getPunctualRadianceTransmission(n, v, l, materialInfo.alphaRoughness, materialInfo.f0, materialInfo.f90, materialInfo.c_diff, materialInfo.ior); + vec3 transmittedLight = lightIntensity * getPunctualRadianceTransmission(n, v, l, materialInfo.alphaRoughness, materialInfo.f0_dielectric, materialInfo.f90, baseColor.rgb, materialInfo.ior); #ifdef MATERIAL_VOLUME transmittedLight = applyVolumeAttenuation(transmittedLight, length(transmissionRay), materialInfo.attenuationColor, materialInfo.attenuationDistance); #endif + l_diffuse = mix(l_diffuse, transmittedLight, materialInfo.transmissionFactor); +#endif - f_specular_transmission += transmittedLight; -#endif // MATERIAL_TRANSMISSION + // Calculation of analytical light + // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#acknowledgments AppendixB + vec3 intensity = getLighIntensity(light, pointToLight); -#ifdef MATERIAL_DIFFUSE_TRANSMISSION - vec3 lambertian = BRDF_lambertian(materialInfo.f0, materialInfo.f90, materialInfo.diffuseTransmissionColorFactor, materialInfo.specularWeight, clampedDot(v, normalize(-l + v))); - vec3 transmittedDiffuseLight = lightIntensity * clampedDot(-n, l) * lambertian; +#ifdef MATERIAL_ANISOTROPY + l_specular_metal = intensity * NdotL * BRDF_specularGGXAnisotropy(materialInfo.alphaRoughness, materialInfo.anisotropyStrength, n, v, l, h, materialInfo.anisotropicT, materialInfo.anisotropicB); + l_specular_dielectric = l_specular_metal; +#else + l_specular_metal = intensity * NdotL * BRDF_specularGGX(materialInfo.alphaRoughness, NdotL, NdotV, NdotH); + l_specular_dielectric = l_specular_metal; +#endif -#ifdef MATERIAL_VOLUME - transmittedDiffuseLight = applyVolumeAttenuation(transmittedDiffuseLight, diffuseTransmissionThickness, materialInfo.attenuationColor, materialInfo.attenuationDistance); + l_metal_brdf = metal_fresnel * l_specular_metal; + l_dielectric_brdf = mix(l_diffuse, l_specular_dielectric, dielectric_fresnel); // Do we need to handle vec3 fresnel here? + +#ifdef MATERIAL_IRIDESCENCE + l_metal_brdf = mix(l_metal_brdf, l_specular_metal * iridescenceFresnel_metallic, materialInfo.iridescenceFactor); + l_dielectric_brdf = mix(l_dielectric_brdf, rgb_mix(l_diffuse, l_specular_dielectric, iridescenceFresnel_dielectric), materialInfo.iridescenceFactor); #endif - f_diffuse_transmission += transmittedDiffuseLight; -#endif // MATERIAL_DIFFUSE_TRANSMISSION +#ifdef MATERIAL_CLEARCOAT + l_clearcoat_brdf = intensity * getPunctualRadianceClearCoat(materialInfo.clearcoatNormal, v, l, h, VdotH, + materialInfo.clearcoatF0, materialInfo.clearcoatF90, materialInfo.clearcoatRoughness); +#endif +#ifdef MATERIAL_SHEEN + l_sheen = intensity * getPunctualRadianceSheen(materialInfo.sheenColorFactor, materialInfo.sheenRoughnessFactor, NdotL, NdotV, NdotH); + l_albedoSheenScaling = min(1.0 - max3(materialInfo.sheenColorFactor) * albedoSheenScalingLUT(NdotV, materialInfo.sheenRoughnessFactor), + 1.0 - max3(materialInfo.sheenColorFactor) * albedoSheenScalingLUT(NdotL, materialInfo.sheenRoughnessFactor)); +#endif + + vec3 l_color = mix(l_dielectric_brdf, l_metal_brdf, materialInfo.metallic); + l_color = l_sheen + l_color * l_albedoSheenScaling; + l_color = mix(l_color, l_clearcoat_brdf, clearcoatFactor * clearcoatFresnel); + color += l_color; } #endif // USE_PUNCTUAL @@ -296,51 +345,11 @@ void main() f_emissive *= texture(u_EmissiveSampler, getEmissiveUV()).rgb; #endif - // Layer blending - - float clearcoatFactor = 0.0; - vec3 clearcoatFresnel = vec3(0); - vec3 diffuse; - vec3 specular; - vec3 sheen; - vec3 clearcoat; - float ao = 1.0; - // Apply optional PBR terms for additional (optional) shading -#ifdef HAS_OCCLUSION_MAP - ao = texture(u_OcclusionSampler, getOcclusionUV()).r; - diffuse = f_diffuse + mix(f_diffuse_ibl, f_diffuse_ibl * ao, u_OcclusionStrength) * albedoSheenScaling; - // apply ambient occlusion to all lighting that is not punctual - specular = f_specular + mix(f_specular_ibl, f_specular_ibl * ao, u_OcclusionStrength) * albedoSheenScaling; - sheen = f_sheen + mix(f_sheen_ibl, f_sheen_ibl * ao, u_OcclusionStrength); - clearcoat = f_clearcoat + mix(f_clearcoat_ibl, f_clearcoat_ibl * ao, u_OcclusionStrength); -#else - diffuse = f_diffuse_ibl * albedoSheenScaling + f_diffuse; - specular = f_specular_ibl * albedoSheenScaling + f_specular; - sheen = f_sheen_ibl + f_sheen; - clearcoat = f_clearcoat_ibl + f_clearcoat; -#endif - -#ifdef MATERIAL_CLEARCOAT - clearcoatFactor = materialInfo.clearcoatFactor; - clearcoatFresnel = F_Schlick(materialInfo.clearcoatF0, materialInfo.clearcoatF90, clampedDot(materialInfo.clearcoatNormal, v)); - clearcoat *= clearcoatFactor; -#endif - -#ifdef MATERIAL_DIFFUSE_TRANSMISSION - diffuse = mix(diffuse, f_diffuse_transmission, materialInfo.diffuseTransmissionFactor); -#endif -#ifdef MATERIAL_TRANSMISSION - diffuse = mix(diffuse, f_specular_transmission, materialInfo.transmissionFactor); -#endif - - vec3 color = vec3(0); #ifdef MATERIAL_UNLIT color = baseColor.rgb; #else - color = f_emissive + diffuse + specular; - color = sheen + color; - color = color * (1.0 - clearcoatFactor * clearcoatFresnel) + clearcoat; + color = f_emissive * (1.0 - clearcoatFactor * clearcoatFresnel) + color; #endif #if DEBUG == DEBUG_NONE @@ -409,9 +418,6 @@ void main() // MR: #ifdef MATERIAL_METALLICROUGHNESS -#if DEBUG == DEBUG_METALLIC_ROUGHNESS - g_finalColor.rgb = linearTosRGB(diffuse + specular); -#endif #if DEBUG == DEBUG_METALLIC g_finalColor.rgb = vec3(materialInfo.metallic); #endif @@ -425,9 +431,6 @@ void main() // Clearcoat: #ifdef MATERIAL_CLEARCOAT -#if DEBUG == DEBUG_CLEARCOAT - g_finalColor.rgb = linearTosRGB(clearcoat); -#endif #if DEBUG == DEBUG_CLEARCOAT_FACTOR g_finalColor.rgb = vec3(materialInfo.clearcoatFactor); #endif @@ -441,9 +444,6 @@ void main() // Sheen: #ifdef MATERIAL_SHEEN -#if DEBUG == DEBUG_SHEEN - g_finalColor.rgb = linearTosRGB(sheen); -#endif #if DEBUG == DEBUG_SHEEN_COLOR g_finalColor.rgb = materialInfo.sheenColorFactor; #endif @@ -454,9 +454,6 @@ void main() // Specular: #ifdef MATERIAL_SPECULAR -#if DEBUG == DEBUG_SPECULAR - g_finalColor.rgb = linearTosRGB(specular); -#endif #if DEBUG == DEBUG_SPECULAR_FACTOR g_finalColor.rgb = vec3(materialInfo.specularWeight); #endif @@ -472,9 +469,6 @@ vec3 specularTexture = vec3(1.0); // Transmission, Volume: #ifdef MATERIAL_TRANSMISSION -#if DEBUG == DEBUG_TRANSMISSION_VOLUME - g_finalColor.rgb = linearTosRGB(f_specular_transmission * materialInfo.transmissionFactor); -#endif #if DEBUG == DEBUG_TRANSMISSION_FACTOR g_finalColor.rgb = vec3(materialInfo.transmissionFactor); #endif @@ -487,9 +481,6 @@ vec3 specularTexture = vec3(1.0); // Iridescence: #ifdef MATERIAL_IRIDESCENCE -#if DEBUG == DEBUG_IRIDESCENCE - g_finalColor.rgb = iridescenceFresnel * materialInfo.iridescenceFactor; -#endif #if DEBUG == DEBUG_IRIDESCENCE_FACTOR g_finalColor.rgb = vec3(materialInfo.iridescenceFactor); #endif @@ -519,9 +510,6 @@ vec3 specularTexture = vec3(1.0); // Diffuse Transmission: #ifdef MATERIAL_DIFFUSE_TRANSMISSION -#if DEBUG == DEBUG_DIFFUSE_TRANSMISSION - g_finalColor.rgb = linearTosRGB(f_diffuse_transmission * vec3(materialInfo.diffuseTransmissionFactor)); -#endif #if DEBUG == DEBUG_DIFFUSE_TRANSMISSION_FACTOR g_finalColor.rgb = linearTosRGB(vec3(materialInfo.diffuseTransmissionFactor)); #endif diff --git a/source/Renderer/shaders/punctual.glsl b/source/Renderer/shaders/punctual.glsl index 254cbbf4..25345ccf 100644 --- a/source/Renderer/shaders/punctual.glsl +++ b/source/Renderer/shaders/punctual.glsl @@ -98,7 +98,7 @@ vec3 getPunctualRadianceClearCoat(vec3 clearcoatNormal, vec3 v, vec3 l, vec3 h, float NdotL = clampedDot(clearcoatNormal, l); float NdotV = clampedDot(clearcoatNormal, v); float NdotH = clampedDot(clearcoatNormal, h); - return NdotL * BRDF_specularGGX(f0, f90, clearcoatRoughness * clearcoatRoughness, 1.0, VdotH, NdotL, NdotV, NdotH); + return NdotL * BRDF_specularGGX(clearcoatRoughness * clearcoatRoughness, NdotL, NdotV, NdotH); }