diff --git a/autobuild.xml b/autobuild.xml
index fa4f118f8e..2cf5496bd0 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -483,18 +483,6 @@
emoji_shortcodes
+ license
+ MIT
+ license_file
+ LICENSES/emojibase-license.txt
+ copyright
+ Copyright 2017-2019 Miles Johnson.
version
6.1.0.579438
+ name
+ emoji_shortcodes
+ canonical_repo
+ https://github.com/secondlife/3p-emoji-shortcodes
+ description
+ Emoji shortcodes
expat
@@ -617,16 +617,6 @@
freetype
- copyright
- Copyright 2006, 2007, 2008, 2009, 2010 by David Turner, Robert Wilhelm, and Werner Lemberg.
- description
- Font rendering library
- license
- FreeType
- license_file
- LICENSES/freetype.txt
- name
- freetype
platforms
darwin64
@@ -672,8 +662,18 @@
windows64
+ license
+ FreeType
+ license_file
+ LICENSES/freetype.txt
+ copyright
+ Copyright 2006, 2007, 2008, 2009, 2010 by David Turner, Robert Wilhelm, and Werner Lemberg.
version
2.12.1.557becd
+ name
+ freetype
+ description
+ Font rendering library
glext
@@ -859,18 +859,6 @@
icu4c
- canonical_repo
- https://bitbucket.org/lindenlab/3p-icu4c
- copyright
- Copyright (c) 1995-2011 International Business Machines Corporation and others <http://source.icu-project.org>
- description
- ICU is a mature, widely used set of C/C++ and Java libraries providing Unicode and Globalization support for software applications. ICU is widely portable and gives applications the same results on all platforms and between C/C++ and Java software.
- license
- ICU, permissive non-copyleft free software license
- license_file
- LICENSES/icu.txt
- name
- icu4c
platforms
darwin64
@@ -902,8 +890,20 @@
windows64
+ license
+ ICU, permissive non-copyleft free software license
+ license_file
+ LICENSES/icu.txt
+ copyright
+ Copyright (c) 1995-2011 International Business Machines Corporation and others <http://source.icu-project.org>
version
4.8.1-7d08d82
+ name
+ icu4c
+ canonical_repo
+ https://bitbucket.org/lindenlab/3p-icu4c
+ description
+ ICU is a mature, widely used set of C/C++ and Java libraries providing Unicode and Globalization support for software applications. ICU is widely portable and gives applications the same results on all platforms and between C/C++ and Java software.
jpegencoderbasic
@@ -1389,15 +1389,6 @@
llca
- copyright
- Copyright (c) 2016, Linden Research, Inc.; data provided by the Mozilla NSS Project.
-
- license
- mit
- license_file
- LICENSES/ca-license.txt
- name
- llca
platforms
common
@@ -1415,8 +1406,17 @@
common
+ license
+ mit
+ license_file
+ LICENSES/ca-license.txt
+ copyright
+ Copyright (c) 2016, Linden Research, Inc.; data provided by the Mozilla NSS Project.
+
version
202402012004.0
+ name
+ llca
llphysicsextensions_source
@@ -1786,18 +1786,6 @@
nanosvg
- canonical_repo
- https://bitbucket.org/lindenlab/3p-nanosvg
- copyright
- Copyright (c) 2013-14 Mikko Mononen
- description
- NanoSVG is a simple single-header-file SVG parser and rasterizer
- license
- Zlib
- license_file
- LICENSES/nanosvg.txt
- name
- nanosvg
platforms
darwin64
@@ -1837,8 +1825,20 @@
windows64
+ license
+ Zlib
+ license_file
+ LICENSES/nanosvg.txt
+ copyright
+ Copyright (c) 2013-14 Mikko Mononen
version
2022.09.27
+ name
+ nanosvg
+ canonical_repo
+ https://bitbucket.org/lindenlab/3p-nanosvg
+ description
+ NanoSVG is a simple single-header-file SVG parser and rasterizer
nghttp2
@@ -2254,14 +2254,12 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
- creds
- github
hash
- cc7c5bf53f83cff81d874ad66394df0991bd432c
+ 1e70b06fe6eb9796097010871b32d8e95167e373
hash_algorithm
sha1
url
- https://api.github.com/repos/secondlife/3p-slvoice/releases/assets/108299352
+ https://automated-builds-secondlife-com.s3.amazonaws.com/gh/secondlife/3p-slvoice/slvoice-4.10.0000.32327.5fc3fe7c.5942f08-darwin64-5942f08.tar.zst
name
darwin64
@@ -2282,14 +2280,12 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
- creds
- github
hash
- 0c205371bb1731a9812b00556037729fdc057cbc
+ ddfb7c30d9756915e8b26f44e2ee3a69ee87fb9a
hash_algorithm
sha1
url
- https://api.github.com/repos/secondlife/3p-slvoice/releases/assets/108299356
+ https://automated-builds-secondlife-com.s3.amazonaws.com/gh/secondlife/3p-slvoice/slvoice-4.10.0000.32327.5fc3fe7c.5942f08-windows64-5942f08.tar.zst
name
windows64
@@ -2302,7 +2298,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
copyright
2010 Vivox, including audio coding using Polycom¨ Siren14TM (ITU-T Rec. G.722.1 Annex C)
version
- 4.10.0000.32327.5fc3fe7c.571099
+ 4.10.0000.32327.5fc3fe7c.5942f08
name
slvoice
description
@@ -2548,16 +2544,6 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
viewer-fonts
- copyright
- Copyright 2016-2022 Brad Erickson CC-BY-4.0/MIT, Copyright 2016-2022 Twitter, Inc. CC-BY-4.0, Copyright 2013 Joe Loughry and Terence Eden MIT
- description
- Viewer fonts
- license
- Various open source
- license_file
- LICENSES/fonts.txt
- name
- viewer-fonts
platforms
darwin64
@@ -2585,8 +2571,18 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
windows64
+ license
+ Various open source
+ license_file
+ LICENSES/fonts.txt
+ copyright
+ Copyright 2016-2022 Brad Erickson CC-BY-4.0/MIT, Copyright 2016-2022 Twitter, Inc. CC-BY-4.0, Copyright 2013 Joe Loughry and Terence Eden MIT
version
1.579464
+ name
+ viewer-fonts
+ description
+ Viewer fonts
viewer-manager
diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp
index 219c65fbb8..23b30bcc57 100644
--- a/indra/llcommon/llcoros.cpp
+++ b/indra/llcommon/llcoros.cpp
@@ -140,7 +140,7 @@ LLCoros::LLCoros():
// Previously we used
// boost::context::guarded_stack_allocator::default_stacksize();
// empirically this is insufficient.
- mStackSize(900*1024),
+ mStackSize(1024*1024),
// mCurrent does NOT own the current CoroData instance -- it simply
// points to it. So initialize it with a no-op deleter.
mCurrent{ [](CoroData*){} }
diff --git a/indra/llprimitive/llgltfmaterial.h b/indra/llprimitive/llgltfmaterial.h
index 1b0ab19f71..23a39593cf 100644
--- a/indra/llprimitive/llgltfmaterial.h
+++ b/indra/llprimitive/llgltfmaterial.h
@@ -125,7 +125,6 @@ public:
// heightmaps cannot currently be described as finite enclosed
// volumes.
// See also LLPanelRegionTerrainInfo::validateMaterials
-
public:
// get a UUID based on a hash of this LLGLTFMaterial
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index 3e1e235fcd..8950770172 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -75,6 +75,7 @@ RenderGLMultiThreadedTextures 1 0
RenderGLMultiThreadedMedia 1 1
RenderReflectionProbeResolution 1 128
RenderScreenSpaceReflections 1 1
+RenderMirrors 1 1
//
@@ -251,8 +252,8 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 1
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 3
-RenderMirrors 1 0
-RenderHeroProbeResolution 1 1024
+RenderMirrors 1 1
+RenderHeroProbeResolution 1 512
RenderHeroProbeDistance 1 8
RenderHeroProbeUpdateRate 1 2
RenderHeroProbeConservativeUpdateMultiplier 1 8
@@ -287,7 +288,7 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 1
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 3
-RenderMirrors 1 0
+RenderMirrors 1 1
RenderHeroProbeResolution 1 1024
RenderHeroProbeDistance 1 16
RenderHeroProbeUpdateRate 1 1
diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt
index 2ffefadcc1..8c71235f37 100644
--- a/indra/newview/featuretable_mac.txt
+++ b/indra/newview/featuretable_mac.txt
@@ -74,6 +74,7 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 2
RenderScreenSpaceReflections 1 1
RenderReflectionProbeLevel 1 3
+RenderMirrors 1 1
//
// Low Graphics Settings
@@ -249,8 +250,8 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 1
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 1
-RenderMirrors 1 0
-RenderHeroProbeResolution 1 1024
+RenderMirrors 1 1
+RenderHeroProbeResolution 1 512
RenderHeroProbeDistance 1 8
RenderHeroProbeUpdateRate 1 2
RenderHeroProbeConservativeUpdateMultiplier 1 8
@@ -285,8 +286,8 @@ RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 1
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 2
-RenderMirrors 1 0
-RenderHeroProbeResolution 1 1024
+RenderMirrors 1 1
+RenderHeroProbeResolution 1 512
RenderHeroProbeDistance 1 16
RenderHeroProbeUpdateRate 1 1
RenderHeroProbeConservativeUpdateMultiplier 1 4
@@ -322,7 +323,7 @@ RenderReflectionProbeDetail 1 1
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 3
RenderMirrors 1 1
-RenderHeroProbeResolution 1 2048
+RenderHeroProbeResolution 1 1024
RenderHeroProbeDistance 1 16
RenderHeroProbeUpdateRate 1 1
RenderHeroProbeConservativeUpdateMultiplier 1 4
diff --git a/indra/newview/llheroprobemanager.cpp b/indra/newview/llheroprobemanager.cpp
index cd7ee4736a..af66867e7c 100644
--- a/indra/newview/llheroprobemanager.cpp
+++ b/indra/newview/llheroprobemanager.cpp
@@ -113,22 +113,40 @@ void LLHeroProbeManager::update()
LLVector4a probe_pos;
LLVector3 camera_pos = LLViewerCamera::instance().mOrigin;
F32 near_clip = 0.1f;
+ bool probe_present = false;
+ LLQuaternion cameraOrientation = LLViewerCamera::instance().getQuaternion();
+ LLVector3 cameraDirection = LLVector3::z_axis * cameraOrientation;
+
if (mHeroVOList.size() > 0)
{
// Find our nearest hero candidate.
-
float last_distance = 99999.f;
-
+ float camera_center_distance = 99999.f;
for (auto vo : mHeroVOList)
{
if (vo && !vo->isDead() && vo->mDrawable.notNull())
{
float distance = (LLViewerCamera::instance().getOrigin() - vo->getPositionAgent()).magVec();
- if (distance < last_distance)
+ float center_distance = cameraDirection * (vo->getPositionAgent() - camera_pos);
+
+ if (distance > LLViewerCamera::instance().getFar())
+ continue;
+
+ LLVector4a center;
+ center.load3(vo->getPositionAgent().mV);
+ LLVector4a size;
+
+ size.load3(vo->getScale().mV);
+
+ bool visible = LLViewerCamera::instance().AABBInFrustum(center, size);
+
+ if (distance < last_distance && center_distance < camera_center_distance && visible)
{
- mNearestHero = vo;
- last_distance = distance;
- }
+ probe_present = true;
+ mNearestHero = vo;
+ last_distance = distance;
+ camera_center_distance = center_distance;
+ }
}
else
{
@@ -136,6 +154,10 @@ void LLHeroProbeManager::update()
}
}
+ // Don't even try to do anything if we didn't find a single mirror present.
+ if (!probe_present)
+ return;
+
if (mNearestHero != nullptr && !mNearestHero->isDead() && mNearestHero->mDrawable.notNull())
{
LLVector3 hero_pos = mNearestHero->getPositionAgent();
@@ -152,14 +174,12 @@ void LLHeroProbeManager::update()
mCurrentClipPlane.setVec(hero_pos, face_normal);
mMirrorPosition = hero_pos;
mMirrorNormal = face_normal;
-
probe_pos.load3(point.mV);
- // Collect the list of faces that need updating based upon the camera's rotation.
- LLVector3 cam_direction = LLVector3(0, 0, 1) * LLViewerCamera::instance().getQuaternion();
- cam_direction.normalize();
+ // Detect visible faces of a cube based on camera direction and distance
+ // Define the cube faces
static LLVector3 cubeFaces[6] = {
LLVector3(1, 0, 0),
LLVector3(-1, 0, 0),
@@ -169,17 +189,21 @@ void LLHeroProbeManager::update()
LLVector3(0, 0, -1)
};
+ // Iterate through each face of the cube
for (int i = 0; i < 6; i++)
{
- float shouldUpdate = fminf(1, (fmaxf(-1, cam_direction * cubeFaces[i]) * 0.5 + 0.5));
-
- int updateRate = ceilf((1 - shouldUpdate) * gPipeline.RenderHeroProbeConservativeUpdateMultiplier);
-
- // Chances are this is a face that's non-visible to the camera when it's being reflected.
- // Set it to 0. It will be skipped below.
- if (updateRate == gPipeline.RenderHeroProbeConservativeUpdateMultiplier)
+ float cube_facing = fmax(-1, fmin(1.0f, cameraDirection * cubeFaces[i])) * 0.6 + 0.4;
+
+ float updateRate;
+ if (cube_facing < 0.1f)
+ {
updateRate = 0;
-
+ }
+ else
+ {
+ updateRate = ceilf(cube_facing * gPipeline.RenderHeroProbeConservativeUpdateMultiplier);
+ }
+
mFaceUpdateList[i] = updateRate;
}
}
@@ -199,6 +223,7 @@ void LLHeroProbeManager::update()
static LLCachedControl sDetail(gSavedSettings, "RenderHeroReflectionProbeDetail", -1);
static LLCachedControl sLevel(gSavedSettings, "RenderHeroReflectionProbeLevel", 3);
+ if (mNearestHero != nullptr)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("hpmu - realtime");
// Probe 0 is always our mirror probe.
@@ -208,13 +233,16 @@ void LLHeroProbeManager::update()
gPipeline.mReflectionMapManager.mRadiancePass = true;
mRenderingMirror = true;
+
+ doOcclusion();
+
for (U32 j = 0; j < mProbes.size(); j++)
{
for (U32 i = 0; i < 6; ++i)
{
if (mFaceUpdateList[i] > 0 && mCurrentProbeUpdateFrame % mFaceUpdateList[i] == 0)
{
- updateProbeFace(mProbes[j], i, near_clip);
+ updateProbeFace(mProbes[j], i, mNearestHero->getReflectionProbeIsDynamic() && sDetail > 0, near_clip);
mCurrentProbeUpdateFrame = 0;
}
}
@@ -239,18 +267,17 @@ void LLHeroProbeManager::update()
// The next six passes render the scene with both radiance and irradiance into the same scratch space cube map and generate a simple mip chain.
// At the end of these passes, a radiance map is generated for this probe and placed into the radiance cube map array at the index for this probe.
// In effect this simulates single-bounce lighting.
-void LLHeroProbeManager::updateProbeFace(LLReflectionMap* probe, U32 face, F32 near_clip)
+void LLHeroProbeManager::updateProbeFace(LLReflectionMap* probe, U32 face, bool is_dynamic, F32 near_clip)
{
// hacky hot-swap of camera specific render targets
gPipeline.mRT = &gPipeline.mHeroProbeRT;
- probe->update(mRenderTarget.getWidth(), face, true, near_clip);
+ probe->update(mRenderTarget.getWidth(), face, is_dynamic, near_clip);
gPipeline.mRT = &gPipeline.mMainRT;
S32 sourceIdx = mReflectionProbeCount;
-
// Unlike the reflectionmap manager, all probes are considered "realtime" for hero probes.
sourceIdx += 1;
@@ -371,8 +398,6 @@ void LLHeroProbeManager::generateRadiance(LLReflectionMap* probe)
static LLStaticHashedString sSourceIdx("sourceIdx");
{
-
-
// generate radiance map (even if this is not the irradiance map, we need the mip chain for the irradiance map)
gHeroRadianceGenProgram.bind();
mVertexBuffer->setBuffer();
diff --git a/indra/newview/llheroprobemanager.h b/indra/newview/llheroprobemanager.h
index d5e720e8e8..5df146f2f1 100644
--- a/indra/newview/llheroprobemanager.h
+++ b/indra/newview/llheroprobemanager.h
@@ -116,7 +116,7 @@ private:
// update the specified face of the specified probe
- void updateProbeFace(LLReflectionMap* probe, U32 face, F32 near_clip);
+ void updateProbeFace(LLReflectionMap* probe, U32 face, bool is_dynamic, F32 near_clip);
void generateRadiance(LLReflectionMap *probe);
// list of active reflection maps
diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp
index ac7bf0c2dc..ee0b001843 100644
--- a/indra/newview/llpanelvolume.cpp
+++ b/indra/newview/llpanelvolume.cpp
@@ -424,19 +424,21 @@ void LLPanelVolume::getState( )
volume_type = "Sphere";
}
- std::string update_type;
- if (volobjp->getReflectionProbeIsDynamic())
+
+ std::string update_type = "Static";
+
+ if (volobjp->getReflectionProbeIsDynamic() && !volobjp->getReflectionProbeIsMirror())
{
update_type = "Dynamic";
}
- else if (volobjp->getReflectionProbeIsMirror())
+ else if (volobjp->getReflectionProbeIsMirror() && !volobjp->getReflectionProbeIsDynamic())
{
update_type = "Mirror";
}
- else
- {
- update_type = "Static";
+ else if (volobjp->getReflectionProbeIsDynamic() && volobjp->getReflectionProbeIsMirror())
+ {
+ update_type = "Dynamic Mirror";
}
getChildView("Probe Ambiance")->setEnabled(update_type != "Mirror");
@@ -1200,6 +1202,7 @@ void LLPanelVolume::onCopyLight()
clipboard["reflection_probe"]["ambiance"] = volobjp->getReflectionProbeAmbiance();
clipboard["reflection_probe"]["near_clip"] = volobjp->getReflectionProbeNearClip();
clipboard["reflection_probe"]["dynamic"] = volobjp->getReflectionProbeIsDynamic();
+ clipboard["reflection_probe"]["mirror"] = volobjp->getReflectionProbeIsMirror();
}
mClipboardParams["light"] = clipboard;
@@ -1257,6 +1260,7 @@ void LLPanelVolume::onPasteLight()
volobjp->setReflectionProbeAmbiance((F32)clipboard["reflection_probe"]["ambiance"].asReal());
volobjp->setReflectionProbeNearClip((F32)clipboard["reflection_probe"]["near_clip"].asReal());
volobjp->setReflectionProbeIsDynamic(clipboard["reflection_probe"]["dynamic"].asBoolean());
+ volobjp->setReflectionProbeIsMirror(clipboard["reflection_probe"]["mirror"].asBoolean());
}
else
{
@@ -1428,11 +1432,13 @@ void LLPanelVolume::onCommitProbe(LLUICtrl* ctrl, void* userdata)
std::string update_type = self->getChild("Probe Update Type")->getValue().asString();
- volobjp->setReflectionProbeIsDynamic(update_type == "Dynamic");
- volobjp->setReflectionProbeIsMirror(update_type == "Mirror");
+ bool is_mirror = update_type.find("Mirror") != std::string::npos;
- self->getChildView("Probe Ambiance")->setEnabled(update_type != "Mirror");
- self->getChildView("Probe Near Clip")->setEnabled(update_type != "Mirror");
+ volobjp->setReflectionProbeIsDynamic(update_type.find("Dynamic") != std::string::npos);
+ volobjp->setReflectionProbeIsMirror(is_mirror);
+
+ self->getChildView("Probe Ambiance")->setEnabled(!is_mirror);
+ self->getChildView("Probe Near Clip")->setEnabled(!is_mirror);
std::string shape_type = self->getChild("Probe Volume Type")->getValue().asString();
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 8b5ffcb5e9..6668384f52 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -2466,14 +2466,6 @@ void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features)
gSavedSettings.setS32("max_texture_dimension_Y", 1024);
}
- bool mirrors_enabled = false;
- if (features.has("MirrorsEnabled"))
- {
- mirrors_enabled = features["MirrorsEnabled"].asBoolean();
- }
-
- gSavedSettings.setBOOL("RenderMirrors", mirrors_enabled);
-
if (features.has("PBRTerrainEnabled"))
{
bool enabled = features["PBRTerrainEnabled"];
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 78df9aa9cf..a4835849eb 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -3422,8 +3422,15 @@ bool LLVOVolume::setReflectionProbeIsMirror(bool is_mirror)
{
if (param_block->getIsMirror() != is_mirror)
{
+ LL_INFOS() << "Setting reflection probe mirror to " << is_mirror << LL_ENDL;
param_block->setIsMirror(is_mirror);
parameterChanged(LLNetworkData::PARAMS_REFLECTION_PROBE, true);
+
+ if (!is_mirror)
+ gPipeline.mHeroProbeManager.unregisterViewerObject(this);
+ else
+ gPipeline.mHeroProbeManager.registerViewerObject(this);
+
return true;
}
}
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 66797cd127..d17bb904cf 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -2268,7 +2268,8 @@ static LLTrace::BlockTimerStatHandle FTM_CULL("Object Culling");
// static
bool LLPipeline::isWaterClip()
{
- return (!sRenderTransparentWater || gCubeSnapshot) && !sRenderingHUDs;
+ // We always pretend that we're not clipping water when rendering mirrors.
+ return (gPipeline.mHeroProbeManager.isMirrorPass()) ? false : (!sRenderTransparentWater || gCubeSnapshot) && !sRenderingHUDs;
}
void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result)
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index 3ee4a354d4..e43143c8c3 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -2549,7 +2549,7 @@ even though the user gets a free copy.
follows="left|top"
name="Probe Volume Type"
tool_tip="Choose the probe influence volume"
- width="108">
+ width="140">
+ tool_tip="Determines how the probe updates. Static updates the slowest and without avatars. Dynamic updates more frequently, with avatars visible in the probes. Mirror (Environment) turns this probe into a realtime planar projected probe that only reflects the environment, but does not calculate ambiance. Mirror (Everything) is similar to Mirror (Environment), but it reflects particles and avatars."
+ width="140">
+