diff options
-rw-r--r-- | src/extras/shaders/gl3/metalrough.frag | 61 | ||||
-rw-r--r-- | src/extras/shaders/gl3/metalroughuniform.frag | 56 |
2 files changed, 56 insertions, 61 deletions
diff --git a/src/extras/shaders/gl3/metalrough.frag b/src/extras/shaders/gl3/metalrough.frag index 0bbef9167..7f2f3d20e 100644 --- a/src/extras/shaders/gl3/metalrough.frag +++ b/src/extras/shaders/gl3/metalrough.frag @@ -85,6 +85,18 @@ int mipLevelCount(const in samplerCube cube) return nMips; } +float remapRoughness(const in float roughness) +{ + // As per page 14 of + // http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf + // we remap the roughness to give a more perceptually linear response + // of "bluriness" as a function of the roughness specified by the user. + // r = roughness^2 + const float maxSpecPower = 999999.0; + const float minRoughness = sqrt(2.0 / (maxSpecPower + 2)); + return max(roughness * roughness, minRoughness); +} + mat3 calcWorldSpaceToTangentSpaceMatrix(const in vec3 wNormal, const in vec4 wTangent) { // Make the tangent truly orthogonal to the normal by using Gram-Schmidt. @@ -105,12 +117,9 @@ mat3 calcWorldSpaceToTangentSpaceMatrix(const in vec3 wNormal, const in vec4 wTa return worldToTangentMatrix; } -float roughnessToMipLevel(float roughness) +float alphaToMipLevel(float alpha) { - const float maxSpecPower = 999999.0; - const float minRoughness = sqrt(2.0 / (maxSpecPower + 2)); - float r = max(roughness, minRoughness); - float specPower = 2.0 / (r * r) - 2.0; + float specPower = 2.0 / (alpha * alpha) - 2.0; // We use the mip level calculation from Lys' default power drop, which in // turn is a slight modification of that used in Marmoset Toolbag. See @@ -138,24 +147,12 @@ float roughnessToMipLevel(float roughness) return mipLevel; } -// Helper function to map from linear roughness value to non-linear alpha (shininess) -float roughnessToAlpha(const in float roughness) +float normalDistribution(const in vec3 n, const in vec3 h, const in float alpha) { - // Constants to control how to convert from roughness [0,1] to - // shininess (alpha) [minAlpha, maxAlpha] using a power law with - // a power of 1 / rho. - const float minAlpha = 1.0; - const float maxAlpha = 1024.0; - const float rho = 3.0; - - return minAlpha + (maxAlpha - minAlpha) * (1.0 - pow(roughness, 1.0 / rho)); -} - -float normalDistribution(const in vec3 n, const in vec3 h, const in float roughness) -{ - // Blinn-Phong approximation - float alpha = roughnessToAlpha(roughness); - return (alpha + 2.0) / (2.0 * 3.14159) * pow(max(dot(n, h), 0.0), alpha); + // Blinn-Phong approximation - see + // http://graphicrants.blogspot.co.uk/2013/08/specular-brdf-reference.html + float specPower = 2.0 / (alpha * alpha) - 2.0; + return (specPower + 2.0) / (2.0 * 3.14159) * pow(max(dot(n, h), 0.0), specPower); } vec3 fresnelFactor(const in vec3 color, const in float cosineFactor) @@ -203,7 +200,7 @@ vec3 pbrModel(const in int lightIndex, const in vec3 wView, const in vec3 baseColor, const in float metalness, - const in float roughness, + const in float alpha, const in float ambientOcclusion) { // Calculate some useful quantities @@ -261,7 +258,7 @@ vec3 pbrModel(const in int lightIndex, vec3 specularFactor = vec3(0.0); if (sDotN > 0.0) { specularFactor = specularModel(F0, sDotH, sDotN, vDotN, n, h); - specularFactor *= normalDistribution(n, h, roughness); + specularFactor *= normalDistribution(n, h, alpha); } vec3 specularColor = lights[lightIndex].color; vec3 specular = specularColor * specularFactor; @@ -279,7 +276,7 @@ vec3 pbrIblModel(const in vec3 wNormal, const in vec3 wView, const in vec3 baseColor, const in float metalness, - const in float roughness, + const in float alpha, const in float ambientOcclusion) { // Calculate reflection direction of view vector about surface normal @@ -304,12 +301,7 @@ vec3 pbrIblModel(const in vec3 wNormal, vec3 F0 = mix(dielectricColor, baseColor, metalness); vec3 specularFactor = specularModel(F0, lDotH, lDotN, vDotN, n, h); - // As per page 14 of - // http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf - // we remap the roughness to give a more perceptually linear response - // of "bluriness" as a function of the roughness specified by the user. - // r = roughness^2 - float lod = roughnessToMipLevel(roughness * roughness); + float lod = alphaToMipLevel(alpha); //#define DEBUG_SPECULAR_LODS #ifdef DEBUG_SPECULAR_LODS if (lod > 7.0) @@ -368,12 +360,15 @@ void main() vec3 tNormal = 2.0 * texture(normalMap, texCoord).rgb - vec3(1.0); vec3 wNormal = normalize(transpose(worldToTangentMatrix) * tNormal); + // Remap roughness for a perceptually more linear correspondence + float alpha = remapRoughness(roughness); + for (int i = 0; i < envLightCount; ++i) { cLinear += pbrIblModel(wNormal, wView, baseColor, metalness, - roughness, + alpha, ambientOcclusion); } @@ -384,7 +379,7 @@ void main() wView, baseColor.rgb, metalness, - roughness, + alpha, ambientOcclusion); } diff --git a/src/extras/shaders/gl3/metalroughuniform.frag b/src/extras/shaders/gl3/metalroughuniform.frag index 17773515d..c9191adbf 100644 --- a/src/extras/shaders/gl3/metalroughuniform.frag +++ b/src/extras/shaders/gl3/metalroughuniform.frag @@ -80,6 +80,18 @@ int mipLevelCount(const in samplerCube cube) return nMips; } +float remapRoughness(const in float roughness) +{ + // As per page 14 of + // http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf + // we remap the roughness to give a more perceptually linear response + // of "bluriness" as a function of the roughness specified by the user. + // r = roughness^2 + const float maxSpecPower = 999999.0; + const float minRoughness = sqrt(2.0 / (maxSpecPower + 2)); + return max(roughness * roughness, minRoughness); +} + mat3 calcWorldSpaceToTangentSpaceMatrix(const in vec3 wNormal, const in vec4 wTangent) { // Make the tangent truly orthogonal to the normal by using Gram-Schmidt. @@ -100,12 +112,9 @@ mat3 calcWorldSpaceToTangentSpaceMatrix(const in vec3 wNormal, const in vec4 wTa return worldToTangentMatrix; } -float roughnessToMipLevel(float roughness) +float alphaToMipLevel(float alpha) { - const float maxSpecPower = 999999.0; - const float minRoughness = sqrt(2.0 / (maxSpecPower + 2)); - float r = max(roughness, minRoughness); - float specPower = 2.0 / (r * r) - 2.0; + float specPower = 2.0 / (alpha * alpha) - 2.0; // We use the mip level calculation from Lys' default power drop, which in // turn is a slight modification of that used in Marmoset Toolbag. See @@ -133,24 +142,12 @@ float roughnessToMipLevel(float roughness) return mipLevel; } -// Helper function to map from linear roughness value to non-linear alpha (shininess) -float roughnessToAlpha(const in float roughness) +float normalDistribution(const in vec3 n, const in vec3 h, const in float alpha) { - // Constants to control how to convert from roughness [0,1] to - // shininess (alpha) [minAlpha, maxAlpha] using a power law with - // a power of 1 / rho. - const float minAlpha = 1.0; - const float maxAlpha = 1024.0; - const float rho = 3.0; - - return minAlpha + (maxAlpha - minAlpha) * (1.0 - pow(roughness, 1.0 / rho)); -} - -float normalDistribution(const in vec3 n, const in vec3 h, const in float roughness) -{ - // Blinn-Phong approximation - float alpha = roughnessToAlpha(roughness); - return (alpha + 2.0) / (2.0 * 3.14159) * pow(max(dot(n, h), 0.0), alpha); + // Blinn-Phong approximation - see + // http://graphicrants.blogspot.co.uk/2013/08/specular-brdf-reference.html + float specPower = 2.0 / (alpha * alpha) - 2.0; + return (specPower + 2.0) / (2.0 * 3.14159) * pow(max(dot(n, h), 0.0), specPower); } vec3 fresnelFactor(const in vec3 color, const in float cosineFactor) @@ -198,7 +195,7 @@ vec3 pbrModel(const in int lightIndex, const in vec3 wView, const in vec3 baseColor, const in float metalness, - const in float roughness) + const in float alpha) { // Calculate some useful quantities vec3 n = wNormal; @@ -255,7 +252,7 @@ vec3 pbrModel(const in int lightIndex, vec3 specularFactor = vec3(0.0); if (sDotN > 0.0) { specularFactor = specularModel(F0, sDotH, sDotN, vDotN, n, h); - specularFactor *= normalDistribution(n, h, roughness); + specularFactor *= normalDistribution(n, h, alpha); } vec3 specularColor = lights[lightIndex].color; vec3 specular = specularColor * specularFactor; @@ -268,7 +265,7 @@ vec3 pbrIblModel(const in vec3 wNormal, const in vec3 wView, const in vec3 baseColor, const in float metalness, - const in float roughness) + const in float alpha) { // Calculate reflection direction of view vector about surface normal // vector in world space. This is used in the fragment shader to sample @@ -297,7 +294,7 @@ vec3 pbrIblModel(const in vec3 wNormal, // we remap the roughness to give a more perceptually linear response // of "bluriness" as a function of the roughness specified by the user. // r = roughness^2 - float lod = roughnessToMipLevel(roughness * roughness); + float lod = alphaToMipLevel(alpha); //#define DEBUG_SPECULAR_LODS #ifdef DEBUG_SPECULAR_LODS if (lod > 7.0) @@ -338,13 +335,16 @@ void main() { vec3 cLinear = vec3(0.0); + // Remap roughness for a perceptually more linear correspondence + float alpha = remapRoughness(roughness); + vec3 worldView = normalize(eyePosition - worldPosition); for (int i = 0; i < envLightCount; ++i) { cLinear += pbrIblModel(worldNormal, worldView, baseColor.rgb, metalness, - roughness); + alpha); } for (int i = 0; i < lightCount; ++i) { @@ -354,7 +354,7 @@ void main() worldView, baseColor.rgb, metalness, - roughness); + alpha); } // Apply exposure correction |