summaryrefslogtreecommitdiff
path: root/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl')
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl392
1 files changed, 392 insertions, 0 deletions
diff --git a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl
index e27bbce094..68a57d12f0 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/deferredUtil.glsl
@@ -25,10 +25,88 @@
uniform sampler2DRect normalMap;
uniform sampler2DRect depthMap;
+uniform sampler2D projectionMap; // rgba
+
+// projected lighted params
+uniform mat4 proj_mat; //screen space to light space projector
+uniform vec3 proj_n; // projector normal
+uniform vec3 proj_p; //plane projection is emitting from (in screen space)
+uniform float proj_focus; // distance from plane to begin blurring
+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;
+
+// light params
+uniform vec3 color; // light_color
+uniform float size; // light_size
uniform mat4 inv_proj;
uniform vec2 screen_res;
+const float M_PI = 3.14159265;
+const float ONE_OVER_PI = 0.3183098861;
+
+vec3 srgb_to_linear(vec3 cs);
+
+float calcLegacyDistanceAttenuation(float distance, float falloff)
+{
+ float dist_atten = 1.0 - clamp((distance + falloff)/(1.0 + falloff), 0.0, 1.0);
+ dist_atten *= dist_atten;
+
+ // Tweak falloff slightly to match pre-EEP attenuation
+ // NOTE: this magic number also shows up in a great many other places, search for dist_atten *= to audit
+ dist_atten *= 2.0;
+ return dist_atten;
+}
+
+// In:
+// lv unnormalized surface to light vector
+// n normal of the surface
+// pos unnormalized camera to surface vector
+// Out:
+// l normalized surace to light vector
+// nl diffuse angle
+// nh specular angle
+void calcHalfVectors(vec3 lv, vec3 n, vec3 v,
+ out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist)
+{
+ 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);
+
+ lightDist = length(lv);
+}
+
+// In:
+// light_center
+// pos
+// Out:
+// dist
+// l_dist
+// lv
+// proj_tc Projector Textue Coordinates
+bool clipProjectedLightVars(vec3 light_center, vec3 pos, out float dist, out float l_dist, out vec3 lv, out vec4 proj_tc )
+{
+ lv = light_center - pos.xyz;
+ dist = length(lv);
+ bool clipped = (dist >= size);
+ if ( !clipped )
+ {
+ dist /= size;
+
+ l_dist = -dot(lv, proj_n);
+ vec4 projected_point = (proj_mat * vec4(pos.xyz, 1.0));
+ clipped = (projected_point.z < 0.0);
+ projected_point.xyz /= projected_point.w;
+ proj_tc = projected_point;
+ }
+
+ return clipped;
+}
+
vec2 getScreenCoordinate(vec2 screenpos)
{
vec2 sc = screenpos.xy * 2.0;
@@ -39,6 +117,8 @@ 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 = texture2DRect(normalMap, screenpos.xy).xy;
@@ -51,12 +131,136 @@ vec3 getNorm(vec2 screenpos)
return n;
}
+vec3 getNormalFromPacked(vec4 packedNormalEnvIntensityFlags)
+{
+ 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?
+}
+
+// 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 packedNormalEnvIntensityFlags = texture2DRect(normalMap, screenpos.xy);
+ n = getNormalFromPacked( packedNormalEnvIntensityFlags );
+ envIntensity = packedNormalEnvIntensityFlags.z;
+ return packedNormalEnvIntensityFlags;
+}
+
float getDepth(vec2 pos_screen)
{
float depth = texture2DRect(depthMap, pos_screen).r;
return depth;
}
+vec4 getTexture2DLodAmbient(vec2 tc, float lod)
+{
+ vec4 ret = texture2DLod(projectionMap, tc, lod);
+ ret.rgb = srgb_to_linear(ret.rgb);
+
+ vec2 dist = tc-vec2(0.5);
+ float d = dot(dist,dist);
+ ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0), 1.0);
+
+ return ret;
+}
+
+vec4 getTexture2DLodDiffuse(vec2 tc, float lod)
+{
+ vec4 ret = texture2DLod(projectionMap, tc, lod);
+ ret.rgb = srgb_to_linear(ret.rgb);
+
+ vec2 dist = vec2(0.5) - abs(tc-vec2(0.5));
+ float det = min(lod/(proj_lod*0.5), 1.0);
+ float d = min(dist.x, dist.y);
+ float edge = 0.25*det;
+ ret *= clamp(d/edge, 0.0, 1.0);
+
+ return ret;
+}
+
+// lit This is set by the caller: if (nl > 0.0) { lit = attenuation * nl * noise; }
+// Uses:
+// color Projected spotlight color
+vec3 getProjectedLightAmbiance(float amb_da, float attenuation, float lit, float nl, float noise, vec2 projected_uv)
+{
+ vec4 amb_plcol = getTexture2DLodAmbient(projected_uv, proj_lod);
+ vec3 amb_rgb = amb_plcol.rgb * amb_plcol.a;
+
+ amb_da += proj_ambiance;
+ amb_da += (nl*nl*0.5+0.5) * proj_ambiance;
+ amb_da *= attenuation * noise;
+ amb_da = min(amb_da, 1.0-lit);
+
+ return (amb_da * color.rgb * amb_rgb);
+}
+
+// Returns projected light in Linear
+// Uses global spotlight color:
+// color
+// NOTE: projected.a will be pre-multiplied with projected.rgb
+vec3 getProjectedLightDiffuseColor(float light_distance, vec2 projected_uv)
+{
+ float diff = clamp((light_distance - proj_focus)/proj_range, 0.0, 1.0);
+ float lod = diff * proj_lod;
+ vec4 plcol = getTexture2DLodDiffuse(projected_uv.xy, lod);
+
+ return color.rgb * plcol.rgb * plcol.a;
+}
+
+vec4 texture2DLodSpecular(vec2 tc, float lod)
+{
+ vec4 ret = texture2DLod(projectionMap, tc, lod);
+ ret.rgb = srgb_to_linear(ret.rgb);
+
+ vec2 dist = vec2(0.5) - abs(tc-vec2(0.5));
+ float det = min(lod/(proj_lod*0.5), 1.0);
+ float d = min(dist.x, dist.y);
+ d *= min(1, d * (proj_lod - lod)); // BUG? extra factor compared to diffuse causes N repeats
+ float edge = 0.25*det;
+ ret *= clamp(d/edge, 0.0, 1.0);
+
+ return ret;
+}
+
+// See: clipProjectedLightVars()
+vec3 getProjectedLightSpecularColor(vec3 pos, vec3 n )
+{
+ vec3 slit = vec3(0);
+ vec3 ref = reflect(normalize(pos), n);
+
+ //project from point pos in direction ref to plane proj_p, proj_n
+ vec3 pdelta = proj_p-pos;
+ float l_dist = length(pdelta);
+ float ds = dot(ref, proj_n);
+ if (ds < 0.0)
+ {
+ vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds;
+ vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0));
+ if (stc.z > 0.0)
+ {
+ stc /= stc.w;
+ slit = getProjectedLightDiffuseColor( l_dist, stc.xy ); // NOTE: Using diffuse due to texture2DLodSpecular() has extra: d *= min(1, d * (proj_lod - lod));
+ }
+ }
+ return slit; // specular light
+}
+
+vec3 getProjectedLightSpecularColor(float light_distance, vec2 projected_uv)
+{
+ float diff = clamp((light_distance - proj_focus)/proj_range, 0.0, 1.0);
+ float lod = diff * proj_lod;
+ vec4 plcol = getTexture2DLodDiffuse(projected_uv.xy, lod); // NOTE: Using diffuse due to texture2DLodSpecular() has extra: d *= min(1, d * (proj_lod - lod));
+
+ return color.rgb * plcol.rgb * plcol.a;
+}
+
vec4 getPosition(vec2 pos_screen)
{
float depth = getDepth(pos_screen);
@@ -77,3 +281,191 @@ vec4 getPositionWithDepth(vec2 pos_screen, float depth)
pos.w = 1.0;
return pos;
}
+
+vec2 getScreenXY(vec4 clip)
+{
+ vec4 ndc = clip;
+ ndc.xyz /= clip.w;
+ vec2 screen = vec2( ndc.xy * 0.5 );
+ screen += 0.5;
+ screen *= screen_res;
+ return screen;
+}
+
+// Color utils
+
+vec3 colorize_dot(float x)
+{
+ if (x > 0.0) return vec3( 0, x, 0 );
+ if (x < 0.0) return vec3(-x, 0, 0 );
+ return vec3( 0, 0, 1 );
+}
+
+vec3 hue_to_rgb(float hue)
+{
+ if (hue > 1.0) return vec3(0.5);
+ vec3 rgb = abs(hue * 6. - vec3(3, 2, 4)) * vec3(1, -1, -1) + vec3(-1, 2, 2);
+ return clamp(rgb, 0.0, 1.0);
+}
+
+// PBR Utils
+
+// ior Index of Refraction, normally 1.5
+// returns reflect0
+float calcF0(float ior)
+{
+ float f0 = (1.0 - ior) / (1.0 + ior);
+ return f0 * f0;
+}
+
+vec3 fresnel(float vh, vec3 f0, vec3 f90 )
+{
+ float x = 1.0 - abs(vh);
+ float x2 = x*x;
+ float x5 = x2*x2*x;
+ vec3 fr = f0 + (f90 - f0)*x5;
+ return fr;
+}
+
+vec3 fresnelSchlick( vec3 reflect0, vec3 reflect90, float vh)
+{
+ return reflect0 + (reflect90 - reflect0) * pow(clamp(1.0 - vh, 0.0, 1.0), 5.0);
+}
+
+// Approximate Environment BRDF
+vec2 getGGXApprox( vec2 uv )
+{
+ // Reference: Physically Based Shading on Mobile
+ // https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
+ // EnvBRDFApprox( vec3 SpecularColor, float Roughness, float NoV )
+ float nv = uv.x;
+ float roughness = uv.y;
+
+ const vec4 c0 = vec4( -1, -0.0275, -0.572, 0.022 );
+ const vec4 c1 = vec4( 1, 0.0425, 1.04 , -0.04 );
+ vec4 r = roughness * c0 + c1;
+ float a004 = min( r.x * r.x, exp2( -9.28 * nv ) ) * r.x + r.y;
+ vec2 ScaleBias = vec2( -1.04, 1.04 ) * a004 + r.zw;
+ return ScaleBias;
+}
+
+#define PBR_USE_GGX_APPROX 1
+vec2 getGGX( vec2 brdfPoint )
+{
+#if PBR_USE_GGX_APPROX
+ return getGGXApprox( brdfPoint);
+#else
+ return texture2D(GGXLUT, brdfPoint).rg; // TODO: use GGXLUT
+#endif
+}
+
+
+// Reference: float getRangeAttenuation(float range, float distance)
+float getLightAttenuationPointSpot(float range, float distance)
+{
+#if 1
+ return distance;
+#else
+ float range2 = pow(range, 2.0);
+
+ // support negative range as unlimited
+ if (range <= 0.0)
+ {
+ return 1.0 / range2;
+ }
+
+ return max(min(1.0 - pow(distance / range, 4.0), 1.0), 0.0) / range2;
+#endif
+}
+
+vec3 getLightIntensityPoint(vec3 lightColor, float lightRange, float lightDistance)
+{
+ float rangeAttenuation = getLightAttenuationPointSpot(lightRange, lightDistance);
+ return rangeAttenuation * lightColor;
+}
+
+float getLightAttenuationSpot(vec3 spotDirection)
+{
+ return 1.0;
+}
+
+vec3 getLightIntensitySpot(vec3 lightColor, float lightRange, float lightDistance, vec3 v)
+{
+ float spotAttenuation = getLightAttenuationSpot(-v);
+ return spotAttenuation * getLightIntensityPoint( lightColor, lightRange, lightDistance );
+}
+
+// NOTE: This is different from the GGX texture
+float D_GGX( float nh, float alphaRough )
+{
+ float rough2 = alphaRough * alphaRough;
+ float f = (nh * nh) * (rough2 - 1.0) + 1.0;
+ return rough2 / (M_PI * f * f);
+}
+
+// NOTE: This is different from the GGX texture
+// See:
+// Real Time Rendering, 4th Edition
+// Page 341
+// Equation 9.43
+// Also see:
+// https://google.github.io/filament/Filament.md.html#materialsystem/specularbrdf/geometricshadowing(specularg)
+// 4.4.2 Geometric Shadowing (specular G)
+float V_GGX( float nl, float nv, float alphaRough )
+{
+#if 1
+ // Note: When roughness is zero, has discontuinity in the bottom hemisphere
+ float rough2 = alphaRough * alphaRough;
+ float ggxv = nl * sqrt(nv * nv * (1.0 - rough2) + rough2);
+ float ggxl = nv * sqrt(nl * nl * (1.0 - rough2) + rough2);
+
+ float ggx = ggxv + ggxl;
+ if (ggx > 0.0)
+ {
+ return 0.5 / ggx;
+ }
+ return 0.0;
+#else
+ // See: smithVisibility_GGXCorrelated, V_SmithCorrelated, etc.
+ float rough2 = alphaRough * alphaRough;
+ float ggxv = nl * sqrt(nv * (nv - rough2 * nv) + rough2);
+ float ggxl = nv * sqrt(nl * (nl - rough2 * nl) + rough2);
+ return 0.5 / (ggxv + ggxl);
+#endif
+
+}
+
+// NOTE: Assumes a hard-coded IOR = 1.5
+void initMaterial( vec3 diffuse, vec3 packedORM, out float alphaRough, out vec3 c_diff, out vec3 reflect0, out vec3 reflect90, out float specWeight )
+{
+ float metal = packedORM.b;
+ c_diff = mix(diffuse, vec3(0), metal);
+ float IOR = 1.5; // default Index Of Refraction 1.5 (dielectrics)
+ reflect0 = vec3(0.04); // -> incidence reflectance 0.04
+// reflect0 = vec3(calcF0(IOR));
+ reflect0 = mix(reflect0, diffuse, metal); // reflect at 0 degrees
+ reflect90 = vec3(1); // reflect at 90 degrees
+ specWeight = 1.0;
+
+ // When roughness is zero blender shows a tiny specular
+ float perceptualRough = max(packedORM.g, 0.1);
+ alphaRough = perceptualRough * perceptualRough;
+}
+
+vec3 BRDFDiffuse(vec3 color)
+{
+ return color * ONE_OVER_PI;
+}
+
+vec3 BRDFLambertian( vec3 reflect0, vec3 reflect90, vec3 c_diff, float specWeight, float vh )
+{
+ return (1.0 - specWeight * fresnelSchlick( reflect0, reflect90, vh)) * BRDFDiffuse(c_diff);
+}
+
+vec3 BRDFSpecularGGX( vec3 reflect0, vec3 reflect90, float alphaRough, float specWeight, float vh, float nl, float nv, float nh )
+{
+ vec3 fresnel = fresnelSchlick( reflect0, reflect90, vh ); // Fresnel
+ float vis = V_GGX( nl, nv, alphaRough ); // Visibility
+ float d = D_GGX( nh, alphaRough ); // Distribution
+ return specWeight * fresnel * vis * d;
+}