diff options
author | Mauro Persano <mauro.persano@kdab.com> | 2018-11-01 09:37:56 -0300 |
---|---|---|
committer | Mauro Persano <mauro.persano@kdab.com> | 2018-11-05 21:06:45 +0000 |
commit | ab5a1549ea25bb2a939b4fe526f5af28bbf2d713 (patch) | |
tree | 59d04f60b613ced534db67487d7d439476466ae5 /src/extras | |
parent | 7b401dcd3345d42108eb162ea354f64152c9d0a4 (diff) |
Make floating point precision explicit in ES3 MetalRough shader
Change-Id: Ibd59dd30e31ded3cbf169fa583d537a7d67fee96
Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
Diffstat (limited to 'src/extras')
-rw-r--r-- | src/extras/shaders/es3/metalrough.inc.frag | 186 |
1 files changed, 94 insertions, 92 deletions
diff --git a/src/extras/shaders/es3/metalrough.inc.frag b/src/extras/shaders/es3/metalrough.inc.frag index 85f392f4c..f145e90f8 100644 --- a/src/extras/shaders/es3/metalrough.inc.frag +++ b/src/extras/shaders/es3/metalrough.inc.frag @@ -48,46 +48,48 @@ ** ****************************************************************************/ -precision highp float; +#ifndef FP +#define FP highp +#endif // Exposure correction -uniform float exposure; +uniform FP float exposure; // Gamma correction -const float gamma = 2.2; +const FP float gamma = 2.2; #pragma include light.inc.frag -int mipLevelCount(const in samplerCube cube) +int mipLevelCount(const in FP samplerCube cube) { int baseSize = textureSize(cube, 0).x; int nMips = int(log2(float(baseSize > 0 ? baseSize : 1))) + 1; return nMips; } -float remapRoughness(const in float roughness) +float remapRoughness(const in FP 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.0)); + const FP float maxSpecPower = 999999.0; + const FP float minRoughness = sqrt(2.0 / (maxSpecPower + 2.0)); return max(roughness * roughness, minRoughness); } -float alphaToMipLevel(float alpha) +FP float alphaToMipLevel(FP float alpha) { - float specPower = 2.0 / (alpha * alpha) - 2.0; + FP 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 // https://docs.knaldtech.com/doku.php?id=specular_lys for details. // For now we assume a max specular power of 999999 which gives // maxGlossiness = 1. - const float k0 = 0.00098; - const float k1 = 0.9921; - float glossiness = (pow(2.0, -10.0 / sqrt(specPower)) - k0) / k1; + const FP float k0 = 0.00098; + const FP float k1 = 0.9921; + FP float glossiness = (pow(2.0, -10.0 / sqrt(specPower)) - k0) / k1; // TODO: Optimize by doing this on CPU and set as // uniform int envLight.specularMipLevels say (if present in shader). @@ -96,35 +98,35 @@ float alphaToMipLevel(float alpha) // Offset of smallest miplevel we should use (corresponds to specular // power of 1). I.e. in the 32x32 sized mip. - const float mipOffset = 5.0; + const FP float mipOffset = 5.0; // The final factor is really 1 - g / g_max but as mentioned above g_max // is 1 by definition here so we can avoid the division. If we make the // max specular power for the spec map configurable, this will need to // be handled properly. - float mipLevel = (float(mipLevels) - 1.0 - mipOffset) * (1.0 - glossiness); + FP float mipLevel = (float(mipLevels) - 1.0 - mipOffset) * (1.0 - glossiness); return mipLevel; } -float normalDistribution(const in vec3 n, const in vec3 h, const in float alpha) +FP float normalDistribution(const in FP vec3 n, const in FP vec3 h, const in FP float alpha) { // Blinn-Phong approximation - see // http://graphicrants.blogspot.co.uk/2013/08/specular-brdf-reference.html - float specPower = 2.0 / (alpha * alpha) - 2.0; + FP 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) +FP vec3 fresnelFactor(const in FP vec3 color, const in FP float cosineFactor) { // Calculate the Fresnel effect value - vec3 f = color; - vec3 F = f + (1.0 - f) * pow(1.0 - cosineFactor, 5.0); + FP vec3 f = color; + FP vec3 F = f + (1.0 - f) * pow(1.0 - cosineFactor, 5.0); return clamp(F, f, vec3(1.0)); } -float geometricModel(const in float lDotN, - const in float vDotN, - const in vec3 h) +FP float geometricModel(const in FP float lDotN, + const in FP float vDotN, + const in FP vec3 h) { // Implicit geometric model (equal to denominator in specular model). // This currently assumes that there is no attenuation by geometric shadowing or @@ -132,46 +134,46 @@ float geometricModel(const in float lDotN, return lDotN * vDotN; } -vec3 specularModel(const in vec3 F0, - const in float sDotH, - const in float sDotN, - const in float vDotN, - const in vec3 n, - const in vec3 h) +FP vec3 specularModel(const in FP vec3 F0, + const in FP float sDotH, + const in FP float sDotN, + const in FP float vDotN, + const in FP vec3 n, + const in FP vec3 h) { // Clamp sDotN and vDotN to small positive value to prevent the // denominator in the reflection equation going to infinity. Balance this // by using the clamped values in the geometric factor function to // avoid ugly seams in the specular lighting. - float sDotNPrime = max(sDotN, 0.001); - float vDotNPrime = max(vDotN, 0.001); + FP float sDotNPrime = max(sDotN, 0.001); + FP float vDotNPrime = max(vDotN, 0.001); - vec3 F = fresnelFactor(F0, sDotH); - float G = geometricModel(sDotNPrime, vDotNPrime, h); + FP vec3 F = fresnelFactor(F0, sDotH); + FP float G = geometricModel(sDotNPrime, vDotNPrime, h); - vec3 cSpec = F * G / (4.0 * sDotNPrime * vDotNPrime); + FP vec3 cSpec = F * G / (4.0 * sDotNPrime * vDotNPrime); return clamp(cSpec, vec3(0.0), vec3(1.0)); } -vec3 pbrModel(const in int lightIndex, - const in vec3 wPosition, - const in vec3 wNormal, - const in vec3 wView, - const in vec3 baseColor, - const in float metalness, - const in float alpha, - const in float ambientOcclusion) +FP vec3 pbrModel(const in int lightIndex, + const in FP vec3 wPosition, + const in FP vec3 wNormal, + const in FP vec3 wView, + const in FP vec3 baseColor, + const in FP float metalness, + const in FP float alpha, + const in FP float ambientOcclusion) { // Calculate some useful quantities - vec3 n = wNormal; - vec3 s = vec3(0.0); - vec3 v = wView; - vec3 h = vec3(0.0); + FP vec3 n = wNormal; + FP vec3 s = vec3(0.0); + FP vec3 v = wView; + FP vec3 h = vec3(0.0); - float vDotN = dot(v, n); - float sDotN = 0.0; - float sDotH = 0.0; - float att = 1.0; + FP float vDotN = dot(v, n); + FP float sDotN = 0.0; + FP float sDotH = 0.0; + FP float att = 1.0; if (lights[lightIndex].type != TYPE_DIRECTIONAL) { // Point and Spot lights @@ -208,22 +210,22 @@ vec3 pbrModel(const in int lightIndex, sDotH = dot(s, h); // Calculate diffuse component - vec3 diffuseColor = (1.0 - metalness) * baseColor * lights[lightIndex].color; - vec3 diffuse = diffuseColor * max(sDotN, 0.0) / 3.14159; + FP vec3 diffuseColor = (1.0 - metalness) * baseColor * lights[lightIndex].color; + FP vec3 diffuse = diffuseColor * max(sDotN, 0.0) / 3.14159; // Calculate specular component - vec3 dielectricColor = vec3(0.04); - vec3 F0 = mix(dielectricColor, baseColor, metalness); - vec3 specularFactor = vec3(0.0); + FP vec3 dielectricColor = vec3(0.04); + FP vec3 F0 = mix(dielectricColor, baseColor, metalness); + FP vec3 specularFactor = vec3(0.0); if (sDotN > 0.0) { specularFactor = specularModel(F0, sDotH, sDotN, vDotN, n, h); specularFactor *= normalDistribution(n, h, alpha); } - vec3 specularColor = lights[lightIndex].color; - vec3 specular = specularColor * specularFactor; + FP vec3 specularColor = lights[lightIndex].color; + FP vec3 specular = specularColor * specularFactor; // Blend between diffuse and specular to conserver energy - vec3 color = att * lights[lightIndex].intensity * (specular + diffuse * (vec3(1.0) - specular)); + FP vec3 color = att * lights[lightIndex].intensity * (specular + diffuse * (vec3(1.0) - specular)); // Reduce by ambient occlusion amount color *= ambientOcclusion; @@ -231,36 +233,36 @@ vec3 pbrModel(const in int lightIndex, return color; } -vec3 pbrIblModel(const in vec3 wNormal, - const in vec3 wView, - const in vec3 baseColor, - const in float metalness, - const in float alpha, - const in float ambientOcclusion) +FP vec3 pbrIblModel(const in FP vec3 wNormal, + const in FP vec3 wView, + const in FP vec3 baseColor, + const in FP float metalness, + const in FP float alpha, + const in FP float ambientOcclusion) { // Calculate reflection direction of view vector about surface normal // vector in world space. This is used in the fragment shader to sample // from the environment textures for a light source. This is equivalent // to the l vector for punctual light sources. Armed with this, calculate // the usual factors needed - vec3 n = wNormal; - vec3 l = reflect(-wView, n); - vec3 v = wView; - vec3 h = normalize(l + v); - float vDotN = dot(v, n); - float lDotN = dot(l, n); - float lDotH = dot(l, h); + FP vec3 n = wNormal; + FP vec3 l = reflect(-wView, n); + FP vec3 v = wView; + FP vec3 h = normalize(l + v); + FP float vDotN = dot(v, n); + FP float lDotN = dot(l, n); + FP float lDotH = dot(l, h); // Calculate diffuse component - vec3 diffuseColor = (1.0 - metalness) * baseColor; - vec3 diffuse = diffuseColor * texture(envLight.irradiance, l).rgb; + FP vec3 diffuseColor = (1.0 - metalness) * baseColor; + FP vec3 diffuse = diffuseColor * texture(envLight.irradiance, l).rgb; // Calculate specular component - vec3 dielectricColor = vec3(0.04); - vec3 F0 = mix(dielectricColor, baseColor, metalness); - vec3 specularFactor = specularModel(F0, lDotH, lDotN, vDotN, n, h); + FP vec3 dielectricColor = vec3(0.04); + FP vec3 F0 = mix(dielectricColor, baseColor, metalness); + FP vec3 specularFactor = specularModel(F0, lDotH, lDotN, vDotN, n, h); - float lod = alphaToMipLevel(alpha); + FP float lod = alphaToMipLevel(alpha); //#define DEBUG_SPECULAR_LODS #ifdef DEBUG_SPECULAR_LODS if (lod > 7.0) @@ -280,11 +282,11 @@ vec3 pbrIblModel(const in vec3 wNormal, else if (lod > 0.0) return vec3(1.0, 0.0, 1.0); #endif - vec3 specularSkyColor = textureLod(envLight.specular, l, lod).rgb; - vec3 specular = specularSkyColor * specularFactor; + FP vec3 specularSkyColor = textureLod(envLight.specular, l, lod).rgb; + FP vec3 specular = specularSkyColor * specularFactor; // Blend between diffuse and specular to conserve energy - vec3 color = specular + diffuse * (vec3(1.0) - specularFactor); + FP vec3 color = specular + diffuse * (vec3(1.0) - specularFactor); // Reduce by ambient occlusion amount color *= ambientOcclusion; @@ -292,28 +294,28 @@ vec3 pbrIblModel(const in vec3 wNormal, return color; } -vec3 toneMap(const in vec3 c) +FP vec3 toneMap(const in FP vec3 c) { return c / (c + vec3(1.0)); } -vec3 gammaCorrect(const in vec3 color) +FP vec3 gammaCorrect(const in FP vec3 color) { return pow(color, vec3(1.0 / gamma)); } -vec4 metalRoughFunction(const in vec4 baseColor, - const in float metalness, - const in float roughness, - const in float ambientOcclusion, - const in vec3 worldPosition, - const in vec3 worldView, - const in vec3 worldNormal) +FP vec4 metalRoughFunction(const in FP vec4 baseColor, + const in FP float metalness, + const in FP float roughness, + const in FP float ambientOcclusion, + const in FP vec3 worldPosition, + const in FP vec3 worldView, + const in FP vec3 worldNormal) { - vec3 cLinear = vec3(0.0); + FP vec3 cLinear = vec3(0.0); // Remap roughness for a perceptually more linear correspondence - float alpha = remapRoughness(roughness); + FP float alpha = remapRoughness(roughness); for (int i = 0; i < envLightCount; ++i) { cLinear += pbrIblModel(worldNormal, @@ -339,10 +341,10 @@ vec4 metalRoughFunction(const in vec4 baseColor, cLinear *= pow(2.0, exposure); // Apply simple (Reinhard) tonemap transform to get into LDR range [0, 1] - vec3 cToneMapped = toneMap(cLinear); + FP vec3 cToneMapped = toneMap(cLinear); // Apply gamma correction prior to display - vec3 cGamma = gammaCorrect(cToneMapped); + FP vec3 cGamma = gammaCorrect(cToneMapped); return vec4(cGamma, 1.0); } |