diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
index 3607c325a42008665b5322df9c5fff14f7858d55..d188233a8d359996bb8b6fbb06689fab71ef90f1 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 c146a888cf3860dce140938c73195aa771ee0eb0..4ac2803208abffb213d308a8c8ac60a756bebe72 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 305f33af4bcf52de943c0729e5f0105a030076a2..4f0f124118117ca64a2790c1b8522c76be530f13 100644
--- a/indra/newview/llreflectionmap.h
+++ b/indra/newview/llreflectionmap.h
@@ -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
     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 @@ class alignas(16) LLReflectionMap : public LLRefCount
     // 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 53c4857b0f037aa8b5cc910ffcdf6379355d7ec3..f4fdc3993fae3d33102e880c832125f5cc3137fa 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 f7feabbf66a30ec84438589d00bfc39d56954492..9417fe2416d7cc38be3bc72a676150d632fb9f47 100644
--- a/indra/newview/llreflectionmapmanager.h
+++ b/indra/newview/llreflectionmapmanager.h
@@ -52,9 +52,6 @@ class alignas(16) LLReflectionMapManager
     // 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);