diff options
author | Dave Parks <davep@lindenlab.com> | 2022-05-18 23:09:57 -0500 |
---|---|---|
committer | Dave Parks <davep@lindenlab.com> | 2022-05-18 23:09:57 -0500 |
commit | 63878a60eb8ab6884ed3aeec63a28e5089636092 (patch) | |
tree | 9ec9560c89feb5304c13cc12248bec12ee25cb2d /indra/newview | |
parent | 53c692c9597551c9a1ba8eee346432de51d9d22d (diff) |
SL-17416 Box reflection probe influence volumes
Diffstat (limited to 'indra/newview')
-rw-r--r-- | indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl | 130 | ||||
-rw-r--r-- | indra/newview/llreflectionmap.cpp | 61 | ||||
-rw-r--r-- | indra/newview/llreflectionmap.h | 9 | ||||
-rw-r--r-- | indra/newview/llreflectionmapmanager.cpp | 44 | ||||
-rw-r--r-- | indra/newview/llreflectionmapmanager.h | 3 |
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); |