diff options
| -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); | 
