Skip to content
Snippets Groups Projects
Commit 63878a60 authored by David Parks's avatar David Parks
Browse files

SL-17416 Box reflection probe influence volumes

parent 53c692c9
No related branches found
No related tags found
No related merge requests found
...@@ -48,14 +48,20 @@ uniform sampler2D lightFunc; ...@@ -48,14 +48,20 @@ uniform sampler2D lightFunc;
layout (std140, binding = 1) uniform ReflectionProbes 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]; vec4 refSphere[REFMAP_COUNT];
// index of cube map in reflectionProbes for a corresponding reflection probe // index of cube map in reflectionProbes for a corresponding reflection probe
// e.g. cube map channel of refSphere[2] is stored in refIndex[2] // e.g. cube map channel of refSphere[2] is stored in refIndex[2]
// refIndex.x - cubemap channel in reflectionProbes // refIndex.x - cubemap channel in reflectionProbes
// refIndex.y - index in refNeighbor of neighbor list (index is ivec4 index, not int index) // refIndex.y - index in refNeighbor of neighbor list (index is ivec4 index, not int index)
// refIndex.z - number of neighbors // refIndex.z - number of neighbors
// refIndex.w - priority // refIndex.w - priority, if negative, this probe has a box influence
ivec4 refIndex[REFMAP_COUNT]; ivec4 refIndex[REFMAP_COUNT];
// neighbor list data (refSphere indices, not cubemap array layer) // neighbor list data (refSphere indices, not cubemap array layer)
...@@ -103,15 +109,38 @@ int probeIndex[REF_SAMPLE_COUNT]; ...@@ -103,15 +109,38 @@ int probeIndex[REF_SAMPLE_COUNT];
// number of probes stored in probeIndex // number of probes stored in probeIndex
int probeInfluences = 0; 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 // return true if probe at index i influences position pos
bool shouldSampleProbe(int i, vec3 pos) bool shouldSampleProbe(int i, vec3 pos)
{ {
vec3 delta = pos.xyz - refSphere[i].xyz; if (refIndex[i].w < 0)
float d = dot(delta, delta); {
float r2 = refSphere[i].w; vec4 v = refBox[i] * vec4(pos, 1.0);
r2 *= r2; if (abs(v.x) > 1 ||
return d < r2; 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 // 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 ...@@ -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 // 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 float t0, t1; // solutions for t if the ray intersects
...@@ -258,9 +287,60 @@ float sphereIntersect(vec3 origin, vec3 dir, vec3 center, float radius2) ...@@ -258,9 +287,60 @@ float sphereIntersect(vec3 origin, vec3 dir, vec3 center, float radius2)
t0 = tca - thc; t0 = tca - thc;
t1 = 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 // Tap a sphere based reflection probe
// pos - position of pixel // pos - position of pixel
// dir - pixel normal // dir - pixel normal
...@@ -269,18 +349,24 @@ float sphereIntersect(vec3 origin, vec3 dir, vec3 center, float radius2) ...@@ -269,18 +349,24 @@ float sphereIntersect(vec3 origin, vec3 dir, vec3 center, float radius2)
// r2 - radius of probe squared // r2 - radius of probe squared
// i - index of probe // i - index of probe
// vi - point at which reflection vector struck the influence volume, in clip space // 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); //lod = max(lod, 1);
// parallax adjustment // parallax adjustment
float d = sphereIntersect(pos, dir, c, r2);
vec3 v;
if (refIndex[i].w < 0)
{
v = boxIntersect(pos, dir, i);
}
else
{ {
vec3 v = pos + dir * d; v = sphereIntersect(pos, dir, c, r2);
vi = v; }
v -= c.xyz;
v = env_mat * v;
v -= c;
v = env_mat * v;
{
float min_lod = textureQueryLod(reflectionProbes,v).y; // lower is higher res 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 textureLod(reflectionProbes, vec4(v.xyz, refIndex[i].x), max(min_lod, lod)).rgb;
//return texture(reflectionProbes, vec4(v.xyz, refIndex[i].x)).rgb; //return texture(reflectionProbes, vec4(v.xyz, refIndex[i].x)).rgb;
...@@ -297,7 +383,7 @@ vec3 sampleRefMap(vec3 pos, vec3 dir, float lod) ...@@ -297,7 +383,7 @@ vec3 sampleRefMap(vec3 pos, vec3 dir, float lod)
{ {
int i = probeIndex[idx]; int i = probeIndex[idx];
float r = refSphere[i].w; // radius of sphere volume 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 rr = r*r; // radius squred
float r1 = r * 0.1; // 75% of radius (outer sphere to start interpolating down) float r1 = r * 0.1; // 75% of radius (outer sphere to start interpolating down)
vec3 delta = pos.xyz-refSphere[i].xyz; vec3 delta = pos.xyz-refSphere[i].xyz;
...@@ -305,8 +391,7 @@ vec3 sampleRefMap(vec3 pos, vec3 dir, float lod) ...@@ -305,8 +391,7 @@ vec3 sampleRefMap(vec3 pos, vec3 dir, float lod)
float r2 = r1*r1; float r2 = r1*r1;
{ {
vec3 vi; vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, rr, i);
vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, rr, i, vi);
float w = 1.0/d2; float w = 1.0/d2;
...@@ -323,13 +408,16 @@ vec3 sampleRefMap(vec3 pos, vec3 dir, float lod) ...@@ -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 { //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) 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; int i = idx;
vec3 delta = pos.xyz-refSphere[i].xyz; vec3 delta = pos.xyz-refSphere[i].xyz;
float d2 = dot(delta,delta); float d2 = dot(delta,delta);
{ {
vec3 vi; vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, d2, i);
vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, d2, i, vi);
float w = 1.0/d2; float w = 1.0/d2;
w *= w; w *= w;
......
...@@ -106,6 +106,7 @@ void LLReflectionMap::autoAdjustOrigin() ...@@ -106,6 +106,7 @@ void LLReflectionMap::autoAdjustOrigin()
} }
else if (mGroup->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_VOLUME) else if (mGroup->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_VOLUME)
{ {
mPriority = 8;
// cast a ray towards 8 corners of bounding box // cast a ray towards 8 corners of bounding box
// nudge origin towards center of empty space // nudge origin towards center of empty space
...@@ -182,6 +183,9 @@ void LLReflectionMap::autoAdjustOrigin() ...@@ -182,6 +183,9 @@ void LLReflectionMap::autoAdjustOrigin()
} }
else else
{ {
// user placed probe
mPriority = 64;
// use center of octree node volume for nodes that are just branches without data // use center of octree node volume for nodes that are just branches without data
mOrigin = node->getCenter(); mOrigin = node->getCenter();
...@@ -196,13 +200,15 @@ void LLReflectionMap::autoAdjustOrigin() ...@@ -196,13 +200,15 @@ void LLReflectionMap::autoAdjustOrigin()
} }
else if (mViewerObject) else if (mViewerObject)
{ {
mPriority = 64;
mOrigin.load3(mViewerObject->getPositionAgent().mV); mOrigin.load3(mViewerObject->getPositionAgent().mV);
mRadius = mViewerObject->getScale().mV[0]; mRadius = mViewerObject->getScale().mV[0]*0.5f;
} }
} }
bool LLReflectionMap::intersects(LLReflectionMap* other) bool LLReflectionMap::intersects(LLReflectionMap* other)
{ {
// TODO: incorporate getBox
LLVector4a delta; LLVector4a delta;
delta.setSub(other->mOrigin, mOrigin); delta.setSub(other->mOrigin, mOrigin);
...@@ -214,3 +220,56 @@ bool LLReflectionMap::intersects(LLReflectionMap* other) ...@@ -214,3 +220,56 @@ bool LLReflectionMap::intersects(LLReflectionMap* other)
return dist < r2; 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;
}
...@@ -55,6 +55,12 @@ class alignas(16) LLReflectionMap : public LLRefCount ...@@ -55,6 +55,12 @@ class alignas(16) LLReflectionMap : public LLRefCount
// return true if given Reflection Map's influence volume intersect's with this one's // return true if given Reflection Map's influence volume intersect's with this one's
bool intersects(LLReflectionMap* other); 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) // point at which environment map was last generated from (in agent space)
LLVector4a mOrigin; LLVector4a mOrigin;
...@@ -87,6 +93,9 @@ class alignas(16) LLReflectionMap : public LLRefCount ...@@ -87,6 +93,9 @@ class alignas(16) LLReflectionMap : public LLRefCount
// viewer object this probe is tracking (if any) // viewer object this probe is tracking (if any)
LLViewerObject* mViewerObject = nullptr; LLViewerObject* mViewerObject = nullptr;
// what priority should this probe have (higher is higher priority)
U32 mPriority = 1;
bool mDirty = true; bool mDirty = true;
}; };
...@@ -141,10 +141,16 @@ void LLReflectionMapManager::update() ...@@ -141,10 +141,16 @@ void LLReflectionMapManager::update()
mCreateList.clear(); 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; bool did_update = false;
LLReflectionMap* oldestProbe = mProbes[0];
if (mUpdatingProbe != nullptr) if (mUpdatingProbe != nullptr)
{ {
did_update = true; did_update = true;
...@@ -181,21 +187,30 @@ void LLReflectionMapManager::update() ...@@ -181,21 +187,30 @@ void LLReflectionMapManager::update()
probe->mDirty = false; probe->mDirty = false;
} }
if (probe->mCubeArray.notNull() &&
probe->mCubeIndex != -1 &&
probe->mLastUpdateTime < oldestProbe->mLastUpdateTime)
{
oldestProbe = probe;
}
d.setSub(camera_pos, probe->mOrigin); d.setSub(camera_pos, probe->mOrigin);
probe->mDistance = d.getLength3().getF32()-probe->mRadius; 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 // update distance to camera for all probes
std::sort(mProbes.begin(), mProbes.end(), CompareProbeDistance()); 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* LLReflectionMapManager::addProbe(LLSpatialGroup* group)
{ {
LLReflectionMap* probe = new LLReflectionMap(); LLReflectionMap* probe = new LLReflectionMap();
...@@ -251,6 +266,7 @@ void LLReflectionMapManager::getReflectionMaps(std::vector<LLReflectionMap*>& ma ...@@ -251,6 +266,7 @@ void LLReflectionMapManager::getReflectionMaps(std::vector<LLReflectionMap*>& ma
LLReflectionMap* LLReflectionMapManager::registerSpatialGroup(LLSpatialGroup* group) LLReflectionMap* LLReflectionMapManager::registerSpatialGroup(LLSpatialGroup* group)
{ {
#if 1
if (group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_VOLUME) if (group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_VOLUME)
{ {
OctreeNode* node = group->getOctreeNode(); OctreeNode* node = group->getOctreeNode();
...@@ -270,7 +286,7 @@ LLReflectionMap* LLReflectionMapManager::registerSpatialGroup(LLSpatialGroup* gr ...@@ -270,7 +286,7 @@ LLReflectionMap* LLReflectionMapManager::registerSpatialGroup(LLSpatialGroup* gr
return addProbe(group); return addProbe(group);
} }
} }
#endif
return nullptr; return nullptr;
} }
...@@ -493,6 +509,7 @@ void LLReflectionMapManager::setUniforms() ...@@ -493,6 +509,7 @@ void LLReflectionMapManager::setUniforms()
// see class2/deferred/softenLightF.glsl // see class2/deferred/softenLightF.glsl
struct ReflectionProbeData 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 LLVector4 refSphere[LL_REFLECTION_PROBE_COUNT]; //origin and radius of refmaps in clip space
GLint refIndex[LL_REFLECTION_PROBE_COUNT][4]; GLint refIndex[LL_REFLECTION_PROBE_COUNT][4];
GLint refNeighbor[4096]; GLint refNeighbor[4096];
...@@ -535,7 +552,14 @@ void LLReflectionMapManager::setUniforms() ...@@ -535,7 +552,14 @@ void LLReflectionMapManager::setUniforms()
rpd.refIndex[count][0] = refmap->mCubeIndex; rpd.refIndex[count][0] = refmap->mCubeIndex;
llassert(nc % 4 == 0); llassert(nc % 4 == 0);
rpd.refIndex[count][1] = nc / 4; 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 S32 ni = nc; // neighbor ("index") - index into refNeighbor to write indices for current reflection probe's neighbors
{ {
......
...@@ -52,9 +52,6 @@ class alignas(16) LLReflectionMapManager ...@@ -52,9 +52,6 @@ class alignas(16) LLReflectionMapManager
// maintain reflection probes // maintain reflection probes
void update(); 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 // add a probe for the given spatial group
LLReflectionMap* addProbe(LLSpatialGroup* group); LLReflectionMap* addProbe(LLSpatialGroup* group);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment