summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorDave Parks <davep@lindenlab.com>2022-05-19 22:24:41 -0500
committerDave Parks <davep@lindenlab.com>2022-05-19 22:24:41 -0500
commit3564b24e2a90e0772c37185cc5dcedca29d62ab8 (patch)
tree9c0e7fa9d747d7bca7b25352bf8e28c875163e77 /indra
parent02fb1bd6103cad5538fc170e015f4329f3545542 (diff)
SL-17286 Reflection probe alpha/fullbright support.
Diffstat (limited to 'indra')
-rw-r--r--indra/llrender/llglslshader.h1
-rw-r--r--indra/llrender/llshadermgr.cpp8
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl50
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl16
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/materialF.glsl64
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/reflectionProbeF.glsl44
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl476
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl436
-rw-r--r--indra/newview/lldrawpoolbump.cpp9
-rw-r--r--indra/newview/llreflectionmapmanager.cpp2
-rw-r--r--indra/newview/llviewershadermgr.cpp14
-rw-r--r--indra/newview/pipeline.cpp53
-rw-r--r--indra/newview/pipeline.h4
13 files changed, 686 insertions, 491 deletions
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index fe0aaae467..6b4778c270 100644
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -58,6 +58,7 @@ public:
S32 mIndexedTextureChannels;
bool disableTextureIndex;
bool hasAlphaMask;
+ bool hasReflectionProbes = false;
bool attachNothing;
// char numLights;
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index 8e8f44e99b..bdc1f78201 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -218,6 +218,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
}
}
+ if (features->hasReflectionProbes)
+ {
+ if (!shader->attachFragmentObject("deferred/reflectionProbeF.glsl"))
+ {
+ return FALSE;
+ }
+ }
+
if (features->hasAmbientOcclusion)
{
if (!shader->attachFragmentObject("deferred/aoUtil.glsl"))
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl
index 9fcee04c32..a04f611440 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl
@@ -35,10 +35,11 @@ out vec4 frag_color;
uniform sampler2D diffuseMap;
#endif
+
VARYING vec4 vertex_color;
VARYING vec2 vary_texcoord0;
VARYING vec3 vary_texcoord1;
-VARYING vec4 vary_position;
+VARYING vec3 vary_position;
uniform samplerCube environmentMap;
@@ -54,6 +55,14 @@ void calcAtmosphericVars(vec3 inPositionEye, vec3 light_dir, float ambFactor, ou
vec3 linear_to_srgb(vec3 c);
vec3 srgb_to_linear(vec3 c);
+#ifdef HAS_REFLECTION_PROBES
+// reflection probe interface
+void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyEnv,
+ vec3 pos, vec3 norm, float glossiness, float envIntensity);
+void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm);
+void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity);
+#endif
+
// See:
// class1\deferred\fullbrightShinyF.glsl
// class1\lighting\lightFullbrightShinyF.glsl
@@ -70,21 +79,29 @@ void main()
// SL-9632 HUDs are affected by Atmosphere
if (no_atmo == 0)
{
- vec3 sunlit;
- vec3 amblit;
- vec3 additive;
- vec3 atten;
- vec3 pos = vary_position.xyz/vary_position.w;
-
- calcAtmosphericVars(pos.xyz, vec3(0), 1.0, sunlit, amblit, additive, atten, false);
-
- vec3 envColor = textureCube(environmentMap, vary_texcoord1.xyz).rgb;
- float env_intensity = vertex_color.a;
-
- //color.rgb = srgb_to_linear(color.rgb);
- color.rgb = mix(color.rgb, envColor.rgb, env_intensity);
- color.rgb = fullbrightAtmosTransportFrag(color.rgb, additive, atten);
- color.rgb = fullbrightScaleSoftClip(color.rgb);
+ vec3 sunlit;
+ vec3 amblit;
+ vec3 additive;
+ vec3 atten;
+ vec3 pos = vary_position;
+ calcAtmosphericVars(pos.xyz, vec3(0), 1.0, sunlit, amblit, additive, atten, false);
+
+ float env_intensity = vertex_color.a;
+#ifndef HAS_REFLECTION_PROBES
+ vec3 envColor = textureCube(environmentMap, vary_texcoord1.xyz).rgb;
+ color.rgb = mix(color.rgb, envColor.rgb, env_intensity);
+#else
+ vec3 ambenv;
+ vec3 glossenv;
+ vec3 legacyenv;
+ vec3 norm = normalize(vary_texcoord1.xyz);
+ vec4 spec = vec4(0,0,0,0);
+ sampleReflectionProbes(ambenv, glossenv, legacyenv, pos.xyz, norm.xyz, spec.a, env_intensity);
+ legacyenv *= 1.5; // fudge brighter
+ applyLegacyEnv(color.rgb, legacyenv, spec, pos, norm, env_intensity);
+#endif
+ color.rgb = fullbrightAtmosTransportFrag(color.rgb, additive, atten);
+ color.rgb = fullbrightScaleSoftClip(color.rgb);
}
/*
@@ -98,7 +115,6 @@ void main()
*/
color.a = 1.0;
-
//color.rgb = linear_to_srgb(color.rgb);
frag_color = color;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl
index 2c139430e7..a897198062 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl
@@ -44,7 +44,7 @@ ATTRIBUTE vec2 texcoord0;
VARYING vec4 vertex_color;
VARYING vec2 vary_texcoord0;
VARYING vec3 vary_texcoord1;
-VARYING vec4 vary_position;
+VARYING vec3 vary_position;
#ifdef HAS_SKIN
mat4 getObjectSkinnedTransform();
@@ -61,17 +61,23 @@ void main()
mat4 mat = getObjectSkinnedTransform();
mat = modelview_matrix * mat;
vec4 pos = mat * vert;
- vary_position = gl_Position = projection_matrix * pos;
+ gl_Position = projection_matrix * pos;
vec3 norm = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz);
#else
vec4 pos = (modelview_matrix * vert);
- vary_position = gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
+ gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
vec3 norm = normalize(normal_matrix * normal);
#endif
- vec3 ref = reflect(pos.xyz, -norm);
- vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
+ vary_position = pos.xyz;
+ vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
+
+#ifndef HAS_REFLECTION_PROBES
+ vec3 ref = reflect(pos.xyz, -norm);
vary_texcoord1 = transpose(normal_matrix) * ref.xyz;
+#else
+ vary_texcoord1 = norm;
+#endif
calcAtmospherics(pos.xyz);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
index 02d83925ea..c5b1937cfb 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
@@ -64,6 +64,13 @@ out vec4 frag_color;
float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen);
#endif
+#ifdef HAS_REFLECTION_PROBES
+void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
+ vec3 pos, vec3 norm, float glossiness, float envIntensity);
+void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm);
+void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity);
+#endif
+
uniform samplerCube environmentMap;
uniform sampler2D lightFunc;
@@ -322,6 +329,16 @@ void main()
// lighting from the sun stays sharp
float da = clamp(dot(normalize(norm.xyz), light_dir.xyz), 0.0, 1.0);
da = pow(da, 1.0 / 1.3);
+ vec3 sun_contrib = min(da, shadow) * sunlit;
+
+#ifdef HAS_REFLECTION_PROBES
+ vec3 ambenv;
+ vec3 glossenv;
+ vec3 legacyenv;
+ sampleReflectionProbes(ambenv, glossenv, legacyenv, pos.xyz, norm.xyz, spec.a, envIntensity);
+ amblit = max(ambenv, amblit);
+ color.rgb = amblit;
+#else
color = amblit;
@@ -333,9 +350,8 @@ void main()
ambient *= ambient;
ambient = (1.0 - ambient);
- vec3 sun_contrib = min(da, shadow) * sunlit;
-
color *= ambient;
+#endif
color += sun_contrib;
@@ -345,35 +361,6 @@ void main()
if (spec.a > 0.0) // specular reflection
{
- /* // Reverting this specular calculation to previous 'dumbshiny' version - DJH 6/17/2020
- // Preserving the refactored version as a comment for potential reconsideration,
- // overriding the general rule to avoid pollutiong the source with commented code.
- //
- // If you're reading this in 2021+, feel free to obliterate.
-
- vec3 npos = -normalize(pos.xyz);
-
- //vec3 ref = dot(pos+lv, norm);
- vec3 h = normalize(light_dir.xyz + npos);
- float nh = dot(norm.xyz, h);
- float nv = dot(norm.xyz, npos);
- float vh = dot(npos, h);
- float sa = nh;
- float fres = pow(1 - dot(h, npos), 5)*0.4 + 0.5;
-
- float gtdenom = 2 * nh;
- float gt = max(0, min(gtdenom * nv / vh, gtdenom * da / vh));
-
- if (nh > 0.0)
- {
- float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt / (nh*da);
- vec3 sp = sun_contrib*scol / 6.0f;
- sp = clamp(sp, vec3(0), vec3(1));
- bloom = dot(sp, sp) / 4.0;
- color += sp * spec.rgb;
- }
- */
-
float sa = dot(refnormpersp, sun_dir.xyz);
vec3 dumbshiny = sunlit * shadow * (texture2D(lightFunc, vec2(sa, spec.a)).r);
@@ -385,10 +372,24 @@ void main()
glare = max(glare, spec_contrib.b);
color += spec_contrib;
+
+#ifdef HAS_REFLECTION_PROBES
+ applyGlossEnv(color, glossenv, spec, pos.xyz, norm.xyz);
+#endif
}
+
color = mix(color.rgb, diffcol.rgb, diffuse.a);
+#ifdef HAS_REFLECTION_PROBES
+ if (envIntensity > 0.0)
+ { // add environmentmap
+ //fudge darker
+ legacyenv *= 0.5*diffuse.a+0.5;
+
+ applyLegacyEnv(color, legacyenv, spec, pos.xyz, norm.xyz, envIntensity);
+ }
+#else
if (envIntensity > 0.0)
{
//add environmentmap
@@ -403,6 +404,7 @@ void main()
cur_glare *= envIntensity*4.0;
glare += cur_glare;
}
+#endif
color = atmosFragLighting(color, additive, atten);
color = scaleSoftClipFrag(color);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class1/deferred/reflectionProbeF.glsl
new file mode 100644
index 0000000000..8f3e38b08b
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/reflectionProbeF.glsl
@@ -0,0 +1,44 @@
+/**
+ * @file class1/deferred/reflectionProbeF.glsl
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, 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$
+ */
+
+// fallback stub -- will be used if actual reflection probe shader failed to load (output pink so it's obvious)
+void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
+ vec3 pos, vec3 norm, float glossiness, float envIntensity)
+{
+ ambenv = vec3(1,0,1);
+ glossenv = vec3(1,0,1);
+ legacyenv = vec3(1,0,1);
+}
+
+void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm)
+{
+ color = vec3(1,0,1);
+}
+
+void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity)
+{
+ color = vec3(1,0,1);
+}
+
diff --git a/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl
new file mode 100644
index 0000000000..8c1323ba1a
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/reflectionProbeF.glsl
@@ -0,0 +1,476 @@
+/**
+ * @file class2/deferred/reflectionProbeF.glsl
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, 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$
+ */
+
+#extension GL_ARB_shader_texture_lod : enable
+
+#define FLT_MAX 3.402823466e+38
+
+#define REFMAP_COUNT 256
+#define REF_SAMPLE_COUNT 64 //maximum number of samples to consider
+
+uniform samplerCubeArray reflectionProbes;
+
+layout (std140, binding = 1) uniform ReflectionProbes
+{
+ // list of OBBs for user override probes
+ // box is a set of 3 planes outward facing planes and the depth of the box along that plane
+ // for each box refBox[i]...
+ /// box[0..2] - plane 0 .. 2 in [A,B,C,D] notation
+ // box[3][0..2] - plane thickness
+ mat4 refBox[REFMAP_COUNT];
+ // list of bounding spheres for reflection probes sorted by distance to camera (closest first)
+ vec4 refSphere[REFMAP_COUNT];
+ // index of cube map in reflectionProbes for a corresponding reflection probe
+ // e.g. cube map channel of refSphere[2] is stored in refIndex[2]
+ // refIndex.x - cubemap channel in reflectionProbes
+ // refIndex.y - index in refNeighbor of neighbor list (index is ivec4 index, not int index)
+ // refIndex.z - number of neighbors
+ // refIndex.w - priority, if negative, this probe has a box influence
+ ivec4 refIndex[REFMAP_COUNT];
+
+ // neighbor list data (refSphere indices, not cubemap array layer)
+ ivec4 refNeighbor[1024];
+
+ // number of reflection probes present in refSphere
+ int refmapCount;
+
+ // intensity of ambient light from reflection probes
+ float reflectionAmbiance;
+};
+
+// Inputs
+uniform mat3 env_mat;
+
+// list of probeIndexes shader will actually use after "getRefIndex" is called
+// (stores refIndex/refSphere indices, NOT rerflectionProbes layer)
+int probeIndex[REF_SAMPLE_COUNT];
+
+// number of probes stored in probeIndex
+int probeInfluences = 0;
+
+bool isAbove(vec3 pos, vec4 plane)
+{
+ return (dot(plane.xyz, pos) + plane.w) > 0;
+}
+
+// return true if probe at index i influences position pos
+bool shouldSampleProbe(int i, vec3 pos)
+{
+ if (refIndex[i].w < 0)
+ {
+ vec4 v = refBox[i] * vec4(pos, 1.0);
+ if (abs(v.x) > 1 ||
+ abs(v.y) > 1 ||
+ abs(v.z) > 1)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ vec3 delta = pos.xyz - refSphere[i].xyz;
+ float d = dot(delta, delta);
+ float r2 = refSphere[i].w;
+ r2 *= r2;
+
+ if (d > r2)
+ { //outside bounding sphere
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// call before sampleRef
+// populate "probeIndex" with N probe indices that influence pos where N is REF_SAMPLE_COUNT
+// overall algorithm --
+void preProbeSample(vec3 pos)
+{
+ // TODO: make some sort of structure that reduces the number of distance checks
+
+ for (int i = 0; i < refmapCount; ++i)
+ {
+ // found an influencing probe
+ if (shouldSampleProbe(i, pos))
+ {
+ probeIndex[probeInfluences] = i;
+ ++probeInfluences;
+
+ int neighborIdx = refIndex[i].y;
+ if (neighborIdx != -1)
+ {
+ int neighborCount = min(refIndex[i].z, REF_SAMPLE_COUNT-1);
+
+ int count = 0;
+ while (count < neighborCount)
+ {
+ // check up to REF_SAMPLE_COUNT-1 neighbors (neighborIdx is ivec4 index)
+
+ int idx = refNeighbor[neighborIdx].x;
+ if (shouldSampleProbe(idx, pos))
+ {
+ probeIndex[probeInfluences++] = idx;
+ if (probeInfluences == REF_SAMPLE_COUNT)
+ {
+ return;
+ }
+ }
+ count++;
+ if (count == neighborCount)
+ {
+ return;
+ }
+
+ idx = refNeighbor[neighborIdx].y;
+ if (shouldSampleProbe(idx, pos))
+ {
+ probeIndex[probeInfluences++] = idx;
+ if (probeInfluences == REF_SAMPLE_COUNT)
+ {
+ return;
+ }
+ }
+ count++;
+ if (count == neighborCount)
+ {
+ return;
+ }
+
+ idx = refNeighbor[neighborIdx].z;
+ if (shouldSampleProbe(idx, pos))
+ {
+ probeIndex[probeInfluences++] = idx;
+ if (probeInfluences == REF_SAMPLE_COUNT)
+ {
+ return;
+ }
+ }
+ count++;
+ if (count == neighborCount)
+ {
+ return;
+ }
+
+ idx = refNeighbor[neighborIdx].w;
+ if (shouldSampleProbe(idx, pos))
+ {
+ probeIndex[probeInfluences++] = idx;
+ if (probeInfluences == REF_SAMPLE_COUNT)
+ {
+ return;
+ }
+ }
+ count++;
+ if (count == neighborCount)
+ {
+ return;
+ }
+
+ ++neighborIdx;
+ }
+
+ return;
+ }
+ }
+ }
+}
+
+// from https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection
+
+// original reference implementation:
+/*
+bool intersect(const Ray &ray) const
+{
+ float t0, t1; // solutions for t if the ray intersects
+#if 0
+ // geometric solution
+ Vec3f L = center - orig;
+ float tca = L.dotProduct(dir);
+ // if (tca < 0) return false;
+ float d2 = L.dotProduct(L) - tca * tca;
+ if (d2 > radius2) return false;
+ float thc = sqrt(radius2 - d2);
+ t0 = tca - thc;
+ t1 = tca + thc;
+#else
+ // analytic solution
+ Vec3f L = orig - center;
+ float a = dir.dotProduct(dir);
+ float b = 2 * dir.dotProduct(L);
+ float c = L.dotProduct(L) - radius2;
+ if (!solveQuadratic(a, b, c, t0, t1)) return false;
+#endif
+ if (t0 > t1) std::swap(t0, t1);
+
+ if (t0 < 0) {
+ t0 = t1; // if t0 is negative, let's use t1 instead
+ if (t0 < 0) return false; // both t0 and t1 are negative
+ }
+
+ t = t0;
+
+ return true;
+} */
+
+// adapted -- assume that origin is inside sphere, return distance from origin to edge of sphere
+vec3 sphereIntersect(vec3 origin, vec3 dir, vec3 center, float radius2)
+{
+ float t0, t1; // solutions for t if the ray intersects
+
+ vec3 L = center - origin;
+ float tca = dot(L,dir);
+
+ float d2 = dot(L,L) - tca * tca;
+
+ float thc = sqrt(radius2 - d2);
+ t0 = tca - thc;
+ t1 = tca + thc;
+
+ vec3 v = origin + dir * t1;
+ return v;
+}
+
+// from https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/
+/*
+vec3 DirectionWS = normalize(PositionWS - CameraWS);
+vec3 ReflDirectionWS = reflect(DirectionWS, NormalWS);
+
+// Intersection with OBB convertto unit box space
+// Transform in local unit parallax cube space (scaled and rotated)
+vec3 RayLS = MulMatrix( float(3x3)WorldToLocal, ReflDirectionWS);
+vec3 PositionLS = MulMatrix( WorldToLocal, PositionWS);
+
+vec3 Unitary = vec3(1.0f, 1.0f, 1.0f);
+vec3 FirstPlaneIntersect = (Unitary - PositionLS) / RayLS;
+vec3 SecondPlaneIntersect = (-Unitary - PositionLS) / RayLS;
+vec3 FurthestPlane = max(FirstPlaneIntersect, SecondPlaneIntersect);
+float Distance = min(FurthestPlane.x, min(FurthestPlane.y, FurthestPlane.z));
+
+// Use Distance in WS directly to recover intersection
+vec3 IntersectPositionWS = PositionWS + ReflDirectionWS * Distance;
+vec3 ReflDirectionWS = IntersectPositionWS - CubemapPositionWS;
+
+return texCUBE(envMap, ReflDirectionWS);
+*/
+
+// get point of intersection with given probe's box influence volume
+// origin - ray origin in clip space
+// dir - ray direction in clip space
+// i - probe index in refBox/refSphere
+vec3 boxIntersect(vec3 origin, vec3 dir, int i)
+{
+ // Intersection with OBB convertto unit box space
+ // Transform in local unit parallax cube space (scaled and rotated)
+ mat4 clipToLocal = refBox[i];
+
+ vec3 RayLS = mat3(clipToLocal) * dir;
+ vec3 PositionLS = (clipToLocal * vec4(origin, 1.0)).xyz;
+
+ vec3 Unitary = vec3(1.0f, 1.0f, 1.0f);
+ vec3 FirstPlaneIntersect = (Unitary - PositionLS) / RayLS;
+ vec3 SecondPlaneIntersect = (-Unitary - PositionLS) / RayLS;
+ vec3 FurthestPlane = max(FirstPlaneIntersect, SecondPlaneIntersect);
+ float Distance = min(FurthestPlane.x, min(FurthestPlane.y, FurthestPlane.z));
+
+ // Use Distance in CS directly to recover intersection
+ vec3 IntersectPositionCS = origin + dir * Distance;
+
+ return IntersectPositionCS;
+}
+
+
+
+// Tap a sphere based reflection probe
+// pos - position of pixel
+// dir - pixel normal
+// lod - which mip to bias towards (lower is higher res, sharper reflections)
+// c - center of probe
+// r2 - radius of probe squared
+// i - index of probe
+// vi - point at which reflection vector struck the influence volume, in clip space
+vec3 tapRefMap(vec3 pos, vec3 dir, float lod, vec3 c, float r2, int i)
+{
+ //lod = max(lod, 1);
+ // parallax adjustment
+
+ vec3 v;
+ if (refIndex[i].w < 0)
+ {
+ v = boxIntersect(pos, dir, i);
+ }
+ else
+ {
+ v = sphereIntersect(pos, dir, c, r2);
+ }
+
+ v -= c;
+ v = env_mat * v;
+ {
+ float min_lod = textureQueryLod(reflectionProbes,v).y; // lower is higher res
+ return textureLod(reflectionProbes, vec4(v.xyz, refIndex[i].x), max(min_lod, lod)).rgb;
+ //return texture(reflectionProbes, vec4(v.xyz, refIndex[i].x)).rgb;
+ }
+}
+
+vec3 sampleProbes(vec3 pos, vec3 dir, float lod)
+{
+ float wsum = 0.0;
+ vec3 col = vec3(0,0,0);
+ float vd2 = dot(pos,pos); // view distance squared
+
+ for (int idx = 0; idx < probeInfluences; ++idx)
+ {
+ int i = probeIndex[idx];
+ float r = refSphere[i].w; // radius of sphere volume
+ float p = float(abs(refIndex[i].w)); // priority
+ float rr = r*r; // radius squred
+ float r1 = r * 0.1; // 75% of radius (outer sphere to start interpolating down)
+ vec3 delta = pos.xyz-refSphere[i].xyz;
+ float d2 = dot(delta,delta);
+ float r2 = r1*r1;
+
+ {
+ vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, rr, i);
+
+ float w = 1.0/d2;
+
+ float atten = 1.0-max(d2-r2, 0.0)/(rr-r2);
+ w *= atten;
+ w *= p; // boost weight based on priority
+ col += refcol*w;
+
+ wsum += w;
+ }
+ }
+
+ if (probeInfluences <= 1)
+ { //edge-of-scene probe or no probe influence, mix in with embiggened version of probes closest to camera
+ for (int idx = 0; idx < 8; ++idx)
+ {
+ if (refIndex[idx].w < 0)
+ { // don't fallback to box probes, they are *very* specific
+ continue;
+ }
+ int i = idx;
+ vec3 delta = pos.xyz-refSphere[i].xyz;
+ float d2 = dot(delta,delta);
+
+ {
+ vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, d2, i);
+
+ float w = 1.0/d2;
+ w *= w;
+ col += refcol*w;
+ wsum += w;
+ }
+ }
+ }
+
+ if (wsum > 0.0)
+ {
+ col *= 1.0/wsum;
+ }
+
+ return col;
+}
+
+vec3 sampleProbeAmbient(vec3 pos, vec3 dir, float lod)
+{
+ vec3 col = sampleProbes(pos, dir, lod);
+
+ //desaturate
+ vec3 hcol = col *0.5;
+
+ col *= 2.0;
+ col = vec3(
+ col.r + hcol.g + hcol.b,
+ col.g + hcol.r + hcol.b,
+ col.b + hcol.r + hcol.g
+ );
+
+ col *= 0.333333;
+
+ return col*reflectionAmbiance;
+
+}
+
+// brighten a color so that at least one component is 1
+vec3 brighten(vec3 c)
+{
+ float m = max(max(c.r, c.g), c.b);
+
+ if (m == 0)
+ {
+ return vec3(1,1,1);
+ }
+
+ return c * 1.0/m;
+}
+
+
+void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
+ vec3 pos, vec3 norm, float glossiness, float envIntensity)
+{
+ // TODO - don't hard code lods
+ float reflection_lods = 8;
+ preProbeSample(pos);
+
+ vec3 refnormpersp = reflect(pos.xyz, norm.xyz);
+
+ ambenv = sampleProbeAmbient(pos, norm, reflection_lods-1);
+
+ if (glossiness > 0.0)
+ {
+ float lod = (1.0-glossiness)*reflection_lods;
+ glossenv = sampleProbes(pos, normalize(refnormpersp), lod);
+ }
+
+ if (envIntensity > 0.0)
+ {
+ legacyenv = sampleProbes(pos, normalize(refnormpersp), 0.0);
+ }
+}
+
+void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm)
+{
+ glossenv *= 0.35; // fudge darker
+ float fresnel = 1.0+dot(normalize(pos.xyz), norm.xyz);
+ float minf = spec.a * 0.1;
+ fresnel = fresnel * (1.0-minf) + minf;
+ glossenv *= spec.rgb*min(fresnel, 1.0);
+ color.rgb += glossenv;
+}
+
+ void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity)
+ {
+ vec3 reflected_color = legacyenv; //*0.5; //fudge darker
+ vec3 lookAt = normalize(pos);
+ float fresnel = 1.0+dot(lookAt, norm.xyz);
+ fresnel *= fresnel;
+ fresnel = min(fresnel+envIntensity, 1.0);
+ reflected_color *= (envIntensity*fresnel)*brighten(spec.rgb);
+ color = mix(color.rgb, reflected_color, envIntensity);
+ } \ No newline at end of file
diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
index d6b173b89d..d88400dddb 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
@@ -42,38 +42,8 @@ uniform sampler2DRect specularRect;
uniform sampler2DRect normalMap;
uniform sampler2DRect lightMap;
uniform sampler2DRect depthMap;
-uniform samplerCube environmentMap;
-uniform samplerCubeArray reflectionProbes;
uniform sampler2D lightFunc;
-layout (std140, binding = 1) uniform ReflectionProbes
-{
- // list of OBBs for user override probes
- // box is a set of 3 planes outward facing planes and the depth of the box along that plane
- // for each box refBox[i]...
- /// box[0..2] - plane 0 .. 2 in [A,B,C,D] notation
- // box[3][0..2] - plane thickness
- mat4 refBox[REFMAP_COUNT];
- // list of bounding spheres for reflection probes sorted by distance to camera (closest first)
- vec4 refSphere[REFMAP_COUNT];
- // index of cube map in reflectionProbes for a corresponding reflection probe
- // e.g. cube map channel of refSphere[2] is stored in refIndex[2]
- // refIndex.x - cubemap channel in reflectionProbes
- // refIndex.y - index in refNeighbor of neighbor list (index is ivec4 index, not int index)
- // refIndex.z - number of neighbors
- // refIndex.w - priority, if negative, this probe has a box influence
- ivec4 refIndex[REFMAP_COUNT];
-
- // neighbor list data (refSphere indices, not cubemap array layer)
- ivec4 refNeighbor[1024];
-
- // number of reflection probes present in refSphere
- int refmapCount;
-
- // intensity of ambient light from reflection probes
- float reflectionAmbiance;
-};
-
uniform float blur_size;
uniform float blur_fidelity;
@@ -98,6 +68,12 @@ vec3 scaleSoftClipFrag(vec3 l);
vec3 fullbrightAtmosTransportFrag(vec3 light, vec3 additive, vec3 atten);
vec3 fullbrightScaleSoftClip(vec3 light);
+// reflection probe interface
+void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyEnv,
+ vec3 pos, vec3 norm, float glossiness, float envIntensity);
+void applyGlossEnv(inout vec3 color, vec3 glossenv, vec4 spec, vec3 pos, vec3 norm);
+void applyLegacyEnv(inout vec3 color, vec3 legacyenv, vec4 spec, vec3 pos, vec3 norm, float envIntensity);
+
vec3 linear_to_srgb(vec3 c);
vec3 srgb_to_linear(vec3 c);
@@ -105,376 +81,8 @@ vec3 srgb_to_linear(vec3 c);
vec4 applyWaterFogView(vec3 pos, vec4 color);
#endif
-// list of probeIndexes shader will actually use after "getRefIndex" is called
-// (stores refIndex/refSphere indices, NOT rerflectionProbes layer)
-int probeIndex[REF_SAMPLE_COUNT];
-
-// number of probes stored in probeIndex
-int probeInfluences = 0;
-
-bool isAbove(vec3 pos, vec4 plane)
-{
- return (dot(plane.xyz, pos) + plane.w) > 0;
-}
-
-// return true if probe at index i influences position pos
-bool shouldSampleProbe(int i, vec3 pos)
-{
- if (refIndex[i].w < 0)
- {
- vec4 v = refBox[i] * vec4(pos, 1.0);
- if (abs(v.x) > 1 ||
- abs(v.y) > 1 ||
- abs(v.z) > 1)
- {
- return false;
- }
- }
- else
- {
- vec3 delta = pos.xyz - refSphere[i].xyz;
- float d = dot(delta, delta);
- float r2 = refSphere[i].w;
- r2 *= r2;
-
- if (d > r2)
- { //outside bounding sphere
- return false;
- }
- }
-
- return true;
-}
-
-// populate "probeIndex" with N probe indices that influence pos where N is REF_SAMPLE_COUNT
-// overall algorithm --
-void getRefIndex(vec3 pos)
-{
- // TODO: make some sort of structure that reduces the number of distance checks
-
- for (int i = 0; i < refmapCount; ++i)
- {
- // found an influencing probe
- if (shouldSampleProbe(i, pos))
- {
- probeIndex[probeInfluences] = i;
- ++probeInfluences;
-
- int neighborIdx = refIndex[i].y;
- if (neighborIdx != -1)
- {
- int neighborCount = min(refIndex[i].z, REF_SAMPLE_COUNT-1);
-
- int count = 0;
- while (count < neighborCount)
- {
- // check up to REF_SAMPLE_COUNT-1 neighbors (neighborIdx is ivec4 index)
-
- int idx = refNeighbor[neighborIdx].x;
- if (shouldSampleProbe(idx, pos))
- {
- probeIndex[probeInfluences++] = idx;
- if (probeInfluences == REF_SAMPLE_COUNT)
- {
- return;
- }
- }
- count++;
- if (count == neighborCount)
- {
- return;
- }
-
- idx = refNeighbor[neighborIdx].y;
- if (shouldSampleProbe(idx, pos))
- {
- probeIndex[probeInfluences++] = idx;
- if (probeInfluences == REF_SAMPLE_COUNT)
- {
- return;
- }
- }
- count++;
- if (count == neighborCount)
- {
- return;
- }
-
- idx = refNeighbor[neighborIdx].z;
- if (shouldSampleProbe(idx, pos))
- {
- probeIndex[probeInfluences++] = idx;
- if (probeInfluences == REF_SAMPLE_COUNT)
- {
- return;
- }
- }
- count++;
- if (count == neighborCount)
- {
- return;
- }
-
- idx = refNeighbor[neighborIdx].w;
- if (shouldSampleProbe(idx, pos))
- {
- probeIndex[probeInfluences++] = idx;
- if (probeInfluences == REF_SAMPLE_COUNT)
- {
- return;
- }
- }
- count++;
- if (count == neighborCount)
- {
- return;
- }
-
- ++neighborIdx;
- }
-
- return;
- }
- }
- }
-}
-
-// from https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection
-
-// original reference implementation:
-/*
-bool intersect(const Ray &ray) const
-{
- float t0, t1; // solutions for t if the ray intersects
-#if 0
- // geometric solution
- Vec3f L = center - orig;
- float tca = L.dotProduct(dir);
- // if (tca < 0) return false;
- float d2 = L.dotProduct(L) - tca * tca;
- if (d2 > radius2) return false;
- float thc = sqrt(radius2 - d2);
- t0 = tca - thc;
- t1 = tca + thc;
-#else
- // analytic solution
- Vec3f L = orig - center;
- float a = dir.dotProduct(dir);
- float b = 2 * dir.dotProduct(L);
- float c = L.dotProduct(L) - radius2;
- if (!solveQuadratic(a, b, c, t0, t1)) return false;
-#endif
- if (t0 > t1) std::swap(t0, t1);
-
- if (t0 < 0) {
- t0 = t1; // if t0 is negative, let's use t1 instead
- if (t0 < 0) return false; // both t0 and t1 are negative
- }
-
- t = t0;
-
- return true;
-} */
-
-// adapted -- assume that origin is inside sphere, return distance from origin to edge of sphere
-vec3 sphereIntersect(vec3 origin, vec3 dir, vec3 center, float radius2)
-{
- float t0, t1; // solutions for t if the ray intersects
-
- vec3 L = center - origin;
- float tca = dot(L,dir);
-
- float d2 = dot(L,L) - tca * tca;
-
- float thc = sqrt(radius2 - d2);
- t0 = tca - thc;
- t1 = tca + thc;
-
- vec3 v = origin + dir * t1;
- return v;
-}
-
-// from https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/
-/*
-vec3 DirectionWS = normalize(PositionWS - CameraWS);
-vec3 ReflDirectionWS = reflect(DirectionWS, NormalWS);
-
-// Intersection with OBB convertto unit box space
-// Transform in local unit parallax cube space (scaled and rotated)
-vec3 RayLS = MulMatrix( float(3x3)WorldToLocal, ReflDirectionWS);
-vec3 PositionLS = MulMatrix( WorldToLocal, PositionWS);
-
-vec3 Unitary = vec3(1.0f, 1.0f, 1.0f);
-vec3 FirstPlaneIntersect = (Unitary - PositionLS) / RayLS;
-vec3 SecondPlaneIntersect = (-Unitary - PositionLS) / RayLS;
-vec3 FurthestPlane = max(FirstPlaneIntersect, SecondPlaneIntersect);
-float Distance = min(FurthestPlane.x, min(FurthestPlane.y, FurthestPlane.z));
-
-// Use Distance in WS directly to recover intersection
-vec3 IntersectPositionWS = PositionWS + ReflDirectionWS * Distance;
-vec3 ReflDirectionWS = IntersectPositionWS - CubemapPositionWS;
-
-return texCUBE(envMap, ReflDirectionWS);
-*/
-
-// get point of intersection with given probe's box influence volume
-// origin - ray origin in clip space
-// dir - ray direction in clip space
-// i - probe index in refBox/refSphere
-vec3 boxIntersect(vec3 origin, vec3 dir, int i)
-{
- // Intersection with OBB convertto unit box space
- // Transform in local unit parallax cube space (scaled and rotated)
- mat4 clipToLocal = refBox[i];
-
- vec3 RayLS = mat3(clipToLocal) * dir;
- vec3 PositionLS = (clipToLocal * vec4(origin, 1.0)).xyz;
-
- vec3 Unitary = vec3(1.0f, 1.0f, 1.0f);
- vec3 FirstPlaneIntersect = (Unitary - PositionLS) / RayLS;
- vec3 SecondPlaneIntersect = (-Unitary - PositionLS) / RayLS;
- vec3 FurthestPlane = max(FirstPlaneIntersect, SecondPlaneIntersect);
- float Distance = min(FurthestPlane.x, min(FurthestPlane.y, FurthestPlane.z));
-
- // Use Distance in CS directly to recover intersection
- vec3 IntersectPositionCS = origin + dir * Distance;
-
- return IntersectPositionCS;
-}
-
-
-
-// Tap a sphere based reflection probe
-// pos - position of pixel
-// dir - pixel normal
-// lod - which mip to bias towards (lower is higher res, sharper reflections)
-// c - center of probe
-// r2 - radius of probe squared
-// i - index of probe
-// vi - point at which reflection vector struck the influence volume, in clip space
-vec3 tapRefMap(vec3 pos, vec3 dir, float lod, vec3 c, float r2, int i)
-{
- //lod = max(lod, 1);
- // parallax adjustment
-
- vec3 v;
- if (refIndex[i].w < 0)
- {
- v = boxIntersect(pos, dir, i);
- }
- else
- {
- v = sphereIntersect(pos, dir, c, r2);
- }
-
- v -= c;
- v = env_mat * v;
- {
- float min_lod = textureQueryLod(reflectionProbes,v).y; // lower is higher res
- return textureLod(reflectionProbes, vec4(v.xyz, refIndex[i].x), max(min_lod, lod)).rgb;
- //return texture(reflectionProbes, vec4(v.xyz, refIndex[i].x)).rgb;
- }
-}
-
-vec3 sampleRefMap(vec3 pos, vec3 dir, float lod)
-{
- float wsum = 0.0;
- vec3 col = vec3(0,0,0);
- float vd2 = dot(pos,pos); // view distance squared
-
- for (int idx = 0; idx < probeInfluences; ++idx)
- {
- int i = probeIndex[idx];
- float r = refSphere[i].w; // radius of sphere volume
- float p = float(abs(refIndex[i].w)); // priority
- float rr = r*r; // radius squred
- float r1 = r * 0.1; // 75% of radius (outer sphere to start interpolating down)
- vec3 delta = pos.xyz-refSphere[i].xyz;
- float d2 = dot(delta,delta);
- float r2 = r1*r1;
-
- {
- vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, rr, i);
-
- float w = 1.0/d2;
-
- float atten = 1.0-max(d2-r2, 0.0)/(rr-r2);
- w *= atten;
- w *= p; // boost weight based on priority
- col += refcol*w;
-
- wsum += w;
- }
- }
-
- if (probeInfluences <= 1)
- { //edge-of-scene probe or no probe influence, mix in with embiggened version of probes closest to camera
- for (int idx = 0; idx < 8; ++idx)
- {
- if (refIndex[idx].w < 0)
- { // don't fallback to box probes, they are *very* specific
- continue;
- }
- int i = idx;
- vec3 delta = pos.xyz-refSphere[i].xyz;
- float d2 = dot(delta,delta);
-
- {
- vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, d2, i);
-
- float w = 1.0/d2;
- w *= w;
- col += refcol*w;
- wsum += w;
- }
- }
- }
-
- if (wsum > 0.0)
- {
- col *= 1.0/wsum;
- }
-
- return col;
-}
-
-vec3 sampleAmbient(vec3 pos, vec3 dir, float lod)
-{
- vec3 col = sampleRefMap(pos, dir, lod);
-
- //desaturate
- vec3 hcol = col *0.5;
-
- col *= 2.0;
- col = vec3(
- col.r + hcol.g + hcol.b,
- col.g + hcol.r + hcol.b,
- col.b + hcol.r + hcol.g
- );
-
- col *= 0.333333;
-
- return col*reflectionAmbiance;
-
-}
-
-// brighten a color so that at least one component is 1
-vec3 brighten(vec3 c)
-{
- float m = max(max(c.r, c.g), c.b);
-
- if (m == 0)
- {
- return vec3(1,1,1);
- }
-
- return c * 1.0/m;
-}
-
void main()
{
- float reflection_lods = 8; // TODO -- base this on resolution of reflection map instead of hard coding
-
vec2 tc = vary_fragcoord.xy;
float depth = texture2DRect(depthMap, tc.xy).r;
vec4 pos = getPositionWithDepth(tc, depth);
@@ -504,13 +112,15 @@ void main()
vec3 additive;
vec3 atten;
- getRefIndex(pos.xyz);
-
calcAtmosphericVars(pos.xyz, light_dir, ambocc, sunlit, amblit, additive, atten, true);
//vec3 amb_vec = env_mat * norm.xyz;
- vec3 ambenv = sampleAmbient(pos.xyz, norm.xyz, reflection_lods-1);
+ vec3 ambenv;
+ vec3 glossenv;
+ vec3 legacyenv;
+ sampleReflectionProbes(ambenv, glossenv, legacyenv, pos.xyz, norm.xyz, spec.a, envIntensity);
+
amblit = max(ambenv, amblit);
color.rgb = amblit*ambocc;
@@ -527,7 +137,6 @@ void main()
vec3 refnormpersp = reflect(pos.xyz, norm.xyz);
- vec3 env_vec = env_mat * refnormpersp;
if (spec.a > 0.0) // specular reflection
{
float sa = dot(normalize(refnormpersp), light_dir.xyz);
@@ -539,27 +148,16 @@ void main()
color.rgb += spec_contrib;
// add reflection map - EXPERIMENTAL WORK IN PROGRESS
-
- float lod = (1.0-spec.a)*reflection_lods;
- vec3 reflected_color = sampleRefMap(pos.xyz, normalize(refnormpersp), lod);
- reflected_color *= 0.35; // fudge darker
- float fresnel = 1.0+dot(normalize(pos.xyz), norm.xyz);
- float minf = spec.a * 0.1;
- fresnel = fresnel * (1.0-minf) + minf;
- reflected_color *= spec.rgb*min(fresnel, 1.0);
- color.rgb += reflected_color;
+ applyGlossEnv(color, glossenv, spec, pos.xyz, norm.xyz);
}
color.rgb = mix(color.rgb, diffuse.rgb, diffuse.a);
if (envIntensity > 0.0)
{ // add environmentmap
- vec3 reflected_color = sampleRefMap(pos.xyz, normalize(refnormpersp), 0.0)*0.5; //fudge darker
- float fresnel = 1.0+dot(normalize(pos.xyz), norm.xyz);
- fresnel *= fresnel;
- fresnel = min(fresnel+envIntensity, 1.0);
- reflected_color *= (envIntensity*fresnel)*brighten(spec.rgb);
- color = mix(color.rgb, reflected_color, envIntensity);
+ //fudge darker
+ legacyenv *= 0.5*diffuse.a+0.5;;
+ applyLegacyEnv(color, legacyenv, spec, pos.xyz, norm.xyz, envIntensity);
}
if (norm.w < 0.5)
@@ -577,6 +175,8 @@ void main()
// convert to linear as fullscreen lights need to sum in linear colorspace
// and will be gamma (re)corrected downstream...
//color = vec3(ambocc);
- //color = ambenv;
+ //color = ambenv;
+ //color.b = diffuse.a;
frag_color.rgb = srgb_to_linear(color.rgb);
+ frag_color.a = bloom;
}
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 0df0137b7a..3fe3896aa2 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -460,6 +460,11 @@ void LLDrawPoolBump::beginFullbrightShiny()
LLVector4 vec4(vec, gShinyOrigin.mV[3]);
shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV);
+ if (shader->mFeatures.hasReflectionProbes)
+ {
+ gPipeline.bindReflectionProbes(*shader);
+ }
+
// Make sure that texture coord generation happens for tex unit 1, as that's the one we use for
// the cube map in the one pass shiny shaders
gGL.getTexUnit(1)->disable();
@@ -520,6 +525,10 @@ void LLDrawPoolBump::endFullbrightShiny()
if( cube_map )
{
cube_map->disable();
+ if (shader->mFeatures.hasReflectionProbes)
+ {
+ gPipeline.unbindReflectionProbes(*shader);
+ }
shader->unbind();
}
diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp
index 8aacbba6be..5fe510fb56 100644
--- a/indra/newview/llreflectionmapmanager.cpp
+++ b/indra/newview/llreflectionmapmanager.cpp
@@ -506,6 +506,8 @@ void LLReflectionMapManager::setUniforms()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
+ // TODO -- avoid repacking UBO unnecessarily
+
// structure for packing uniform buffer object
// see class2/deferred/softenLightF.glsl
struct ReflectionProbeData
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 10577b1804..875f585310 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -977,6 +977,7 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/deferredUtil.glsl", 1) );
index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/shadowUtil.glsl", 1) );
index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/aoUtil.glsl", 1) );
+ index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/reflectionProbeF.glsl", llmax(mShaderLevel[SHADER_DEFERRED], 1)) );
index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) );
index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightAlphaMaskNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) );
index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightFullbrightNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) );
@@ -1503,6 +1504,12 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
gDeferredMaterialProgram[i].mFeatures.hasGamma = true;
gDeferredMaterialProgram[i].mFeatures.hasShadows = use_sun_shadow;
+ if (mShaderLevel[SHADER_DEFERRED] > 1)
+ {
+ gDeferredMaterialProgram[i].mFeatures.hasReflectionProbes = true;
+ gDeferredMaterialProgram[i].addPermutation("HAS_REFLECTION_PROBES", "1");
+ }
+
if (has_skin)
{
gDeferredMaterialProgram[i].addPermutation("HAS_SKIN", "1");
@@ -2202,6 +2209,11 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
gDeferredFullbrightShinyProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB));
gDeferredFullbrightShinyProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
gDeferredFullbrightShinyProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
+ if (gDeferredFullbrightShinyProgram.mShaderLevel >= 2) // TODO : make this a 3 when reflection probes are restricted to class 3
+ {
+ gDeferredFullbrightShinyProgram.addPermutation("HAS_REFLECTION_PROBES", "1");
+ gDeferredFullbrightShinyProgram.mFeatures.hasReflectionProbes = true;
+ }
success = make_rigged_variant(gDeferredFullbrightShinyProgram, gDeferredSkinnedFullbrightShinyProgram);
success = success && gDeferredFullbrightShinyProgram.createShader(NULL, NULL);
llassert(success);
@@ -2274,6 +2286,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
gDeferredSoftenProgram.mFeatures.hasGamma = true;
gDeferredSoftenProgram.mFeatures.isDeferred = true;
gDeferredSoftenProgram.mFeatures.hasShadows = use_sun_shadow;
+ gDeferredSoftenProgram.mFeatures.hasReflectionProbes = true;
gDeferredSoftenProgram.clearPermutations();
gDeferredSoftenProgram.mShaderFiles.push_back(make_pair("deferred/softenLightV.glsl", GL_VERTEX_SHADER_ARB));
@@ -2324,6 +2337,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
gDeferredSoftenWaterProgram.mFeatures.hasGamma = true;
gDeferredSoftenWaterProgram.mFeatures.isDeferred = true;
gDeferredSoftenWaterProgram.mFeatures.hasShadows = use_sun_shadow;
+ gDeferredSoftenWaterProgram.mFeatures.hasReflectionProbes = true;
if (ambient_kill)
{
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 4cf8157623..b4b70a3e11 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -8208,30 +8208,16 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_
stop_glerror();
- bool setup_env_mat = false;
channel = shader.enableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
if (channel > -1)
{
LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
if (cube_map)
{
- setup_env_mat = true;
cube_map->enable(channel);
cube_map->bind();
}
- }
- channel = shader.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY);
- if (channel > -1 && mReflectionMapManager.mTexture.notNull())
- {
- // see comments in class2/deferred/softenLightF.glsl for what these uniforms mean
- mReflectionMapManager.mTexture->bind(channel);
- mReflectionMapManager.setUniforms();
- setup_env_mat = true;
- }
-
- if (setup_env_mat)
- {
F32* m = gGLModelView;
F32 mat[] = { m[0], m[1], m[2],
@@ -8239,8 +8225,10 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_
m[8], m[9], m[10] };
shader.uniformMatrix3fv(LLShaderMgr::DEFERRED_ENV_MAT, 1, TRUE, mat);
- }
+ }
+ bindReflectionProbes(shader);
+
if (gAtmosphere)
{
// bind precomputed textures necessary for calculating sun and sky luminance
@@ -9163,7 +9151,35 @@ void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
}
}
- channel = shader.disableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP);
+ unbindReflectionProbes(shader);
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.getTexUnit(0)->activate();
+ shader.unbind();
+}
+
+void LLPipeline::bindReflectionProbes(LLGLSLShader& shader)
+{
+ S32 channel = shader.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY);
+ if (channel > -1 && mReflectionMapManager.mTexture.notNull())
+ {
+ // see comments in class2/deferred/softenLightF.glsl for what these uniforms mean
+ mReflectionMapManager.mTexture->bind(channel);
+ mReflectionMapManager.setUniforms();
+
+ F32* m = gGLModelView;
+
+ F32 mat[] = { m[0], m[1], m[2],
+ m[4], m[5], m[6],
+ m[8], m[9], m[10] };
+
+ shader.uniformMatrix3fv(LLShaderMgr::DEFERRED_ENV_MAT, 1, TRUE, mat);
+ }
+}
+
+void LLPipeline::unbindReflectionProbes(LLGLSLShader& shader)
+{
+ S32 channel = shader.disableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP);
if (channel > -1 && mReflectionMapManager.mTexture.notNull())
{
mReflectionMapManager.mTexture->unbind();
@@ -9172,12 +9188,9 @@ void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
gGL.getTexUnit(channel)->enable(LLTexUnit::TT_TEXTURE);
}
}
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.getTexUnit(0)->activate();
- shader.unbind();
}
+
inline float sgn(float a)
{
if (a > 0.0F) return (1.0F);
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 88eaca558a..5cbd1eb550 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -294,6 +294,10 @@ public:
void setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep);
void unbindDeferredShader(LLGLSLShader& shader);
+
+ void bindReflectionProbes(LLGLSLShader& shader);
+ void unbindReflectionProbes(LLGLSLShader& shader);
+
void renderDeferredLighting(LLRenderTarget* light_target);
void postDeferredGammaCorrect(LLRenderTarget* screen_target);