diff options
Diffstat (limited to 'indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl')
-rw-r--r-- | indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl | 330 |
1 files changed, 201 insertions, 129 deletions
diff --git a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl index f9ebf33b4a..94711be473 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl @@ -1,24 +1,24 @@ -/** +/** * @file class1/deferred/deferredUtil.glsl * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2007, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -48,8 +48,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -uniform sampler2D normalMap; -uniform sampler2D depthMap; +uniform sampler2D normalMap; +uniform sampler2D depthMap; uniform sampler2D projectionMap; // rgba uniform sampler2D brdfLut; @@ -62,6 +62,8 @@ uniform float proj_lod ; // (number of mips in proj map) uniform float proj_range; // range between near clip and far clip plane of projection uniform float proj_ambiance; +uniform int classic_mode; + // light params uniform vec3 color; // light_color uniform float size; // light_size @@ -73,8 +75,11 @@ const float M_PI = 3.14159265; const float ONE_OVER_PI = 0.3183098861; vec3 srgb_to_linear(vec3 cs); +vec3 linear_to_srgb(vec3 cs); vec3 atmosFragLightingLinear(vec3 light, vec3 additive, vec3 atten); +vec4 decodeNormal(vec4 norm); + float calcLegacyDistanceAttenuation(float distance, float falloff) { float dist_atten = 1.0 - clamp((distance + falloff)/(1.0 + falloff), 0.0, 1.0); @@ -99,10 +104,13 @@ void calcHalfVectors(vec3 lv, vec3 n, vec3 v, { l = normalize(lv); h = normalize(l + v); - nh = clamp(dot(n, h), 0.0, 1.0); - nl = clamp(dot(n, l), 0.0, 1.0); - nv = clamp(dot(n, v), 0.0, 1.0); - vh = clamp(dot(v, h), 0.0, 1.0); + + // lower bound to avoid divide by zero + float eps = 0.000001; + nh = clamp(dot(n, h), eps, 1.0); + nl = clamp(dot(n, l), eps, 1.0); + nv = clamp(dot(n, v), eps, 1.0); + vh = clamp(dot(v, h), eps, 1.0); lightDist = length(lv); } @@ -140,40 +148,16 @@ vec2 getScreenCoordinate(vec2 screenpos) return sc - vec2(1.0, 1.0); } -// See: https://aras-p.info/texts/CompactNormalStorage.html -// Method #4: Spheremap Transform, Lambert Azimuthal Equal-Area projection -vec3 getNorm(vec2 screenpos) -{ - vec2 enc = texture(normalMap, screenpos.xy).xy; - vec2 fenc = enc*4-2; - float f = dot(fenc,fenc); - float g = sqrt(1-f/4); - vec3 n; - n.xy = fenc*g; - n.z = 1-f/2; - return n; -} - -vec3 getNormalFromPacked(vec4 packedNormalEnvIntensityFlags) +vec4 getNorm(vec2 screenpos) { - vec2 enc = packedNormalEnvIntensityFlags.xy; - vec2 fenc = enc*4-2; - float f = dot(fenc,fenc); - float g = sqrt(1-f/4); - vec3 n; - n.xy = fenc*g; - n.z = 1-f/2; - return normalize(n); // TODO: Is this normalize redundant? + vec4 norm = decodeNormal(texture(normalMap, screenpos.xy)); + return norm; } -// return packedNormalEnvIntensityFlags since GBUFFER_FLAG_HAS_PBR needs .w -// See: C++: addDeferredAttachments(), GLSL: softenLightF -vec4 getNormalEnvIntensityFlags(vec2 screenpos, out vec3 n, out float envIntensity) +vec4 getNormRaw(vec2 screenpos) { - vec4 packedNormalEnvIntensityFlags = texture(normalMap, screenpos.xy); - n = getNormalFromPacked( packedNormalEnvIntensityFlags ); - envIntensity = packedNormalEnvIntensityFlags.z; - return packedNormalEnvIntensityFlags; + vec4 norm = texture(normalMap, screenpos.xy); + return norm; } // get linear depth value given a depth buffer sample d and znear and zfar values @@ -376,23 +360,26 @@ vec2 BRDF(float NoV, float roughness) } // set colorDiffuse and colorSpec to the results of GLTF PBR style IBL -vec3 pbrIbl(vec3 diffuseColor, +void pbrIbl(vec3 diffuseColor, vec3 specularColor, vec3 radiance, // radiance map sample vec3 irradiance, // irradiance map sample float ao, // ambient occlusion factor float nv, // normal dot view vector - float perceptualRough) + float perceptualRough, + out vec3 diffuseOut, + out vec3 specularOut) { // retrieve a scale and bias to F0. See [1], Figure 3 - vec2 brdf = BRDF(clamp(nv, 0, 1), 1.0-perceptualRough); - vec3 diffuseLight = irradiance; - vec3 specularLight = radiance; - - vec3 diffuse = diffuseLight * diffuseColor; - vec3 specular = specularLight * (specularColor * brdf.x + brdf.y); + vec2 brdf = BRDF(clamp(nv, 0, 1), 1.0-perceptualRough); + vec3 diffuseLight = irradiance; + vec3 specularLight = radiance; - return (diffuse + specular) * ao; + vec3 diffuse = diffuseLight * diffuseColor; + vec3 specular = specularLight * (specularColor * brdf.x + brdf.y); + + diffuseOut = diffuse * ao; + specularOut = specular * ao; } @@ -401,18 +388,18 @@ vec3 pbrIbl(vec3 diffuseColor, // of the shading terms, outlined in the Readme.MD Appendix. struct PBRInfo { - float NdotL; // cos angle between normal and light direction - float NdotV; // cos angle between normal and view direction - float NdotH; // cos angle between normal and half vector - float LdotH; // cos angle between light direction and half vector - float VdotH; // cos angle between view direction and half vector - float perceptualRoughness; // roughness value, as authored by the model creator (input to shader) - float metalness; // metallic value at the surface - vec3 reflectance0; // full reflectance color (normal incidence angle) - vec3 reflectance90; // reflectance color at grazing angle - float alphaRoughness; // roughness mapped to a more linear change in the roughness (proposed by [2]) - vec3 diffuseColor; // color contribution from diffuse lighting - vec3 specularColor; // color contribution from specular lighting + float NdotL; // cos angle between normal and light direction + float NdotV; // cos angle between normal and view direction + float NdotH; // cos angle between normal and half vector + float LdotH; // cos angle between light direction and half vector + float VdotH; // cos angle between view direction and half vector + float perceptualRoughness; // roughness value, as authored by the model creator (input to shader) + float metalness; // metallic value at the surface + vec3 reflectance0; // full reflectance color (normal incidence angle) + vec3 reflectance90; // reflectance color at grazing angle + float alphaRoughness; // roughness mapped to a more linear change in the roughness (proposed by [2]) + vec3 diffuseColor; // color contribution from diffuse lighting + vec3 specularColor; // color contribution from specular lighting }; // Basic Lambertian diffuse @@ -420,14 +407,14 @@ struct PBRInfo // See also [1], Equation 1 vec3 diffuse(PBRInfo pbrInputs) { - return pbrInputs.diffuseColor / M_PI; + return pbrInputs.diffuseColor / M_PI; } // The following equation models the Fresnel reflectance term of the spec equation (aka F()) // Implementation of fresnel from [4], Equation 15 vec3 specularReflection(PBRInfo pbrInputs) { - return pbrInputs.reflectance0 + (pbrInputs.reflectance90 - pbrInputs.reflectance0) * pow(clamp(1.0 - pbrInputs.VdotH, 0.0, 1.0), 5.0); + return pbrInputs.reflectance0 + (pbrInputs.reflectance90 - pbrInputs.reflectance0) * pow(clamp(1.0 - pbrInputs.VdotH, 0.0, 1.0), 5.0); } // This calculates the specular geometric attenuation (aka G()), @@ -436,13 +423,13 @@ vec3 specularReflection(PBRInfo pbrInputs) // alphaRoughness as input as originally proposed in [2]. float geometricOcclusion(PBRInfo pbrInputs) { - float NdotL = pbrInputs.NdotL; - float NdotV = pbrInputs.NdotV; - float r = pbrInputs.alphaRoughness; + float NdotL = pbrInputs.NdotL; + float NdotV = pbrInputs.NdotV; + float r = pbrInputs.alphaRoughness; - float attenuationL = 2.0 * NdotL / (NdotL + sqrt(r * r + (1.0 - r * r) * (NdotL * NdotL))); - float attenuationV = 2.0 * NdotV / (NdotV + sqrt(r * r + (1.0 - r * r) * (NdotV * NdotV))); - return attenuationL * attenuationV; + float attenuationL = 2.0 * NdotL / (NdotL + sqrt(r * r + (1.0 - r * r) * (NdotL * NdotL))); + float attenuationV = 2.0 * NdotV / (NdotV + sqrt(r * r + (1.0 - r * r) * (NdotV * NdotV))); + return attenuationL * attenuationV; } // The following equation(s) model the distribution of microfacet normals across the area being drawn (aka D()) @@ -450,69 +437,117 @@ float geometricOcclusion(PBRInfo pbrInputs) // Follows the distribution function recommended in the SIGGRAPH 2013 course notes from EPIC Games [1], Equation 3. float microfacetDistribution(PBRInfo pbrInputs) { - float roughnessSq = pbrInputs.alphaRoughness * pbrInputs.alphaRoughness; - float f = (pbrInputs.NdotH * roughnessSq - pbrInputs.NdotH) * pbrInputs.NdotH + 1.0; - return roughnessSq / (M_PI * f * f); + float roughnessSq = pbrInputs.alphaRoughness * pbrInputs.alphaRoughness; + float f = (pbrInputs.NdotH * roughnessSq - pbrInputs.NdotH) * pbrInputs.NdotH + 1.0; + return roughnessSq / (M_PI * f * f); } -vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor, - float perceptualRoughness, +void pbrPunctual(vec3 diffuseColor, vec3 specularColor, + float perceptualRoughness, float metallic, vec3 n, // normal vec3 v, // surface point to camera - vec3 l) //surface point to light + vec3 l, + out float nl, + out vec3 diff, + out vec3 spec) //surface point to light { // make sure specular highlights from punctual lights don't fall off of polished surfaces perceptualRoughness = max(perceptualRoughness, 8.0/255.0); - - float alphaRoughness = perceptualRoughness * perceptualRoughness; - - // Compute reflectance. - float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b); - - // For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect. - // For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%. - float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0); - vec3 specularEnvironmentR0 = specularColor.rgb; - vec3 specularEnvironmentR90 = vec3(1.0, 1.0, 1.0) * reflectance90; - - vec3 h = normalize(l+v); // Half vector between both l and v - vec3 reflection = -normalize(reflect(v, n)); - reflection.y *= -1.0f; - - float NdotL = clamp(dot(n, l), 0.001, 1.0); - float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0); - float NdotH = clamp(dot(n, h), 0.0, 1.0); - float LdotH = clamp(dot(l, h), 0.0, 1.0); - float VdotH = clamp(dot(v, h), 0.0, 1.0); - - PBRInfo pbrInputs = PBRInfo( - NdotL, - NdotV, - NdotH, - LdotH, - VdotH, - perceptualRoughness, - metallic, - specularEnvironmentR0, - specularEnvironmentR90, - alphaRoughness, - diffuseColor, - specularColor - ); - - // Calculate the shading terms for the microfacet specular shading model - vec3 F = specularReflection(pbrInputs); - float G = geometricOcclusion(pbrInputs); - float D = microfacetDistribution(pbrInputs); - - // Calculation of analytical lighting contribution - vec3 diffuseContrib = (1.0 - F) * diffuse(pbrInputs); - vec3 specContrib = F * G * D / (4.0 * NdotL * NdotV); - // Obtain final intensity as reflectance (BRDF) scaled by the energy of the light (cosine law) - vec3 color = NdotL * (diffuseContrib + specContrib); - - return clamp(color, vec3(0), vec3(10)); + + float alphaRoughness = perceptualRoughness * perceptualRoughness; + + // Compute reflectance. + float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b); + + // For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect. + // For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%. + float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0); + vec3 specularEnvironmentR0 = specularColor.rgb; + vec3 specularEnvironmentR90 = vec3(1.0, 1.0, 1.0) * reflectance90; + + vec3 h = normalize(l+v); // Half vector between both l and v + vec3 reflection = -normalize(reflect(v, n)); + reflection.y *= -1.0f; + + float NdotL = clamp(dot(n, l), 0.001, 1.0); + float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0); + float NdotH = clamp(dot(n, h), 0.0, 1.0); + float LdotH = clamp(dot(l, h), 0.0, 1.0); + float VdotH = clamp(dot(v, h), 0.0, 1.0); + + PBRInfo pbrInputs = PBRInfo( + NdotL, + NdotV, + NdotH, + LdotH, + VdotH, + perceptualRoughness, + metallic, + specularEnvironmentR0, + specularEnvironmentR90, + alphaRoughness, + diffuseColor, + specularColor + ); + + // Calculate the shading terms for the microfacet specular shading model + vec3 F = specularReflection(pbrInputs); + float G = geometricOcclusion(pbrInputs); + float D = microfacetDistribution(pbrInputs); + + // Calculation of analytical lighting contribution + vec3 diffuseContrib = (1.0 - F) * diffuse(pbrInputs); + vec3 specContrib = F * G * D / (4.0 * NdotL * NdotV); + + nl = NdotL; + + diff = diffuseContrib; + spec = specContrib; +} + +vec3 pbrCalcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor, + float perceptualRoughness, + float metallic, + vec3 n, // normal + vec3 p, // pixel position + vec3 v, // view vector (negative normalized pixel position) + vec3 lp, // light position + vec3 ld, // light direction (for spotlights) + vec3 lightColor, + float lightSize, float falloff, float is_pointlight, float ambiance) +{ + vec3 color = vec3(0,0,0); + + vec3 lv = lp.xyz - p; + + float lightDist = length(lv); + + float dist = lightDist / lightSize; + if (dist <= 1.0) + { + lv /= lightDist; + + float dist_atten = calcLegacyDistanceAttenuation(dist, falloff); + + // spotlight coefficient. + float spot = max(dot(-ld, lv), is_pointlight); + // spot*spot => GL_SPOT_EXPONENT=2 + float spot_atten = spot*spot; + + vec3 intensity = spot_atten * dist_atten * lightColor * 3.0; //magic number to balance with legacy materials + + float nl = 0; + vec3 diffPunc = vec3(0); + vec3 specPunc = vec3(0); + + pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, n.xyz, v, lv, nl, diffPunc, specPunc); + color = intensity * clamp(nl * (diffPunc + specPunc), vec3(0), vec3(10)); + } + float final_scale = 1.0; + if (classic_mode > 0) + final_scale = 0.9; + return color * final_scale; } void calcDiffuseSpecular(vec3 baseColor, float metallic, inout vec3 diffuseColor, inout vec3 specularColor) @@ -528,10 +563,47 @@ vec3 pbrBaseLight(vec3 diffuseColor, vec3 specularColor, float metallic, vec3 v, vec3 color = vec3(0); float NdotV = clamp(abs(dot(norm, v)), 0.001, 1.0); - - color += pbrIbl(diffuseColor, specularColor, radiance, irradiance, ao, NdotV, perceptualRoughness); - - color += pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, norm, v, normalize(light_dir)) * sunlit * 3.0 * scol; //magic number to balance with legacy materials + vec3 iblDiff = vec3(0); + vec3 iblSpec = vec3(0); + pbrIbl(diffuseColor, specularColor, radiance, irradiance, ao, NdotV, perceptualRoughness, iblDiff, iblSpec); + + color += iblDiff; + + // For classic mode, we use a special version of pbrPunctual that basically gives us a deconstructed form of the lighting. + float nl = 0; + vec3 diffPunc = vec3(0); + vec3 specPunc = vec3(0); + pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, norm, v, normalize(light_dir), nl, diffPunc, specPunc); + + // Depending on the sky, we combine these differently. + if (classic_mode > 0) + { + irradiance.rgb = srgb_to_linear(irradiance * 0.9); // BINGO + + // Reconstruct the diffuse lighting that we do for blinn-phong materials here. + // A special note about why we do some really janky stuff for classic mode. + // Since adding classic mode, we've moved the lambertian diffuse multiply out from pbrPunctual and instead handle it in the different light type calcs. + // This will never be 100% correct, but at the very least we can make it look mostly correct with legacy skies and classic mode. + + float da = pow(nl, 1.2); + + vec3 sun_contrib = vec3(min(da, scol)); + + // Multiply by PI to account for lambertian diffuse colors. Otherwise things will be too dark when lit by the sun on legacy skies. + sun_contrib = srgb_to_linear(linear_to_srgb(sun_contrib) * sunlit * 0.7) * M_PI; + + // Manually recombine everything here. We have to separate the shading to ensure that lighting is able to more closely match blinn-phong. + vec3 finalAmbient = irradiance.rgb * diffuseColor.rgb; // BINGO + vec3 finalSun = clamp(sun_contrib * ((diffPunc.rgb + specPunc.rgb) * scol), vec3(0), vec3(10)); // QUESTIONABLE BINGO? + color.rgb = srgb_to_linear(linear_to_srgb(finalAmbient) + (linear_to_srgb(finalSun) * 1.1)); + //color.rgb = sun_contrib * diffuseColor.rgb; + } + else + { + color += clamp(nl * (diffPunc + specPunc), vec3(0), vec3(10)) * sunlit * 3.0 * scol; + } + + color.rgb += iblSpec.rgb; color += colorEmissive; |