summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorDave Parks <davep@lindenlab.com>2023-02-17 10:34:27 -0600
committerDave Parks <davep@lindenlab.com>2023-02-17 10:34:27 -0600
commit50c57b6be72541b92340c6230d417c508a4fa6f9 (patch)
tree45ed7a7885abcccc9df34e3a3c0f3d00ef11081d /indra
parent74275f590e75fc8b1685b77a39529cc91ad084b9 (diff)
SL-19128 Soften the transition between manual and automatic sphere probes.
Diffstat (limited to 'indra')
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl174
-rw-r--r--indra/newview/app_settings/shaders/class3/environment/waterF.glsl4
-rw-r--r--indra/newview/llreflectionmap.cpp4
-rw-r--r--indra/newview/llreflectionmap.h5
4 files changed, 122 insertions, 65 deletions
diff --git a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl
index 8b1d41776f..24539c3c3a 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl
@@ -80,7 +80,7 @@ bool isAbove(vec3 pos, vec4 plane)
return (dot(plane.xyz, pos) + plane.w) > 0;
}
-int max_priority = 0;
+bool sample_automatic = true;
// return true if probe at index i influences position pos
bool shouldSampleProbe(int i, vec3 pos)
@@ -95,24 +95,24 @@ bool shouldSampleProbe(int i, vec3 pos)
return false;
}
- max_priority = max(max_priority, -refIndex[i].w);
+ sample_automatic = false;
}
else
{
- if (refSphere[i].w > 0.0) // zero is special indicator to always sample this probe
+ if (refIndex[i].w == 0 && !sample_automatic)
{
- 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 false;
}
- max_priority = max(max_priority, refIndex[i].w);
+ 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;
@@ -120,7 +120,6 @@ bool shouldSampleProbe(int i, vec3 pos)
// 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
@@ -210,7 +209,7 @@ void preProbeSample(vec3 pos)
}
}
- if (max_priority <= 1)
+ if (sample_automatic)
{ // probe at index 0 is a special probe for smoothing out automatic probes
probeIndex[probeInfluences++] = 0;
}
@@ -342,7 +341,7 @@ return texCUBE(envMap, ReflDirectionWS);
// d - distance to nearest wall in clip space
vec3 boxIntersect(vec3 origin, vec3 dir, int i, out float d)
{
- // Intersection with OBB convertto unit box space
+ // Intersection with OBB convert to unit box space
// Transform in local unit parallax cube space (scaled and rotated)
mat4 clipToLocal = refBox[i];
@@ -431,18 +430,24 @@ void boxIntersectDebug(vec3 origin, vec3 pos, int i, inout vec4 col)
// origin - center of sphere probe
// r - radius of probe influence volume
// min_da - minimum angular attenuation coefficient
-float sphereWeight(vec3 pos, vec3 dir, vec3 origin, float r, float min_da)
+// i - index of probe in refSphere
+// dw - distance weight
+float sphereWeight(vec3 pos, vec3 dir, vec3 origin, float r, float min_da, int i, out float dw)
{
float r1 = r * 0.5; // 50% of radius (outer sphere to start interpolating down)
vec3 delta = pos.xyz - origin;
float d2 = max(length(delta), 0.001);
+
float r2 = r1; //r1 * r1;
//float atten = 1.0 - max(d2 - r2, 0.0) / max((rr - r2), 0.001);
float atten = 1.0 - max(d2 - r2, 0.0) / max((r - r2), 0.001);
+ float w = 1.0 / d2;
+
+ dw = w * atten * max(r, 1.0)*4;
atten *= max(dot(normalize(-delta), dir), min_da);
- float w = 1.0 / d2;
+
w *= atten;
return w;
@@ -451,13 +456,15 @@ float sphereWeight(vec3 pos, vec3 dir, vec3 origin, float r, float min_da)
// Tap a reflection probe
// pos - position of pixel
// dir - pixel normal
+// w - weight of sample (distance and angular attenuation)
+// dw - weight of sample (distance only)
// vi - return value of intersection point with influence volume
// wi - return value of approximate world space position of sampled pixel
// 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
-vec3 tapRefMap(vec3 pos, vec3 dir, out float w, out vec3 vi, out vec3 wi, float lod, vec3 c, int i)
+vec3 tapRefMap(vec3 pos, vec3 dir, out float w, out float dw, out vec3 vi, out vec3 wi, float lod, vec3 c, int i)
{
//lod = max(lod, 1);
// parallax adjustment
@@ -473,14 +480,15 @@ vec3 tapRefMap(vec3 pos, vec3 dir, out float w, out vec3 vi, out vec3 wi, float
}
else
{
- float r = refSphere[i].w; // radius of sphere volume
- float rr = r * r; // radius squared
+ float r = refSphere[i].w;
+
+ float rr = r * r;
v = sphereIntersect(pos, dir, c,
- refIndex[i].w <= 1 ? 4096.0*4096.0 : // <== effectively disable parallax correction for automatically placed probes to keep from bombing the world with obvious spheres
+ refIndex[i].w < 1 ? 4096.0*4096.0 : // <== effectively disable parallax correction for automatically placed probes to keep from bombing the world with obvious spheres
rr);
- w = sphereWeight(pos, dir, refSphere[i].xyz, r, 0.25);
+ w = sphereWeight(pos, dir, refSphere[i].xyz, r, 0.25, i, dw);
}
vi = v;
@@ -500,10 +508,10 @@ vec3 tapRefMap(vec3 pos, vec3 dir, out float w, out vec3 vi, out vec3 wi, float
// Tap an irradiance map
// pos - position of pixel
// dir - pixel normal
-// c - center of probe
-// r2 - radius of probe squared
+// w - weight of sample (distance and angular attenuation)
+// dw - weight of sample (distance only)
// i - index of probe
-vec3 tapIrradianceMap(vec3 pos, vec3 dir, out float w, vec3 c, int i)
+vec3 tapIrradianceMap(vec3 pos, vec3 dir, out float w, out float dw, vec3 c, int i)
{
// parallax adjustment
vec3 v;
@@ -516,14 +524,15 @@ vec3 tapIrradianceMap(vec3 pos, vec3 dir, out float w, vec3 c, int i)
else
{
float r = refSphere[i].w; // radius of sphere volume
- float p = float(abs(refIndex[i].w)); // priority
- float rr = r * r; // radius squred
+
+ // pad sphere for manual probe extending into automatic probe space
+ float rr = r * r;
v = sphereIntersect(pos, dir, c,
- refIndex[i].w <= 1 ? 4096.0*4096.0 : // <== effectively disable parallax correction for automatically placed probes to keep from bombing the world with obvious spheres
+ refIndex[i].w < 1 ? 4096.0*4096.0 : // <== effectively disable parallax correction for automatically placed probes to keep from bombing the world with obvious spheres
rr);
- w = sphereWeight(pos, dir, refSphere[i].xyz, r, 0.001);
+ w = sphereWeight(pos, dir, refSphere[i].xyz, r, 0.001, i, dw);
}
v -= c;
@@ -535,19 +544,30 @@ vec3 tapIrradianceMap(vec3 pos, vec3 dir, out float w, vec3 c, int i)
vec3 sampleProbes(vec3 pos, vec3 dir, float lod, bool errorCorrect)
{
- float wsum = 0.0;
- vec3 col = vec3(0,0,0);
- float vd2 = dot(pos,pos); // view distance squared
+ float wsum[2];
+ wsum[0] = 0;
+ wsum[1] = 0;
+
+ float dwsum[2];
+ dwsum[0] = 0;
+ dwsum[1] = 0;
+
+ vec3 col[2];
+ col[0] = vec3(0);
+ col[1] = vec3(0);
for (int idx = 0; idx < probeInfluences; ++idx)
{
int i = probeIndex[idx];
- if (abs(refIndex[i].w) < max_priority)
+ int p = clamp(abs(refIndex[i].w), 0, 1);
+
+ if (p == 0 && !sample_automatic)
{
continue;
}
- float w;
+ float w = 0;
+ float dw = 0;
vec3 vi, wi;
vec3 refcol;
@@ -556,7 +576,7 @@ vec3 sampleProbes(vec3 pos, vec3 dir, float lod, bool errorCorrect)
if (errorCorrect && refIndex[i].w >= 0)
{ // error correction is on and this probe is a sphere
//take a sample to get depth value, then error correct
- refcol = tapRefMap(pos, dir, w, vi, wi, abs(lod + 2), refSphere[i].xyz, i);
+ refcol = tapRefMap(pos, dir, w, dw, vi, wi, abs(lod + 2), refSphere[i].xyz, i);
//adjust lookup by distance result
float d = length(vi - wi);
@@ -571,61 +591,96 @@ vec3 sampleProbes(vec3 pos, vec3 dir, float lod, bool errorCorrect)
// weight by vector correctness
vec3 pi = normalize(wi - pos);
w *= max(dot(pi, dir), 0.1);
- //w = pow(w, 32.0);
}
else
{
- refcol = tapRefMap(pos, dir, w, vi, wi, lod, refSphere[i].xyz, i);
+ refcol = tapRefMap(pos, dir, w, dw, vi, wi, lod, refSphere[i].xyz, i);
}
- col += refcol.rgb*w;
-
- wsum += w;
+ col[p] += refcol.rgb*w;
+ wsum[p] += w;
+ dwsum[p] += dw;
}
}
- if (wsum > 0.0)
+ // mix automatic and manual probes
+ if (sample_automatic && wsum[0] > 0.0)
+ { // some automatic probes were sampled
+ col[0] *= 1.0/wsum[0];
+ if (wsum[1] > 0.0)
+ { //some manual probes were sampled, mix between the two
+ col[1] *= 1.0/wsum[1];
+ col[1] = mix(col[0], col[1], min(dwsum[1], 1.0));
+ col[0] = vec3(0);
+ }
+ }
+ else if (wsum[1] > 0.0)
{
- col *= 1.0/wsum;
+ // manual probes were sampled but no automatic probes were
+ col[1] *= 1.0/wsum[1];
+ col[0] = vec3(0);
}
- return col;
+ return col[1]+col[0];
}
vec3 sampleProbeAmbient(vec3 pos, vec3 dir)
{
// modified copy/paste of sampleProbes follows, will likely diverge from sampleProbes further
// as irradiance map mixing is tuned independently of radiance map mixing
- float wsum = 0.0;
- vec3 col = vec3(0,0,0);
- float vd2 = dot(pos,pos); // view distance squared
+ float wsum[2];
+ wsum[0] = 0;
+ wsum[1] = 0;
- float minweight = 1.0;
+ float dwsum[2];
+ dwsum[0] = 0;
+ dwsum[1] = 0;
+
+ vec3 col[2];
+ col[0] = vec3(0);
+ col[1] = vec3(0);
for (int idx = 0; idx < probeInfluences; ++idx)
{
int i = probeIndex[idx];
- if (abs(refIndex[i].w) < max_priority)
+ int p = clamp(abs(refIndex[i].w), 0, 1);
+
+ if (p == 0 && !sample_automatic)
{
continue;
}
{
- float w;
- vec3 refcol = tapIrradianceMap(pos, dir, w, refSphere[i].xyz, i);
+ float w = 0;
+ float dw = 0;
- col += refcol*w;
-
- wsum += w;
+ vec3 refcol = tapIrradianceMap(pos, dir, w, dw, refSphere[i].xyz, i);
+
+ col[p] += refcol*w;
+ wsum[p] += w;
+ dwsum[p] += dw;
}
}
- if (wsum > 0.0)
+ // mix automatic and manual probes
+ if (sample_automatic && wsum[0] > 0.0)
+ { // some automatic probes were sampled
+ col[0] *= 1.0/wsum[0];
+ if (wsum[1] > 0.0)
+ { //some manual probes were sampled, mix between the two
+ col[1] *= 1.0/wsum[1];
+ col[1] = mix(col[0], col[1], min(dwsum[1], 1.0));
+ col[0] = vec3(0);
+ }
+ }
+ else if (wsum[1] > 0.0)
{
- col *= 1.0/wsum;
+ // manual probes were sampled but no automatic probes were
+ col[1] *= 1.0/wsum[1];
+ col[0] = vec3(0);
}
-
- return col;
+
+ return col[1]+col[0];
}
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
@@ -658,7 +713,7 @@ void debugTapRefMap(vec3 pos, vec3 dir, float depth, int i, inout vec4 col)
{
vec3 origin = vec3(0,0,0);
- bool manual_probe = abs(refIndex[i].w) > 2;
+ bool manual_probe = abs(refIndex[i].w) > 0;
if (manual_probe)
{
@@ -705,7 +760,6 @@ void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity)
{
- // TODO - don't hard code lods
float reflection_lods = max_probe_lod;
preProbeSample(pos);
diff --git a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl
index 3d721cd048..631d2c04d0 100644
--- a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl
+++ b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl
@@ -232,8 +232,8 @@ void main()
irradiance = vec3(0);
- vec3 diffuseColor;
- vec3 specularColor;
+ vec3 diffuseColor = vec3(0);
+ vec3 specularColor = vec3(0);
calcDiffuseSpecular(vec3(1), metallic, diffuseColor, specularColor);
vec3 v = -normalize(pos.xyz);
diff --git a/indra/newview/llreflectionmap.cpp b/indra/newview/llreflectionmap.cpp
index ce749a96c7..394596feea 100644
--- a/indra/newview/llreflectionmap.cpp
+++ b/indra/newview/llreflectionmap.cpp
@@ -66,7 +66,7 @@ void LLReflectionMap::autoAdjustOrigin()
if (mGroup->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_VOLUME)
{
- mPriority = 1;
+ mPriority = 0;
// cast a ray towards 8 corners of bounding box
// nudge origin towards center of empty space
@@ -150,7 +150,7 @@ void LLReflectionMap::autoAdjustOrigin()
}
else if (mViewerObject)
{
- mPriority = 64;
+ mPriority = 1;
mOrigin.load3(mViewerObject->getPositionAgent().mV);
mRadius = mViewerObject->getScale().mV[0]*0.5f;
}
diff --git a/indra/newview/llreflectionmap.h b/indra/newview/llreflectionmap.h
index cf0bc2ff27..04bc8d824c 100644
--- a/indra/newview/llreflectionmap.h
+++ b/indra/newview/llreflectionmap.h
@@ -97,6 +97,9 @@ public:
LLViewerObject* mViewerObject = nullptr;
// what priority should this probe have (higher is higher priority)
- U32 mPriority = 1;
+ // currently only 0 or 1
+ // 0 - automatic probe
+ // 1 - manual probe
+ U32 mPriority = 0;
};