diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp
index c46e5fb3c576efb958f3e91136ff8b4882df15de..87a78eb4476854b509d4c6c2f9bf8ac878f60020 100644
--- a/indra/llprimitive/llprimitive.cpp
+++ b/indra/llprimitive/llprimitive.cpp
@@ -81,6 +81,14 @@ const F32 LIGHT_MIN_CUTOFF = 0.0f;
 const F32 LIGHT_DEFAULT_CUTOFF = 0.0f;
 const F32 LIGHT_MAX_CUTOFF = 180.f;
 
+// reflection probes
+const F32 REFLECTION_PROBE_MIN_AMBIANCE = 0.f;
+const F32 REFLECTION_PROBE_MAX_AMBIANCE = 1.f;
+const F32 REFLECTION_PROBE_DEFAULT_AMBIANCE = 0.f;
+const F32 REFLECTION_PROBE_MIN_CLIP_DISTANCE = 0.f;
+const F32 REFLECTION_PROBE_MAX_CLIP_DISTANCE = 1024.f;
+const F32 REFLECTION_PROBE_DEFAULT_CLIP_DISTANCE = 0.f;
+
 // "Tension" => [0,10], increments of 0.1
 const F32 FLEXIBLE_OBJECT_MIN_TENSION = 0.0f;
 const F32 FLEXIBLE_OBJECT_DEFAULT_TENSION = 1.0f;
@@ -1811,6 +1819,93 @@ bool LLLightParams::fromLLSD(LLSD& sd)
 
 //============================================================================
 
+LLReflectionProbeParams::LLReflectionProbeParams()
+{
+    mType = PARAMS_REFLECTION_PROBE;
+}
+
+BOOL LLReflectionProbeParams::pack(LLDataPacker& dp) const
+{
+    dp.packF32(mAmbiance, "ambiance");
+    dp.packF32(mClipDistance, "clip_distance");
+    dp.packU8(mVolumeType, "volume_type");
+    return TRUE;
+}
+
+BOOL LLReflectionProbeParams::unpack(LLDataPacker& dp)
+{
+    F32 ambiance;
+    F32 clip_distance;
+    U8 volume_type;
+
+    dp.unpackF32(ambiance, "ambiance");
+    setAmbiance(ambiance);
+
+    dp.unpackF32(clip_distance, "clip_distance");
+    setClipDistance(clip_distance);
+
+    dp.unpackU8(volume_type, "volume_type");
+    setVolumeType((EInfluenceVolumeType)volume_type);
+
+    return TRUE;
+}
+
+bool LLReflectionProbeParams::operator==(const LLNetworkData& data) const
+{
+    if (data.mType != PARAMS_REFLECTION_PROBE)
+    {
+        return false;
+    }
+    const LLReflectionProbeParams* param = (const LLReflectionProbeParams*)&data;
+    if (param->mAmbiance != mAmbiance)
+    {
+        return false;
+    }
+    if (param->mClipDistance != mClipDistance)
+    {
+        return false;
+    }
+    if (param->mVolumeType != mVolumeType)
+    {
+        return false;
+    }
+    return true;
+}
+
+void LLReflectionProbeParams::copy(const LLNetworkData& data)
+{
+    const LLReflectionProbeParams* param = (LLReflectionProbeParams*)&data;
+    mType = param->mType;
+    mAmbiance = param->mAmbiance;
+    mClipDistance = param->mClipDistance;
+    mVolumeType = param->mVolumeType;
+}
+
+LLSD LLReflectionProbeParams::asLLSD() const
+{
+    LLSD sd;
+    sd["ambiance"] = getAmbiance();
+    sd["clip_distance"] = getClipDistance();
+    sd["volume_type"] = getVolumeType();
+    return sd;
+}
+
+bool LLReflectionProbeParams::fromLLSD(LLSD& sd)
+{
+    if (!sd.has("ambiance") ||
+        !sd.has("clip_distance") ||
+        !sd.has("volume_type"))
+    {
+        return false;
+    }
+
+    setAmbiance((F32)sd["ambiance"].asReal());
+    setClipDistance((F32)sd["clip_distance"].asReal());
+    setVolumeType((EInfluenceVolumeType)sd["volume_type"].asInteger());
+
+    return true;
+}
+//============================================================================
 LLFlexibleObjectData::LLFlexibleObjectData()
 {
 	mSimulateLOD				= FLEXIBLE_OBJECT_DEFAULT_NUM_SECTIONS;
diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h
index e23ddd2916135bed9e35be8edf70fe84f79a1d80..2215133e169691df7c2b713b41def1969063f260 100644
--- a/indra/llprimitive/llprimitive.h
+++ b/indra/llprimitive/llprimitive.h
@@ -108,6 +108,7 @@ class LLNetworkData
 		PARAMS_MESH     = 0x60,
         PARAMS_EXTENDED_MESH = 0x70,
         PARAMS_RENDER_MATERIAL = 0x80,
+        PARAMS_REFLECTION_PROBE = 0x90,
 	};
 	
 public:
@@ -171,6 +172,49 @@ class LLLightParams : public LLNetworkData
 	F32 getCutoff() const					{ return mCutoff; }
 };
 
+extern const F32 REFLECTION_PROBE_MIN_AMBIANCE;
+extern const F32 REFLECTION_PROBE_MAX_AMBIANCE;
+extern const F32 REFLECTION_PROBE_DEFAULT_AMBIANCE;
+extern const F32 REFLECTION_PROBE_MIN_CLIP_DISTANCE;
+extern const F32 REFLECTION_PROBE_MAX_CLIP_DISTANCE;
+extern const F32 REFLECTION_PROBE_DEFAULT_CLIP_DISTANCE;
+
+class LLReflectionProbeParams : public LLNetworkData
+{
+public:
+    enum EInfluenceVolumeType : U8
+    {
+        VOLUME_TYPE_SPHERE = 0,  // use a sphere influence volume
+        VOLUME_TYPE_BOX = 1,      // use a box influence volume
+        DEFAULT_VOLUME_TYPE = VOLUME_TYPE_SPHERE
+    };
+
+protected:
+    F32 mAmbiance = REFLECTION_PROBE_DEFAULT_AMBIANCE;
+    F32 mClipDistance = REFLECTION_PROBE_DEFAULT_CLIP_DISTANCE;
+    EInfluenceVolumeType mVolumeType = DEFAULT_VOLUME_TYPE;
+
+public:
+    LLReflectionProbeParams();
+    /*virtual*/ BOOL pack(LLDataPacker& dp) const;
+    /*virtual*/ BOOL unpack(LLDataPacker& dp);
+    /*virtual*/ bool operator==(const LLNetworkData& data) const;
+    /*virtual*/ void copy(const LLNetworkData& data);
+    // LLSD implementations here are provided by Eddy Stryker.
+    // NOTE: there are currently unused in protocols
+    LLSD asLLSD() const;
+    operator LLSD() const { return asLLSD(); }
+    bool fromLLSD(LLSD& sd);
+
+    void setAmbiance(F32 ambiance) { mAmbiance = llclamp(ambiance, REFLECTION_PROBE_MIN_AMBIANCE, REFLECTION_PROBE_MAX_AMBIANCE); }
+    void setClipDistance(F32 distance) { mClipDistance = llclamp(distance, REFLECTION_PROBE_MIN_CLIP_DISTANCE, REFLECTION_PROBE_MAX_CLIP_DISTANCE); }
+    void setVolumeType(EInfluenceVolumeType type) { mVolumeType = llclamp(type, VOLUME_TYPE_SPHERE, VOLUME_TYPE_BOX); }
+
+    F32 getAmbiance() const { return mAmbiance; }
+    F32 getClipDistance() const { return mClipDistance; }
+    EInfluenceVolumeType getVolumeType() const { return mVolumeType; }
+};
+
 //-------------------------------------------------
 // This structure is also used in the part of the 
 // code that creates new flexible objects.
diff --git a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl
index 8c1323ba1aa9b40f5631288a854efa3d77b867fe..eb9d3f485b6f7d3e26e69e4cd012b41ed43a8d4d 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl
@@ -1,5 +1,5 @@
 /**
- * @file class2/deferred/reflectionProbeF.glsl
+ * @file class3/deferred/reflectionProbeF.glsl
  *
  * $LicenseInfo:firstyear=2022&license=viewerlgpl$
  * Second Life Viewer Source Code
@@ -42,6 +42,8 @@ layout (std140, binding = 1) uniform ReflectionProbes
     mat4 refBox[REFMAP_COUNT];
     // list of bounding spheres for reflection probes sorted by distance to camera (closest first)
     vec4 refSphere[REFMAP_COUNT];
+    // extra parameters (currently only .x used for probe ambiance)
+    vec4 refParams[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
@@ -55,9 +57,6 @@ layout (std140, binding = 1) uniform ReflectionProbes
 
     // number of reflection probes present in refSphere
     int refmapCount;
-
-    // intensity of ambient light from reflection probes
-    float reflectionAmbiance;
 };
 
 // Inputs
@@ -335,7 +334,7 @@ vec3 tapRefMap(vec3 pos, vec3 dir, float lod, vec3 c, float r2, int i)
     }
 }
 
-vec3 sampleProbes(vec3 pos, vec3 dir, float lod)
+vec3 sampleProbes(vec3 pos, vec3 dir, float lod, float minweight)
 {
     float wsum = 0.0;
     vec3 col = vec3(0,0,0);
@@ -360,7 +359,7 @@ vec3 sampleProbes(vec3 pos, vec3 dir, float lod)
             float atten = 1.0-max(d2-r2, 0.0)/(rr-r2);
             w *= atten;
             w *= p; // boost weight based on priority
-            col += refcol*w;
+            col += refcol*w*max(minweight, refParams[i].x);
             
             wsum += w;
         }
@@ -383,7 +382,7 @@ vec3 sampleProbes(vec3 pos, vec3 dir, float lod)
                 
                 float w = 1.0/d2;
                 w *= w;
-                col += refcol*w;
+                col += refcol*w*max(minweight, refParams[i].x);
                 wsum += w;
             }
         }
@@ -399,7 +398,7 @@ vec3 sampleProbes(vec3 pos, vec3 dir, float lod)
 
 vec3 sampleProbeAmbient(vec3 pos, vec3 dir, float lod)
 {
-    vec3 col = sampleProbes(pos, dir, lod);
+    vec3 col = sampleProbes(pos, dir, lod, 0.f);
 
     //desaturate
     vec3 hcol = col *0.5;
@@ -413,7 +412,7 @@ vec3 sampleProbeAmbient(vec3 pos, vec3 dir, float lod)
     
     col *= 0.333333;
 
-    return col*reflectionAmbiance;
+    return col;
 
 }
 
@@ -445,12 +444,12 @@ void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, inout vec3 l
     if (glossiness > 0.0)
     {
         float lod = (1.0-glossiness)*reflection_lods;
-        glossenv = sampleProbes(pos, normalize(refnormpersp), lod);
+        glossenv = sampleProbes(pos, normalize(refnormpersp), lod, 1.f);
     }
 
     if (envIntensity > 0.0)
     {
-        legacyenv = sampleProbes(pos, normalize(refnormpersp), 0.0);
+        legacyenv = sampleProbes(pos, normalize(refnormpersp), 0.0, 1.f);
     }
 }
 
diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp
index 89c558e4f8f4e23217008aa5960962c783c6f125..e7bbe266e54bc9049cefe42718b3fe78d246a0dd 100644
--- a/indra/newview/llpanelvolume.cpp
+++ b/indra/newview/llpanelvolume.cpp
@@ -145,6 +145,16 @@ BOOL	LLPanelVolume::postBuild()
 		getChild<LLUICtrl>("Light Ambiance")->setValidateBeforeCommit( precommitValidate);
 	}
 	
+    // REFLECTION PROBE Parameters
+    {
+        childSetCommitCallback("Reflection Probe Checkbox Ctrl", onCommitIsReflectionProbe, this);
+        childSetCommitCallback("Probe Shape Type Combo Ctrl", onCommitProbe, this);
+        childSetCommitCallback("Probe Ambiance", onCommitProbe, this);
+        childSetCommitCallback("Probe Near Clip", onCommitProbe, this);
+
+
+    }
+
 	// PHYSICS Parameters
 	{
 		// PhysicsShapeType combobox
@@ -360,6 +370,40 @@ void LLPanelVolume::getState( )
 		getChildView("Light Ambiance")->setEnabled(false);
 	}
 
+    // Reflection Probe
+    BOOL is_probe = volobjp && volobjp->getIsReflectionProbe();
+    getChild<LLUICtrl>("Reflection Probe Checkbox Ctrl")->setValue(is_probe);
+    getChildView("Reflection Probe Checkbox Ctrl")->setEnabled(editable && single_volume && volobjp);
+
+    bool probe_enabled = is_probe && editable && single_volume;
+
+    getChildView("Probe Volume Type Ctrl")->setEnabled(probe_enabled);
+    getChildView("Probe Ambiance")->setEnabled(probe_enabled);
+    getChildView("Probe Near Clip")->setEnabled(probe_enabled);
+
+    if (!probe_enabled)
+    {
+        getChild<LLComboBox>("Probe Volume Type Ctrl", true)->clear();
+        getChild<LLSpinCtrl>("Probe Ambiance", true)->clear();
+        getChild<LLSpinCtrl>("Probe Near Clip", true)->clear();
+    }
+    else
+    {
+        std::string volume_type;
+        if (volobjp->getReflectionProbeVolumeType() == LLReflectionProbeParams::VOLUME_TYPE_BOX)
+        {
+            volume_type = "Box";
+        }
+        else
+        {
+            volume_type = "Sphere";
+        }
+
+        getChild<LLComboBox>("Probe Volume Type Ctrl", true)->setValue(volume_type);
+        getChild<LLSpinCtrl>("Probe Ambiance", true)->setValue(volobjp->getReflectionProbeAmbiance());
+        getChild<LLSpinCtrl>("Probe Near Clip", true)->setValue(volobjp->getReflectionProbeNearClip());
+    }
+
     // Animated Mesh
 	BOOL is_animated_mesh = single_root_volume && root_volobjp && root_volobjp->isAnimatedObject();
 	getChild<LLUICtrl>("Animated Mesh Checkbox Ctrl")->setValue(is_animated_mesh);
@@ -647,6 +691,10 @@ void LLPanelVolume::clearCtrls()
 	getChildView("Light Radius")->setEnabled(false);
 	getChildView("Light Falloff")->setEnabled(false);
 
+    getChildView("Reflection Probe Checkbox Ctrl")->setEnabled(false);;
+    getChildView("Probe Volume Type Ctrl")->setEnabled(false);
+    getChildView("Probe Ambiance")->setEnabled(false);
+    getChildView("Probe Near Clip")->setEnabled(false);
     getChildView("Animated Mesh Checkbox Ctrl")->setEnabled(false);
 	getChildView("Flexible1D Checkbox Ctrl")->setEnabled(false);
 	getChildView("FlexNumSections")->setEnabled(false);
@@ -684,6 +732,20 @@ void LLPanelVolume::sendIsLight()
 	LL_INFOS() << "update light sent" << LL_ENDL;
 }
 
+void LLPanelVolume::sendIsReflectionProbe()
+{
+    LLViewerObject* objectp = mObject;
+    if (!objectp || (objectp->getPCode() != LL_PCODE_VOLUME))
+    {
+        return;
+    }
+    LLVOVolume* volobjp = (LLVOVolume*)objectp;
+
+    BOOL value = getChild<LLUICtrl>("Reflection Probe Checkbox Ctrl")->getValue();
+    volobjp->setIsReflectionProbe(value);
+    LL_INFOS() << "update reflection probe sent" << LL_ENDL;
+}
+
 void LLPanelVolume::sendIsFlexible()
 {
 	LLViewerObject* objectp = mObject;
@@ -927,6 +989,35 @@ void LLPanelVolume::onCommitLight( LLUICtrl* ctrl, void* userdata )
 	
 }
 
+//static 
+void LLPanelVolume::onCommitProbe(LLUICtrl* ctrl, void* userdata)
+{
+    LLPanelVolume* self = (LLPanelVolume*)userdata;
+    LLViewerObject* objectp = self->mObject;
+    if (!objectp || (objectp->getPCode() != LL_PCODE_VOLUME))
+    {
+        return;
+    }
+    LLVOVolume* volobjp = (LLVOVolume*)objectp;
+
+
+    volobjp->setReflectionProbeAmbiance((F32)self->getChild<LLUICtrl>("Probe Ambiance")->getValue().asReal());
+    volobjp->setReflectionProbeNearClip((F32)self->getChild<LLUICtrl>("Probe Near Clip")->getValue().asReal());
+
+    std::string shape_type = self->getChild<LLUICtrl>("Probe Volume Type Ctrl")->getValue().asString();
+    LLReflectionProbeParams::EInfluenceVolumeType volume_type = LLReflectionProbeParams::DEFAULT_VOLUME_TYPE;
+
+    if (shape_type == "Sphere")
+    {
+        volume_type = LLReflectionProbeParams::VOLUME_TYPE_SPHERE;
+    }
+    else if (shape_type == "Box")
+    {
+        volume_type = LLReflectionProbeParams::VOLUME_TYPE_BOX;
+    }
+    volobjp->setReflectionProbeVolumeType(volume_type);
+}
+
 // static
 void LLPanelVolume::onCommitIsLight( LLUICtrl* ctrl, void* userdata )
 {
@@ -949,6 +1040,15 @@ void LLPanelVolume::setLightTextureID(const LLUUID &asset_id, const LLUUID &item
 }
 //----------------------------------------------------------------------------
 
+// static
+void LLPanelVolume::onCommitIsReflectionProbe(LLUICtrl* ctrl, void* userdata)
+{
+    LLPanelVolume* self = (LLPanelVolume*)userdata;
+    self->sendIsReflectionProbe();
+}
+
+//----------------------------------------------------------------------------
+
 // static
 void LLPanelVolume::onCommitFlexible( LLUICtrl* ctrl, void* userdata )
 {
diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h
index 6e49ccb742649f769ea61ece67939a302854946a..16d9ac292df2195afdaec4c428fbf9b6ef112aa3 100644
--- a/indra/newview/llpanelvolume.h
+++ b/indra/newview/llpanelvolume.h
@@ -56,12 +56,15 @@ class LLPanelVolume : public LLPanel
 	void			refresh();
 
 	void			sendIsLight();
+    void            sendIsReflectionProbe();
 	void			sendIsFlexible();
 
 	static bool		precommitValidate(const LLSD& data);
 	
 	static void 	onCommitIsLight(		LLUICtrl* ctrl, void* userdata);
 	static void 	onCommitLight(			LLUICtrl* ctrl, void* userdata);
+    static void 	onCommitIsReflectionProbe(LLUICtrl* ctrl, void* userdata);
+    static void     onCommitProbe(LLUICtrl* ctrl, void* userdata);
 	void 			onCommitIsFlexible(		LLUICtrl* ctrl, void* userdata);
 	static void 	onCommitFlexible(		LLUICtrl* ctrl, void* userdata);
     void            onCommitAnimatedMeshCheckbox(LLUICtrl* ctrl, void* userdata);
diff --git a/indra/newview/llreflectionmap.cpp b/indra/newview/llreflectionmap.cpp
index 54a627efd4dc307b4aed6130f1d62b30858d528b..f8a2020ccb253a09ae555ce109141fb65c2b0fad 100644
--- a/indra/newview/llreflectionmap.cpp
+++ b/indra/newview/llreflectionmap.cpp
@@ -35,7 +35,6 @@ extern F32SecondsImplicit gFrameTimeSeconds;
 
 LLReflectionMap::LLReflectionMap()
 {
-    mLastUpdateTime = gFrameTimeSeconds;
 }
 
 void LLReflectionMap::update(U32 resolution, U32 face)
@@ -52,7 +51,7 @@ void LLReflectionMap::update(U32 resolution, U32 face)
     {
         resolution /= 2;
     }
-    gViewerWindow->cubeSnapshot(LLVector3(mOrigin), mCubeArray, mCubeIndex, face);
+    gViewerWindow->cubeSnapshot(LLVector3(mOrigin), mCubeArray, mCubeIndex, face, getNearClip());
 }
 
 bool LLReflectionMap::shouldUpdate()
@@ -215,6 +214,35 @@ bool LLReflectionMap::intersects(LLReflectionMap* other)
     return dist < r2;
 }
 
+extern LLControlGroup gSavedSettings;
+
+F32 LLReflectionMap::getAmbiance()
+{
+    static LLCachedControl<F32> minimum_ambiance(gSavedSettings, "RenderReflectionProbeAmbiance", 0.f);
+
+    F32 ret = 0.f;
+    if (mViewerObject && mViewerObject->getVolume())
+    {
+        ret = ((LLVOVolume*)mViewerObject)->getReflectionProbeAmbiance();
+    }
+
+    return llmax(ret, minimum_ambiance());
+}
+
+F32 LLReflectionMap::getNearClip()
+{
+    const F32 MINIMUM_NEAR_CLIP = 0.1f;
+
+    F32 ret = 0.f;
+
+    if (mViewerObject && mViewerObject->getVolume())
+    {
+        ret = ((LLVOVolume*)mViewerObject)->getReflectionProbeNearClip();
+    }
+
+    return llmax(ret, MINIMUM_NEAR_CLIP);
+}
+
 bool LLReflectionMap::getBox(LLMatrix4& box)
 { 
     if (mViewerObject)
@@ -224,25 +252,8 @@ bool LLReflectionMap::getBox(LLMatrix4& box)
         {
             LLVOVolume* vobjp = (LLVOVolume*)mViewerObject;
 
-            U8 profile = volume->getProfileType();
-            U8 path = volume->getPathType();
-
-            if (profile == LL_PCODE_PROFILE_SQUARE &&
-                path == LL_PCODE_PATH_LINE)
+            if (vobjp->getReflectionProbeVolumeType() == LLReflectionProbeParams::VOLUME_TYPE_BOX)
             {
-                // 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));
diff --git a/indra/newview/llreflectionmap.h b/indra/newview/llreflectionmap.h
index 4f0f124118117ca64a2790c1b8522c76be530f13..a358bf5fdf1f199e9adca91aed62901a8ba7474d 100644
--- a/indra/newview/llreflectionmap.h
+++ b/indra/newview/llreflectionmap.h
@@ -55,9 +55,15 @@ 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 ambiance value to use for this probe
+    F32 getAmbiance();
+
+    // Get the near clip plane distance to use for this probe
+    F32 getNearClip();
+
     // 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
+    // will only return a box if this probe is associated with a VOVolume
+    // with its reflection probe influence volume to to VOLUME_TYPE_BOX
     // return false if no bounding box (treat as sphere influence volume)
     bool getBox(LLMatrix4& box);
 
diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp
index 34055653d4827f1f066047e600437240b6adb30e..60396b6c605ef5d9f6ac002f919a639090ac25db 100644
--- a/indra/newview/llreflectionmapmanager.cpp
+++ b/indra/newview/llreflectionmapmanager.cpp
@@ -127,18 +127,12 @@ void LLReflectionMapManager::update()
     camera_pos.load3(LLViewerCamera::instance().getOrigin().mV);
 
     // process kill list
-    for (int i = 0; i < mProbes.size(); )
+    for (auto& probe : mKillList)
     {
-        auto& iter = std::find(mKillList.begin(), mKillList.end(), mProbes[i]);
-        if (iter != mKillList.end())
+        auto& iter = std::find(mProbes.begin(), mProbes.end(), probe);
+        if (iter != mProbes.end())
         {
-            deleteProbe(i);
-            mProbes.erase(mProbes.begin() + i);
-            mKillList.erase(iter);
-        }
-        else
-        {
-            ++i;
+            deleteProbe(iter - mProbes.begin());
         }
     }
 
@@ -275,7 +269,7 @@ LLReflectionMap* LLReflectionMapManager::registerSpatialGroup(LLSpatialGroup* gr
     {
         OctreeNode* node = group->getOctreeNode();
         F32 size = node->getSize().getF32ptr()[0];
-        if (size >= 7.f && size <= 17.f)
+        if (size >= 15.f && size <= 17.f)
         {
             return addProbe(group);
         }
@@ -514,15 +508,15 @@ void LLReflectionMapManager::updateUniforms()
     LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
 
     // structure for packing uniform buffer object
-    // see class2/deferred/softenLightF.glsl
+    // see class3/deferred/reflectionProbeF.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
+        LLVector4 refParams[LL_REFLECTION_PROBE_COUNT]; //extra parameters (currently only ambiance)
         GLint refIndex[LL_REFLECTION_PROBE_COUNT][4];
         GLint refNeighbor[4096];
         GLint refmapCount;
-        GLfloat reflectionAmbiance;
     };
 
     mReflectionMaps.resize(LL_REFLECTION_PROBE_COUNT);
@@ -530,9 +524,6 @@ void LLReflectionMapManager::updateUniforms()
 
     ReflectionProbeData rpd;
 
-    static LLCachedControl<F32> ambiance(gSavedSettings, "RenderReflectionProbeAmbiance", 0.f);
-    rpd.reflectionAmbiance = ambiance;
-
     // load modelview matrix into matrix 4a
     LLMatrix4a modelview;
     modelview.loadu(gGLModelView);
@@ -573,6 +564,8 @@ void LLReflectionMapManager::updateUniforms()
             rpd.refIndex[count][3] = -rpd.refIndex[count][3];
         }
 
+        rpd.refParams[count].set(refmap->getAmbiance(), 0.f, 0.f, 0.f);
+
         S32 ni = nc; // neighbor ("index") - index into refNeighbor to write indices for current reflection probe's neighbors
         {
             //LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmsu - refNeighbors");
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 0edaf40c66dd6064a1dbae688450b27ad49081c5..35e4bb03ac717ceddccecb932ec6f613ae79523c 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -3400,6 +3400,7 @@ void LLTextureFetch::sendRequestListToSimulators()
 					gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
 				}
 				S32 packet = req->mLastPacket + 1;
+                LL_INFOS() << req->mID << ": " << req->mImagePriority << LL_ENDL;
 				gMessageSystem->nextBlockFast(_PREHASH_RequestImage);
 				gMessageSystem->addUUIDFast(_PREHASH_Image, req->mID);
 				gMessageSystem->addS8Fast(_PREHASH_DiscardLevel, (S8)req->mDesiredDiscard);
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 1b8e53e667719783d8b1ff7742e6641a4fd6c1fa..6d98d9b10eafa0472cb8742966ce8e27bf68410e 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -1082,7 +1082,6 @@ void display_cube_face()
 
     gPipeline.mBackfaceCull = TRUE;
 
-    LLViewerCamera::getInstance()->setNear(MIN_NEAR_PLANE);
     gViewerWindow->setup3DViewport();
 
     if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 6ecf9dd0c4696fcc95d1e73c46c5050e928c2a33..732beab448ba98ca335c8e131d29663fdff4fdbf 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -6028,6 +6028,11 @@ LLViewerObject::ExtraParameter* LLViewerObject::createNewParameterEntry(U16 para
       {
           new_block = new LLRenderMaterialParams();
           break;
+      }
+      case LLNetworkData::PARAMS_REFLECTION_PROBE:
+      {
+          new_block = new LLReflectionProbeParams();
+          break;
       }
 	  default:
 	  {
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index a6597e32337379835d0f7dca167abb2587328bfc..6a606710406050a300bf7e3c1e42a86e77ed703c 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -5270,7 +5270,7 @@ BOOL LLViewerWindow::simpleSnapshot(LLImageRaw* raw, S32 image_width, S32 image_
 
 void display_cube_face();
 
-BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubearray, S32 cubeIndex, S32 face)
+BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubearray, S32 cubeIndex, S32 face, F32 near_clip)
 {
     // NOTE: implementation derived from LLFloater360Capture::capture360Images() and simpleSnapshot
     LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;
@@ -5299,6 +5299,7 @@ BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubea
     camera->setView(F_PI_BY_TWO);
     camera->yaw(0.0);
     camera->setOrigin(origin);
+    camera->setNear(near_clip);
 
     glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
     
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index ac7f8b2e3902c4dffd37d4a09312950c22a07d3b..c9cf7da8c7d97e7c2f0da75e172e66ee5610fcb1 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -368,7 +368,9 @@ class LLViewerWindow : public LLWindowCallbacks
     // origin - vantage point to take the snapshot from
     // cubearray - cubemap array for storing the results
     // index - cube index in the array to use (cube index, not face-layer)
-    BOOL cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubearray, S32 index, S32 face);
+    // face - which cube face to update
+    // near_clip - near clip setting to use
+    BOOL cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubearray, S32 index, S32 face, F32 near_clip);
 
     
     // special implementation of simpleSnapshot for reflection maps
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 784c0350fc4bb17ff8f5a033000ab8498a606e49..6aef9ee7c0d30dc59040fa12be98c77217741511 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -985,7 +985,12 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline)
 		// Add it to the pipeline mLightSet
 		gPipeline.setLight(mDrawable, TRUE);
 	}
-	
+
+    if (getIsReflectionProbe())
+    {
+        updateReflectionProbePtr();
+    }
+
 	updateRadius();
 	bool force_update = true; // avoid non-alpha mDistance update being optimized away
 	mDrawable->updateDistance(*LLViewerCamera::getInstance(), force_update);
@@ -3496,6 +3501,121 @@ F32 LLVOVolume::getLightCutoff() const
 	}
 }
 
+void LLVOVolume::setIsReflectionProbe(BOOL is_probe)
+{
+    BOOL was_probe = getIsReflectionProbe();
+    if (is_probe != was_probe)
+    {
+        if (is_probe)
+        {
+            setParameterEntryInUse(LLNetworkData::PARAMS_REFLECTION_PROBE, TRUE, true);
+        }
+        else
+        {
+            setParameterEntryInUse(LLNetworkData::PARAMS_REFLECTION_PROBE, FALSE, true);
+        }
+    }
+
+    updateReflectionProbePtr();
+}
+
+void LLVOVolume::setReflectionProbeAmbiance(F32 ambiance)
+{
+    LLReflectionProbeParams* param_block = (LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE);
+    if (param_block)
+    {
+        if (param_block->getAmbiance() != ambiance)
+        {
+            param_block->setAmbiance(ambiance);
+            parameterChanged(LLNetworkData::PARAMS_REFLECTION_PROBE, true);
+        }
+    }
+}
+
+void LLVOVolume::setReflectionProbeNearClip(F32 near_clip)
+{
+    LLReflectionProbeParams* param_block = (LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE);
+    if (param_block)
+    {
+        if (param_block->getClipDistance() != near_clip)
+        {
+            param_block->setClipDistance(near_clip);
+            parameterChanged(LLNetworkData::PARAMS_REFLECTION_PROBE, true);
+        }
+    }
+}
+
+void LLVOVolume::setReflectionProbeVolumeType(LLReflectionProbeParams::EInfluenceVolumeType volume_type)
+{
+    LLReflectionProbeParams* param_block = (LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE);
+    if (param_block)
+    {
+        if (param_block->getVolumeType() != volume_type)
+        {
+            param_block->setVolumeType(volume_type);
+            parameterChanged(LLNetworkData::PARAMS_REFLECTION_PROBE, true);
+        }
+    }
+}
+
+
+BOOL LLVOVolume::getIsReflectionProbe() const
+{
+    // HACK - make this object a Reflection Probe if a certain UUID is detected
+    static LLCachedControl<std::string> reflection_probe_id(gSavedSettings, "RenderReflectionProbeTextureHackID", "");
+    LLUUID probe_id(reflection_probe_id);
+
+    for (U8 i = 0; i < getNumTEs(); ++i)
+    {
+        if (getTE(i)->getID() == probe_id)
+        {
+            return true;
+        }
+    }
+    // END HACK
+
+    return getParameterEntryInUse(LLNetworkData::PARAMS_REFLECTION_PROBE);
+}
+
+F32 LLVOVolume::getReflectionProbeAmbiance() const
+{
+    const LLReflectionProbeParams* param_block = (const LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE);
+    if (param_block)
+    {
+        return param_block->getAmbiance();
+    }
+    else
+    {
+        return 0.f;
+    }
+}
+
+F32 LLVOVolume::getReflectionProbeNearClip() const
+{
+    const LLReflectionProbeParams* param_block = (const LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE);
+    if (param_block)
+    {
+        return param_block->getClipDistance();
+    }
+    else
+    {
+        return 0.f;
+    }
+}
+
+LLReflectionProbeParams::EInfluenceVolumeType LLVOVolume::getReflectionProbeVolumeType() const
+{
+    const LLReflectionProbeParams* param_block = (const LLReflectionProbeParams*)getParameterEntry(LLNetworkData::PARAMS_REFLECTION_PROBE);
+    if (param_block)
+    {
+        return param_block->getVolumeType();
+    }
+    else
+    {
+        return LLReflectionProbeParams::DEFAULT_VOLUME_TYPE;
+    }
+}
+
 U32 LLVOVolume::getVolumeInterfaceID() const
 {
 	if (mVolumeImpl)
@@ -4381,6 +4501,23 @@ void LLVOVolume::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_u
 			gPipeline.setLight(mDrawable, is_light);
 		}
 	}
+   
+    updateReflectionProbePtr();
+}
+
+void LLVOVolume::updateReflectionProbePtr()
+{
+    if (getIsReflectionProbe())
+    {
+        if (mReflectionProbe.isNull())
+        {
+            mReflectionProbe = gPipeline.mReflectionMapManager.registerViewerObject(this);
+        }
+    }
+    else if (mReflectionProbe.notNull())
+    {
+        mReflectionProbe = nullptr;
+    }
 }
 
 void LLVOVolume::setSelected(BOOL sel)
@@ -5690,24 +5827,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
                 bool is_pbr = false;
 #endif
 
-                // HACK - make this object a Reflection Probe if a certain UUID is detected
-                static LLCachedControl<std::string> reflection_probe_id(gSavedSettings, "RenderReflectionProbeTextureHackID", "");
-                if (facep->getTextureEntry()->getID() == LLUUID(reflection_probe_id))
-                {
-                    if (!vobj->mIsReflectionProbe)
-                    {
-                        vobj->mIsReflectionProbe = true;
-                        vobj->mReflectionProbe = gPipeline.mReflectionMapManager.registerViewerObject(vobj);
-                    }
-                }
-                else
-                {
-                    // not a refleciton probe any more
-                    vobj->mIsReflectionProbe = false;
-                    vobj->mReflectionProbe = nullptr;
-                }
-                // END HACK
-
 				//ALWAYS null out vertex buffer on rebuild -- if the face lands in a render
 				// batch, it will recover its vertex buffer reference from the spatial group
 				facep->setVertexBuffer(NULL);
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 4cb7a5481c6ff856fd55357d75da7419fca9d710..93a10781c2c7d3193a86ff552baca5d2aa1adea5 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -178,6 +178,9 @@ class LLVOVolume : public LLViewerObject
 	/*virtual*/ void	parameterChanged(U16 param_type, bool local_origin);
 	/*virtual*/ void	parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin);
 
+    // update mReflectionProbe based on isReflectionProbe()
+    void updateReflectionProbePtr();
+
 	/*virtual*/ U32		processUpdateMessage(LLMessageSystem *mesgsys,
 											void **user_data,
 											U32 block_num, const EObjectUpdateType update_type,
@@ -281,6 +284,17 @@ class LLVOVolume : public LLViewerObject
 	F32 getLightFalloff(const F32 fudge_factor = 1.f) const;
 	F32 getLightCutoff() const;
 	
+    // Reflection Probes
+    void setIsReflectionProbe(BOOL is_probe);
+    void setReflectionProbeAmbiance(F32 ambiance);
+    void setReflectionProbeNearClip(F32 near_clip);
+    void setReflectionProbeVolumeType(LLReflectionProbeParams::EInfluenceVolumeType volume_type);
+
+    BOOL getIsReflectionProbe() const;
+    F32 getReflectionProbeAmbiance() const;
+    F32 getReflectionProbeNearClip() const;
+    LLReflectionProbeParams::EInfluenceVolumeType getReflectionProbeVolumeType() const;
+
 	// Flexible Objects
 	U32 getVolumeInterfaceID() const;
 	virtual BOOL isFlexible() const;
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index 44bdcd86f91c56e9d9db045ff3d1e7975aa9848e..ae4eb642647d4384eee19b382c46d9947d78608b 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -2353,7 +2353,7 @@ even though the user gets a free copy.
              layout="topleft"
              left="10"
              name="Light Intensity"
-             top_pad="3"
+             top_delta="32"
              width="128" />
           <spinner bottom_delta="0"
                    decimal_digits="3"
@@ -2420,7 +2420,61 @@ even though the user gets a free copy.
                    mouse_opaque="true"
                    name="Light Ambiance"
                    width="120" />
-            <text
+          <check_box
+             height="16"
+             label="Reflection Probe"
+             layout="topleft"
+             left="10"
+             name="Reflection Probe Checkbox Ctrl"
+             tool_tip="Adjusts how objects within this volume receive reflections when PBR is enabled"
+             top_pad="15"
+             width="60" />
+          <combo_box
+			   height="19"
+			   top_delta="0"
+         left="144"
+			   follows="left|top"
+			   name="Probe Volume Type Ctrl"
+			   tool_tip="Choose the probe influence volume"
+			   width="108">
+            <combo_box.item
+             label="Sphere"
+             name="Sphere"
+             value="Sphere" />
+            <combo_box.item
+             label="Box"
+             name="Box"
+             value="Box"/>
+          </combo_box>
+          <spinner bottom_delta="19"
+                   decimal_digits="3"
+                   follows="left|top"
+                   height="16"
+                   increment="0.05"
+                   initial_value="0"
+                   label="Ambiance"
+                   label_width="55"
+                   left="10"
+                   max_val="1"
+                   min_val="0"
+                   mouse_opaque="true"
+                   name="Probe Ambiance"
+                   width="120" />
+          <spinner bottom_delta="0"
+                   decimal_digits="3"
+                   follows="left|top"
+                   height="16"
+                   increment="0.05"
+                   initial_value="0"
+                   label="Near Clip"
+                   label_width="55"
+                   left="144"
+                   max_val="1024"
+                   min_val="0"
+                   mouse_opaque="true"
+                   name="Probe Near Clip"
+                   width="120" />
+          <text
              type="string"
              length="1"
              follows="left|top"