summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorDave Parks <davep@lindenlab.com>2022-05-18 23:09:57 -0500
committerDave Parks <davep@lindenlab.com>2022-05-18 23:09:57 -0500
commit63878a60eb8ab6884ed3aeec63a28e5089636092 (patch)
tree9ec9560c89feb5304c13cc12248bec12ee25cb2d /indra
parent53c692c9597551c9a1ba8eee346432de51d9d22d (diff)
SL-17416 Box reflection probe influence volumes
Diffstat (limited to 'indra')
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl130
-rw-r--r--indra/newview/llreflectionmap.cpp61
-rw-r--r--indra/newview/llreflectionmap.h9
-rw-r--r--indra/newview/llreflectionmapmanager.cpp44
-rw-r--r--indra/newview/llreflectionmapmanager.h3
5 files changed, 212 insertions, 35 deletions
diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
index 3607c325a4..d188233a8d 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
@@ -48,14 +48,20 @@ uniform sampler2D lightFunc;
layout (std140, binding = 1) uniform ReflectionProbes
{
- // list of sphere based reflection probes sorted by distance to camera (closest first)
+ // 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
+ // refIndex.w - priority, if negative, this probe has a box influence
ivec4 refIndex[REFMAP_COUNT];
// neighbor list data (refSphere indices, not cubemap array layer)
@@ -103,15 +109,38 @@ 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)
{
- vec3 delta = pos.xyz - refSphere[i].xyz;
- float d = dot(delta, delta);
- float r2 = refSphere[i].w;
- r2 *= r2;
- return d < r2;
+ 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
@@ -245,7 +274,7 @@ bool intersect(const Ray &ray) const
} */
// adapted -- assume that origin is inside sphere, return distance from origin to edge of sphere
-float sphereIntersect(vec3 origin, vec3 dir, vec3 center, float radius2)
+vec3 sphereIntersect(vec3 origin, vec3 dir, vec3 center, float radius2)
{
float t0, t1; // solutions for t if the ray intersects
@@ -258,9 +287,60 @@ float sphereIntersect(vec3 origin, vec3 dir, vec3 center, float radius2)
t0 = tca - thc;
t1 = tca + thc;
- return t1;
+ 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
@@ -269,18 +349,24 @@ float sphereIntersect(vec3 origin, vec3 dir, vec3 center, float radius2)
// 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, out vec3 vi)
+vec3 tapRefMap(vec3 pos, vec3 dir, float lod, vec3 c, float r2, int i)
{
//lod = max(lod, 1);
-// parallax adjustment
- float d = sphereIntersect(pos, dir, c, r2);
+ // parallax adjustment
+ vec3 v;
+ if (refIndex[i].w < 0)
+ {
+ v = boxIntersect(pos, dir, i);
+ }
+ else
{
- vec3 v = pos + dir * d;
- vi = v;
- v -= c.xyz;
- v = env_mat * v;
+ 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;
@@ -297,7 +383,7 @@ vec3 sampleRefMap(vec3 pos, vec3 dir, float lod)
{
int i = probeIndex[idx];
float r = refSphere[i].w; // radius of sphere volume
- float p = float(refIndex[i].w); // priority
+ 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;
@@ -305,8 +391,7 @@ vec3 sampleRefMap(vec3 pos, vec3 dir, float lod)
float r2 = r1*r1;
{
- vec3 vi;
- vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, rr, i, vi);
+ vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, rr, i);
float w = 1.0/d2;
@@ -323,13 +408,16 @@ vec3 sampleRefMap(vec3 pos, vec3 dir, float lod)
{ //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 vi;
- vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, d2, i, vi);
+ vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, d2, i);
float w = 1.0/d2;
w *= w;
diff --git a/indra/newview/llreflectionmap.cpp b/indra/newview/llreflectionmap.cpp
index c146a888cf..4ac2803208 100644
--- a/indra/newview/llreflectionmap.cpp
+++ b/indra/newview/llreflectionmap.cpp
@@ -106,6 +106,7 @@ void LLReflectionMap::autoAdjustOrigin()
}
else if (mGroup->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_VOLUME)
{
+ mPriority = 8;
// cast a ray towards 8 corners of bounding box
// nudge origin towards center of empty space
@@ -182,6 +183,9 @@ void LLReflectionMap::autoAdjustOrigin()
}
else
{
+ // user placed probe
+ mPriority = 64;
+
// use center of octree node volume for nodes that are just branches without data
mOrigin = node->getCenter();
@@ -196,13 +200,15 @@ void LLReflectionMap::autoAdjustOrigin()
}
else if (mViewerObject)
{
+ mPriority = 64;
mOrigin.load3(mViewerObject->getPositionAgent().mV);
- mRadius = mViewerObject->getScale().mV[0];
+ mRadius = mViewerObject->getScale().mV[0]*0.5f;
}
}
bool LLReflectionMap::intersects(LLReflectionMap* other)
{
+ // TODO: incorporate getBox
LLVector4a delta;
delta.setSub(other->mOrigin, mOrigin);
@@ -214,3 +220,56 @@ bool LLReflectionMap::intersects(LLReflectionMap* other)
return dist < r2;
}
+
+bool LLReflectionMap::getBox(LLMatrix4& box)
+{
+ if (mViewerObject)
+ {
+ LLVolume* volume = mViewerObject->getVolume();
+ if (volume)
+ {
+ LLVOVolume* vobjp = (LLVOVolume*)mViewerObject;
+
+ U8 profile = volume->getProfileType();
+ U8 path = volume->getPathType();
+
+ if (profile == LL_PCODE_PROFILE_SQUARE &&
+ path == LL_PCODE_PATH_LINE)
+ {
+ // nope
+ /*box = vobjp->getRelativeXform();
+ box *= vobjp->mDrawable->getRenderMatrix();
+ LLMatrix4 modelview(gGLModelView);
+ box *= modelview;
+ box.invert();*/
+
+ // nope
+ /*box = LLMatrix4(gGLModelView);
+ box *= vobjp->mDrawable->getRenderMatrix();
+ box *= vobjp->getRelativeXform();
+ box.invert();*/
+
+ glh::matrix4f mv(gGLModelView);
+ glh::matrix4f scale;
+ LLVector3 s = vobjp->getScale().scaledVec(LLVector3(0.5f, 0.5f, 0.5f));
+ mRadius = s.magVec();
+ scale.set_scale(glh::vec3f(s.mV));
+ if (vobjp->mDrawable != nullptr)
+ {
+ glh::matrix4f rm((F32*)vobjp->mDrawable->getWorldMatrix().mMatrix);
+
+ glh::matrix4f rt((F32*)vobjp->getRelativeXform().mMatrix);
+
+ mv = mv * rm * scale; // *rt;
+ mv = mv.inverse();
+
+ box = LLMatrix4(mv.m);
+
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/indra/newview/llreflectionmap.h b/indra/newview/llreflectionmap.h
index 305f33af4b..4f0f124118 100644
--- a/indra/newview/llreflectionmap.h
+++ b/indra/newview/llreflectionmap.h
@@ -55,6 +55,12 @@ public:
// return true if given Reflection Map's influence volume intersect's with this one's
bool intersects(LLReflectionMap* other);
+ // get the encoded bounding box of this probe's influence volume
+ // will only return a box if this probe has a volume with a square
+ // profile and a linear path
+ // return false if no bounding box (treat as sphere influence volume)
+ bool getBox(LLMatrix4& box);
+
// point at which environment map was last generated from (in agent space)
LLVector4a mOrigin;
@@ -87,6 +93,9 @@ public:
// viewer object this probe is tracking (if any)
LLViewerObject* mViewerObject = nullptr;
+ // what priority should this probe have (higher is higher priority)
+ U32 mPriority = 1;
+
bool mDirty = true;
};
diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp
index 53c4857b0f..f4fdc3993f 100644
--- a/indra/newview/llreflectionmapmanager.cpp
+++ b/indra/newview/llreflectionmapmanager.cpp
@@ -141,10 +141,16 @@ void LLReflectionMapManager::update()
mCreateList.clear();
- const F32 UPDATE_INTERVAL = 10.f; //update no more than once every 5 seconds
+ if (mProbes.empty())
+ {
+ return;
+ }
+ const F32 UPDATE_INTERVAL = 5.f; //update no more than once every 5 seconds
bool did_update = false;
+ LLReflectionMap* oldestProbe = mProbes[0];
+
if (mUpdatingProbe != nullptr)
{
did_update = true;
@@ -181,21 +187,30 @@ void LLReflectionMapManager::update()
probe->mDirty = false;
}
+ if (probe->mCubeArray.notNull() &&
+ probe->mCubeIndex != -1 &&
+ probe->mLastUpdateTime < oldestProbe->mLastUpdateTime)
+ {
+ oldestProbe = probe;
+ }
+
d.setSub(camera_pos, probe->mOrigin);
probe->mDistance = d.getLength3().getF32()-probe->mRadius;
}
+#if 0
+ if (mUpdatingProbe == nullptr &&
+ oldestProbe->mCubeArray.notNull() &&
+ oldestProbe->mCubeIndex != -1)
+ { // didn't find any probes to update, update the most out of date probe that's currently in use on next frame
+ mUpdatingProbe = oldestProbe;
+ }
+#endif
+
// update distance to camera for all probes
std::sort(mProbes.begin(), mProbes.end(), CompareProbeDistance());
}
-void LLReflectionMapManager::addProbe(const LLVector3& pos)
-{
- //LLReflectionMap* probe = new LLReflectionMap();
- //probe->update(pos, 1024);
- //mProbes.push_back(probe);
-}
-
LLReflectionMap* LLReflectionMapManager::addProbe(LLSpatialGroup* group)
{
LLReflectionMap* probe = new LLReflectionMap();
@@ -251,6 +266,7 @@ void LLReflectionMapManager::getReflectionMaps(std::vector<LLReflectionMap*>& ma
LLReflectionMap* LLReflectionMapManager::registerSpatialGroup(LLSpatialGroup* group)
{
+#if 1
if (group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_VOLUME)
{
OctreeNode* node = group->getOctreeNode();
@@ -270,7 +286,7 @@ LLReflectionMap* LLReflectionMapManager::registerSpatialGroup(LLSpatialGroup* gr
return addProbe(group);
}
}
-
+#endif
return nullptr;
}
@@ -493,6 +509,7 @@ void LLReflectionMapManager::setUniforms()
// see class2/deferred/softenLightF.glsl
struct ReflectionProbeData
{
+ LLMatrix4 refBox[LL_REFLECTION_PROBE_COUNT]; // object bounding box as needed
LLVector4 refSphere[LL_REFLECTION_PROBE_COUNT]; //origin and radius of refmaps in clip space
GLint refIndex[LL_REFLECTION_PROBE_COUNT][4];
GLint refNeighbor[4096];
@@ -535,7 +552,14 @@ void LLReflectionMapManager::setUniforms()
rpd.refIndex[count][0] = refmap->mCubeIndex;
llassert(nc % 4 == 0);
rpd.refIndex[count][1] = nc / 4;
- rpd.refIndex[count][3] = refmap->mViewerObject ? 10 : 1;
+ rpd.refIndex[count][3] = refmap->mPriority;
+
+ // for objects that are reflection probes, use the volume as the influence volume of the probe
+ // only possibile influence volumes are boxes and spheres, so detect boxes and treat everything else as spheres
+ if (refmap->getBox(rpd.refBox[count]))
+ { // negate priority to indicate this probe has a box influence volume
+ rpd.refIndex[count][3] = -rpd.refIndex[count][3];
+ }
S32 ni = nc; // neighbor ("index") - index into refNeighbor to write indices for current reflection probe's neighbors
{
diff --git a/indra/newview/llreflectionmapmanager.h b/indra/newview/llreflectionmapmanager.h
index f7feabbf66..9417fe2416 100644
--- a/indra/newview/llreflectionmapmanager.h
+++ b/indra/newview/llreflectionmapmanager.h
@@ -52,9 +52,6 @@ public:
// maintain reflection probes
void update();
- // drop a reflection probe at the specified position in agent space
- void addProbe(const LLVector3& pos);
-
// add a probe for the given spatial group
LLReflectionMap* addProbe(LLSpatialGroup* group);