summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/app_settings/settings.xml44
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/materialV.glsl17
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl27
-rw-r--r--indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl2
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/materialF.glsl30
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl1
-rw-r--r--indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl28
-rw-r--r--indra/newview/llappviewer.cpp1
-rw-r--r--indra/newview/lldrawable.h1
-rw-r--r--indra/newview/lldrawpoolmaterials.cpp13
-rw-r--r--indra/newview/llface.cpp14
-rw-r--r--indra/newview/llface.h5
-rw-r--r--indra/newview/llfetchedgltfmaterial.cpp1
-rw-r--r--indra/newview/llheroprobemanager.cpp584
-rw-r--r--indra/newview/llheroprobemanager.h142
-rw-r--r--indra/newview/llpanelface.cpp1
-rw-r--r--indra/newview/llpanelface.h3
-rw-r--r--indra/newview/llpanelvolume.cpp30
-rw-r--r--indra/newview/llpanelvolume.h2
-rw-r--r--indra/newview/llreflectionmap.cpp7
-rw-r--r--indra/newview/llreflectionmap.h13
-rw-r--r--indra/newview/llreflectionmapmanager.cpp29
-rw-r--r--indra/newview/llreflectionmapmanager.h11
-rw-r--r--indra/newview/llviewerdisplay.cpp2
-rw-r--r--indra/newview/llviewerobject.cpp51
-rw-r--r--indra/newview/llviewerobject.h5
-rw-r--r--indra/newview/llviewershadermgr.cpp2
-rw-r--r--indra/newview/llviewerwindow.cpp15
-rw-r--r--indra/newview/llviewerwindow.h3
-rw-r--r--indra/newview/llvovolume.cpp57
-rw-r--r--indra/newview/llvovolume.h7
-rw-r--r--indra/newview/pipeline.cpp31
-rw-r--r--indra/newview/pipeline.h2
-rw-r--r--indra/newview/skins/default/xui/en/floater_tools.xml10
35 files changed, 1139 insertions, 54 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 8eef7cd9d4..e180f8bf43 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -519,6 +519,7 @@ set(viewer_SOURCE_FILES
llrecentpeople.cpp
llreflectionmap.cpp
llreflectionmapmanager.cpp
+ llheroprobemanager.cpp
llregioninfomodel.cpp
llregionposition.cpp
llremoteparcelrequest.cpp
@@ -1158,6 +1159,7 @@ set(viewer_HEADER_FILES
llrecentpeople.h
llreflectionmap.h
llreflectionmapmanager.h
+ llheroprobemanager.h
llregioninfomodel.h
llregionposition.h
llremoteparcelrequest.h
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 5d8d4b199c..a6b9aa0526 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -9186,6 +9186,17 @@
<real>0.00</real>
</array>
</map>
+ <key>RenderMirrors</key>
+ <map>
+ <key>Comment</key>
+ <string>Renders realtime mirrors.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
<key>RenderScreenSpaceReflections</key>
<map>
<key>Comment</key>
@@ -10390,6 +10401,39 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>RenderHeroProbeResolution</key>
+ <map>
+ <key>Comment</key>
+ <string>Resolution to render hero probes used for mirrors, water, etc.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>1024</integer>
+ </map>
+ <key>RenderHeroProbeDistance</key>
+ <map>
+ <key>Comment</key>
+ <string>Distance in meters for hero probes to render out to.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>16</real>
+ </map>
+ <key>RenderHeroProbeNearClipOffset</key>
+ <map>
+ <key>Comment</key>
+ <string>Distance offset in meters for hero probes to near clip.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>2.1</real>
+ </map>
<key>RenderReflectionProbeVolumes</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl
index 7cdddfe8db..65706e2c3f 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl
@@ -28,25 +28,18 @@
#define DIFFUSE_ALPHA_MODE_MASK 2
#define DIFFUSE_ALPHA_MODE_EMISSIVE 3
-#ifdef HAS_SKIN
uniform mat4 modelview_matrix;
uniform mat4 projection_matrix;
+uniform mat4 modelview_projection_matrix;
+
+#ifdef HAS_SKIN
mat4 getObjectSkinnedTransform();
#else
uniform mat3 normal_matrix;
-uniform mat4 modelview_projection_matrix;
-#endif
-
-#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
-
-#if !defined(HAS_SKIN)
-uniform mat4 modelview_matrix;
#endif
out vec3 vary_position;
-#endif
-
uniform mat4 texture_matrix0;
in vec3 position;
@@ -133,10 +126,8 @@ void main()
vertex_color = diffuse_color;
-#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
#if !defined(HAS_SKIN)
- vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz;
-#endif
+ vary_position = (projection_matrix*vec4(position.xyz, 1.0)).xyz;
#endif
}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl
index faa273b834..9b98a37925 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pbropaqueF.glsl
@@ -58,10 +58,37 @@ vec2 encode_normal(vec3 n);
vec3 linear_to_srgb(vec3 c);
vec3 srgb_to_linear(vec3 c);
+uniform vec4 clipPlane;
+uniform float clipSign;
+uniform float mirror_flag;
+void applyClip(vec3 pos)
+{
+ if (mirror_flag > 0)
+ {
+ // TODO: make this less branchy
+ if (clipSign > 0)
+ {
+ if ((dot(pos.xyz, clipPlane.xyz) + clipPlane.w) < 0.0)
+ {
+ discard;
+ }
+ }
+ else
+ {
+ if ((dot(pos.xyz, clipPlane.xyz) + clipPlane.w) > 0.0)
+ {
+ discard;
+ }
+ }
+ }
+}
+
uniform mat3 normal_matrix;
void main()
{
+ applyClip(vary_position);
+
vec4 basecolor = texture(diffuseMap, base_color_texcoord.xy).rgba;
if (basecolor.a < minimum_alpha)
{
diff --git a/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl b/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl
index 9ecdf0bf77..cb6f34713c 100644
--- a/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/radianceGenF.glsl
@@ -38,6 +38,7 @@ in vec3 vary_dir;
uniform float mipLevel;
uniform int u_width;
uniform float max_probe_lod;
+uniform float probe_strength;
// =============================================================================================================
@@ -163,5 +164,6 @@ void main()
{
vec3 N = normalize(vary_dir);
frag_color = max(prefilterEnvMap(N), vec4(0));
+ frag_color.a *= probe_strength;
}
// =============================================================================================================
diff --git a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl
index acff03ec4b..db0daa9b7e 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/materialF.glsl
@@ -49,6 +49,23 @@ void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float
vec3 srgb_to_linear(vec3 cs);
vec3 linear_to_srgb(vec3 cs);
+uniform vec4 clipPlane;
+uniform float clipSign;
+uniform float mirror_flag;
+void applyClip(vec3 pos)
+{
+ float funnyClip = 0;
+ if (mirror_flag > 0)
+ {
+ if ((dot(pos.xyz, clipPlane.xyz) + clipPlane.w) > 0.0)
+ {
+ discard;
+ }
+ }
+}
+
+in vec3 vary_position;
+
#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
out vec4 frag_color;
@@ -70,12 +87,12 @@ uniform vec4 morphFactor;
uniform vec3 camPosLocal;
uniform mat3 env_mat;
+uniform float is_mirror;
+
uniform vec3 sun_dir;
uniform vec3 moon_dir;
in vec2 vary_fragcoord;
-in vec3 vary_position;
-
uniform mat4 proj_mat;
uniform mat4 inv_proj;
uniform vec2 screen_res;
@@ -289,6 +306,7 @@ float getShadow(vec3 pos, vec3 norm)
void main()
{
+ applyClip(vary_position);
waterClip();
// diffcol == diffuse map combined with vertex color
@@ -416,9 +434,15 @@ void main()
#else // mode is not DIFFUSE_ALPHA_MODE_BLEND, encode to gbuffer
// deferred path // See: C++: addDeferredAttachment(), shader: softenLightF.glsl
+
+ float flag = GBUFFER_FLAG_HAS_ATMOS;
+
+ if (mirror_flag > 0)
+ flag = 1;
+
frag_data[0] = vec4(diffcol.rgb, emissive); // gbuffer is sRGB for legacy materials
frag_data[1] = vec4(spec.rgb, glossiness); // XYZ = Specular color. W = Specular exponent.
- frag_data[2] = vec4(encode_normal(norm), env, GBUFFER_FLAG_HAS_ATMOS);; // XY = Normal. Z = Env. intensity. W = 1 skip atmos (mask off fog)
+ frag_data[2] = vec4(encode_normal(norm), env, flag);; // XY = Normal. Z = Env. intensity. W = 1 skip atmos (mask off fog)
frag_data[3] = vec4(0);
#endif
}
diff --git a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl
index 906e66ecc8..d9dc83bb10 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl
@@ -31,6 +31,7 @@ float tapScreenSpaceReflection(int totalSamples, vec2 tc, vec3 viewPos, vec3 n,
uniform samplerCubeArray reflectionProbes;
uniform samplerCubeArray irradianceProbes;
+
uniform sampler2D sceneMap;
uniform int cube_snapshot;
uniform float max_probe_lod;
diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
index 35e99c5bd2..8b7aea24ed 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
@@ -32,6 +32,14 @@ uniform sampler2D specularRect;
uniform sampler2D normalMap;
uniform sampler2D emissiveRect; // PBR linear packed Occlusion, Roughness, Metal. See: pbropaqueF.glsl
+uniform samplerCubeArray heroProbes;
+
+layout (std140) uniform HeroProbeData
+{
+ vec4 heroPosition[1];
+ int heroProbeCount;
+};
+
const float M_PI = 3.14159265;
#if defined(HAS_SUN_SHADOW) || defined(HAS_SSAO)
@@ -108,8 +116,8 @@ vec3 pbrBaseLight(vec3 diffuseColor,
vec3 additive,
vec3 atten);
-vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor,
- float perceptualRoughness,
+vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor,
+ float perceptualRoughness,
float metallic,
vec3 n, // normal
vec3 v, // surface point to camera
@@ -182,9 +190,9 @@ void main()
vec3 irradiance = vec3(0);
vec3 radiance = vec3(0);
- if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR))
+ if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_PBR) || GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_MIRROR))
{
- vec3 orm = texture(specularRect, tc).rgb;
+ vec3 orm = texture(specularRect, tc).rgb;
float perceptualRoughness = orm.g;
float metallic = orm.b;
float ao = orm.r;
@@ -204,10 +212,16 @@ void main()
vec3 v = -normalize(pos.xyz);
color = pbrBaseLight(diffuseColor, specularColor, metallic, v, norm.xyz, perceptualRoughness, light_dir, sunlit_linear, scol, radiance, irradiance, colorEmissive, ao, additive, atten);
+ vec3 refnormpersp = reflect(pos.xyz, norm.xyz);
+
+ if (GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_MIRROR))
+ color = textureLod(heroProbes, vec4(env_mat * refnormpersp, 0), (1.0 - gloss) * 11).xyz * specularColor;
+
if (do_atmospherics)
{
color = atmosFragLightingLinear(color, additive, atten);
}
+
}
else if (!GET_GBUFFER_FLAG(GBUFFER_FLAG_HAS_ATMOS))
{
@@ -265,6 +279,9 @@ void main()
// add radiance map
applyGlossEnv(color, glossenv, spec, pos.xyz, norm.xyz);
+
+ color = textureLod(heroProbes, vec4(env_mat * refnormpersp, 0), (1.0 - spec.a) * 11).xyz * spec.rgb;
+
}
color.rgb = mix(color.rgb, baseColor.rgb, baseColor.a);
@@ -280,14 +297,11 @@ void main()
color = atmosFragLightingLinear(color, additive, atten);
}
}
-
-
#ifdef WATER_FOG
vec4 fogged = applyWaterFogViewLinear(pos.xyz, vec4(color, bloom));
color = fogged.rgb;
#endif
-
frag_color.rgb = max(color.rgb, vec3(0)); //output linear since local lights will be added to this shader's results
frag_color.a = 0.0;
}
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index e20658d327..fbf52ad2d8 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1518,6 +1518,7 @@ bool LLAppViewer::doFrame()
LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df Snapshot");
pingMainloopTimeout("Main:Snapshot");
gPipeline.mReflectionMapManager.update();
+ gPipeline.mHeroProbeManager.update();
LLFloaterSnapshot::update(); // take snapshots
LLFloaterSimpleSnapshot::update();
gGLActive = FALSE;
diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h
index 970e8c8b2a..fc182fc2e2 100644
--- a/indra/newview/lldrawable.h
+++ b/indra/newview/lldrawable.h
@@ -286,6 +286,7 @@ public:
ANIMATED_CHILD = 0x01000000,
ACTIVE_CHILD = 0x02000000,
FOR_UNLOAD = 0x04000000, //should be unload from memory
+ MIRROR = 0x08000000, // Used as a mirror, needs a hero probe position to be calculated.
} EDrawableFlags;
public:
diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp
index 6a7e05ac74..373103ce0a 100644
--- a/indra/newview/lldrawpoolmaterials.cpp
+++ b/indra/newview/lldrawpoolmaterials.cpp
@@ -190,6 +190,19 @@ void LLDrawPoolMaterials::renderDeferred(S32 pass)
glUniform4fv(specular, 1, lastSpecular.mV);
}
+ if (gPipeline.mHeroProbeManager.isMirrorPass())
+ {
+ glUniform1f(LLShaderMgr::MIRROR_FLAG, 1);
+ }
+
+ LLVector4 clipPlane = LLVector4(gPipeline.mHeroProbeManager.currentMirrorClip()[0],
+ gPipeline.mHeroProbeManager.currentMirrorClip()[1],
+ gPipeline.mHeroProbeManager.currentMirrorClip()[2],
+ gPipeline.mHeroProbeManager.currentMirrorClip()[3]);
+
+ mShader->uniform4fv(LLShaderMgr::CLIP_PLANE,
+ 1, clipPlane.mV);
+
LLVOAvatar* lastAvatar = nullptr;
for (LLCullResult::drawinfo_iterator i = begin; i != end; )
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index c1776705f9..2c04224fa0 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -488,6 +488,11 @@ U16 LLFace::getGeometry(LLStrider<LLVector3> &vertices, LLStrider<LLVector3> &no
return mGeomIndex;
}
+LLVector3 LLFace::getAverageNormal()
+{
+ return mAverageNormal;
+}
+
void LLFace::updateCenterAgent()
{
if (mDrawablep->isActive())
@@ -1889,14 +1894,21 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
F32* normals = (F32*) norm.get();
LLVector4a* src = vf.mNormals;
LLVector4a* end = src+num_vertices;
-
+
+ LLVector4a normal_total;
+
while (src < end)
{
LLVector4a normal;
mat_normal.rotate(*src++, normal);
normal.store4a(normals);
+ normal_total.add(normal);
normals += 4;
}
+
+ normal_total.div(LLVector4a(num_vertices));
+
+ mAverageNormal = LLVector3(normal_total[0], normal_total[1], normal_total[2]);
}
if (rebuild_tangent)
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index eb3b47d6d6..d4f4313073 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -176,6 +176,8 @@ public:
LLStrider<LLVector3> &normals,
LLStrider<LLVector2> &texCoords,
LLStrider<U16> &indices);
+
+ LLVector3 getAverageNormal();
S32 getColors(LLStrider<LLColor4U> &colors);
S32 getIndices(LLStrider<U16> &indices);
@@ -278,6 +280,9 @@ private:
U32 mIndicesCount;
U32 mIndicesIndex; // index into mVertexBuffer's index array
S32 mIndexInTex[LLRender::NUM_TEXTURE_CHANNELS];
+
+ LLVector3 mAverageNormal;
+ bool mHasAverageNormal;
LLXformMatrix* mXform;
diff --git a/indra/newview/llfetchedgltfmaterial.cpp b/indra/newview/llfetchedgltfmaterial.cpp
index 1fb3577dd7..9590066b55 100644
--- a/indra/newview/llfetchedgltfmaterial.cpp
+++ b/indra/newview/llfetchedgltfmaterial.cpp
@@ -128,6 +128,7 @@ void LLFetchedGLTFMaterial::bind(LLViewerTexture* media_tex)
shader->uniform1f(LLShaderMgr::ROUGHNESS_FACTOR, mRoughnessFactor);
shader->uniform1f(LLShaderMgr::METALLIC_FACTOR, mMetallicFactor);
shader->uniform3fv(LLShaderMgr::EMISSIVE_COLOR, 1, mEmissiveColor.mV);
+ shader->uniform1f(LLShaderMgr::MIRROR_FLAG, 0);
F32 normal_packed[8];
mTextureTransform[GLTF_TEXTURE_INFO_NORMAL].getPacked(normal_packed);
diff --git a/indra/newview/llheroprobemanager.cpp b/indra/newview/llheroprobemanager.cpp
new file mode 100644
index 0000000000..b6db123cd9
--- /dev/null
+++ b/indra/newview/llheroprobemanager.cpp
@@ -0,0 +1,584 @@
+/**
+ * @file LLHeroProbeManager.cpp
+ * @brief LLHeroProbeManager class implementation
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llheroprobemanager.h"
+#include "llreflectionmapmanager.h"
+#include "llviewercamera.h"
+#include "llspatialpartition.h"
+#include "llviewerregion.h"
+#include "pipeline.h"
+#include "llviewershadermgr.h"
+#include "llviewercontrol.h"
+#include "llenvironment.h"
+#include "llstartup.h"
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llviewerwindow.h"
+#include "llviewerjoystick.h"
+#include "llviewermediafocus.h"
+
+extern BOOL gCubeSnapshot;
+extern BOOL gTeleportDisplay;
+
+// get the next highest power of two of v (or v if v is already a power of two)
+//defined in llvertexbuffer.cpp
+extern U32 nhpo2(U32 v);
+
+static void touch_default_probe(LLReflectionMap* probe)
+{
+ if (LLViewerCamera::getInstance())
+ {
+ LLVector3 origin = LLViewerCamera::getInstance()->getOrigin();
+ origin.mV[2] += 64.f;
+
+ probe->mOrigin.load3(origin.mV);
+ }
+}
+
+LLHeroProbeManager::LLHeroProbeManager()
+{
+}
+
+// helper class to seed octree with probes
+void LLHeroProbeManager::update()
+{
+ if (!LLPipeline::sReflectionProbesEnabled || gTeleportDisplay || LLStartUp::getStartupState() < STATE_PRECACHE)
+ {
+ return;
+ }
+
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
+ llassert(!gCubeSnapshot); // assert a snapshot is not in progress
+ if (LLAppViewer::instance()->logoutRequestSent())
+ {
+ return;
+ }
+
+ initReflectionMaps();
+
+ if (!mRenderTarget.isComplete())
+ {
+ U32 color_fmt = GL_RGBA16F;
+ U32 targetRes = mProbeResolution; // super sample
+ mRenderTarget.allocate(targetRes, targetRes, color_fmt, true);
+ }
+
+ if (mMipChain.empty())
+ {
+ U32 res = mProbeResolution;
+ U32 count = log2((F32)res) + 0.5f;
+
+ mMipChain.resize(count);
+ for (int i = 0; i < count; ++i)
+ {
+ mMipChain[i].allocate(res, res, GL_RGBA16F);
+ res /= 2;
+ }
+ }
+
+ llassert(mProbes[0] == mDefaultProbe);
+
+ LLVector4a probe_pos;
+ LLVector3 camera_pos = LLViewerCamera::instance().mOrigin;
+ F32 near_clip = 0.1f;
+ if (mHeroVOList.size() > 0)
+ {
+ // Find our nearest hero candidate.
+
+ float last_distance = 99999.f;
+
+ for (auto vo : mHeroVOList)
+ {
+ if (vo)
+ {
+ if (vo->mDrawable.notNull())
+ {
+ if (vo->mDrawable->mDistanceWRTCamera < last_distance)
+ {
+ mNearestHero = vo;
+ last_distance = vo->mDrawable->mDistanceWRTCamera;
+ }
+ }
+ else
+ {
+ // Valid drawables only please. Unregister this one.
+ unregisterHeroDrawable(vo);
+ }
+ }
+ else
+ {
+ unregisterHeroDrawable(vo);
+ }
+ }
+
+ if (mNearestHero != nullptr && mNearestHero->mDrawable.notNull())
+ {
+ U8 mode = mNearestHero->mirrorPlacementMode();
+ mode = llmin(mNearestHero->mDrawable->getNumFaces() - 1, mode);
+
+ mCurrentFace = mNearestHero->mDrawable->getFace(mode);
+ LLVector3 hero_pos = mCurrentFace->getPositionAgent();
+
+
+ // Calculate the average normal.
+ LLVector4a *posp = mCurrentFace->getViewerObject()->getVolume()->getVolumeFace(mCurrentFace->getTEOffset()).mPositions;
+ U16 *indp = mCurrentFace->getViewerObject()->getVolume()->getVolumeFace(mCurrentFace->getTEOffset()).mIndices;
+ // get first three vertices (first triangle)
+ LLVector4a v0 = posp[indp[0]];
+ LLVector4a v1 = posp[indp[1]];
+ LLVector4a v2 = posp[indp[2]];
+
+ v1.sub(v0);
+ v2.sub(v0);
+ LLVector3 face_normal = LLVector3(v1[0], v1[1], v1[2]) % LLVector3(v2[0], v2[1], v2[2]);
+
+ face_normal.normalize();
+ face_normal *= mCurrentFace->getXform()->getWorldRotation();
+
+ LLVector3 offset = camera_pos - hero_pos;
+ LLVector3 project = face_normal * (offset * face_normal);
+ LLVector3 reject = offset - project;
+ LLVector3 point = (reject - project) + hero_pos;
+
+ glh::matrix4f mat = copy_matrix(gGLModelView);
+ glh::vec4f tc(face_normal.mV);
+ mat.mult_matrix_vec(tc);
+
+ LLVector3 mirror_normal;
+ mirror_normal.set(tc.v);
+
+ LLVector3 hero_pos_render;
+ tc = glh::vec4f(hero_pos.mV);
+
+ mat.mult_matrix_vec(tc);
+ hero_pos_render.set(tc.v);
+
+ mCurrentClipPlane.setVec(hero_pos_render, mirror_normal);
+
+ probe_pos.load3(point.mV);
+ }
+
+ mHeroProbeStrength = 1;
+ }
+ else
+ {
+ probe_pos.load3(camera_pos.mV);
+ }
+
+
+ static LLCachedControl<S32> sDetail(gSavedSettings, "RenderHeroReflectionProbeDetail", -1);
+ static LLCachedControl<S32> sLevel(gSavedSettings, "RenderHeroReflectionProbeLevel", 3);
+
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("hpmu - realtime");
+ // Probe 0 is always our mirror probe.
+ mProbes[0]->mOrigin = probe_pos;
+
+ bool radiance_pass = gPipeline.mReflectionMapManager.isRadiancePass();
+
+ gPipeline.mReflectionMapManager.mRadiancePass = true;
+ mRenderingMirror = true;
+ for (U32 j = 0; j < mProbes.size(); j++)
+ {
+ for (U32 i = 0; i < 6; ++i)
+ {
+ updateProbeFace(mProbes[j], i, near_clip);
+ }
+ }
+ mRenderingMirror = false;
+
+ gPipeline.mReflectionMapManager.mRadiancePass = radiance_pass;
+ }
+}
+
+// Do the reflection map update render passes.
+// For every 12 calls of this function, one complete reflection probe radiance map and irradiance map is generated
+// First six passes render the scene with direct lighting only into a scratch space cube map at the end of the cube map array and generate
+// a simple mip chain (not convolution filter).
+// At the end of these passes, an irradiance map is generated for this probe and placed into the irradiance cube map array at the index for this probe
+// 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)
+{
+ // hacky hot-swap of camera specific render targets
+ gPipeline.mRT = &gPipeline.mAuxillaryRT;
+
+ probe->update(mRenderTarget.getWidth(), face, true, near_clip);
+
+ gPipeline.mRT = &gPipeline.mMainRT;
+
+ S32 sourceIdx = mReflectionProbeCount;
+
+
+ // Unlike the reflectionmap manager, all probes are considered "realtime" for hero probes.
+ sourceIdx += 1;
+
+ gGL.setColorMask(true, true);
+ LLGLDepthTest depth(GL_FALSE, GL_FALSE);
+ LLGLDisable cull(GL_CULL_FACE);
+ LLGLDisable blend(GL_BLEND);
+
+ // downsample to placeholder map
+ {
+ gGL.matrixMode(gGL.MM_MODELVIEW);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+
+ gGL.matrixMode(gGL.MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+
+ gGL.flush();
+ U32 res = mProbeResolution * 2;
+
+ static LLStaticHashedString resScale("resScale");
+ static LLStaticHashedString direction("direction");
+ static LLStaticHashedString znear("znear");
+ static LLStaticHashedString zfar("zfar");
+
+ LLRenderTarget *screen_rt = &gPipeline.mAuxillaryRT.screen;
+ LLRenderTarget *depth_rt = &gPipeline.mAuxillaryRT.deferredScreen;
+
+ // perform a gaussian blur on the super sampled render before downsampling
+ {
+ gGaussianProgram.bind();
+ gGaussianProgram.uniform1f(resScale, 1.f / mProbeResolution);
+ S32 diffuseChannel = gGaussianProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_TEXTURE);
+
+ // horizontal
+ gGaussianProgram.uniform2f(direction, 1.f, 0.f);
+ gGL.getTexUnit(diffuseChannel)->bind(screen_rt);
+ mRenderTarget.bindTarget();
+ gPipeline.mScreenTriangleVB->setBuffer();
+ gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+ mRenderTarget.flush();
+
+ // vertical
+ gGaussianProgram.uniform2f(direction, 0.f, 1.f);
+ gGL.getTexUnit(diffuseChannel)->bind(&mRenderTarget);
+ screen_rt->bindTarget();
+ gPipeline.mScreenTriangleVB->setBuffer();
+ gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+ screen_rt->flush();
+ }
+
+
+ S32 mips = log2((F32)mProbeResolution) + 0.5f;
+
+ gReflectionMipProgram.bind();
+ S32 diffuseChannel = gReflectionMipProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_TEXTURE);
+ S32 depthChannel = gReflectionMipProgram.enableTexture(LLShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_TEXTURE);
+
+ for (int i = 0; i < mMipChain.size(); ++i)
+ {
+ LL_PROFILE_GPU_ZONE("probe mip");
+ mMipChain[i].bindTarget();
+ if (i == 0)
+ {
+ gGL.getTexUnit(diffuseChannel)->bind(screen_rt);
+ }
+ else
+ {
+ gGL.getTexUnit(diffuseChannel)->bind(&(mMipChain[i - 1]));
+ }
+
+ gGL.getTexUnit(depthChannel)->bind(depth_rt, true);
+
+ gReflectionMipProgram.uniform1f(resScale, 1.f / (mProbeResolution * 2));
+ gReflectionMipProgram.uniform1f(znear, probe->getNearClip());
+ gReflectionMipProgram.uniform1f(zfar, MAX_FAR_CLIP);
+
+ gPipeline.mScreenTriangleVB->setBuffer();
+ gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+
+ res /= 2;
+
+ S32 mip = i - (mMipChain.size() - mips);
+
+ if (mip >= 0)
+ {
+ LL_PROFILE_GPU_ZONE("probe mip copy");
+ mTexture->bind(0);
+
+ glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, sourceIdx * 6 + face, 0, 0, res, res);
+
+ mTexture->unbind();
+ }
+ mMipChain[i].flush();
+ }
+
+ gGL.popMatrix();
+ gGL.matrixMode(gGL.MM_MODELVIEW);
+ gGL.popMatrix();
+
+ gGL.getTexUnit(diffuseChannel)->unbind(LLTexUnit::TT_TEXTURE);
+ gReflectionMipProgram.unbind();
+ }
+
+ if (face == 5)
+ {
+ mMipChain[0].bindTarget();
+ static LLStaticHashedString sSourceIdx("sourceIdx");
+
+ {
+ //generate radiance map (even if this is not the irradiance map, we need the mip chain for the irradiance map)
+ gRadianceGenProgram.bind();
+ mVertexBuffer->setBuffer();
+
+ S32 channel = gRadianceGenProgram.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY);
+ mTexture->bind(channel);
+ gRadianceGenProgram.uniform1i(sSourceIdx, sourceIdx);
+ gRadianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_MAX_LOD, mMaxProbeLOD);
+ gRadianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_STRENGTH, mHeroProbeStrength);
+
+ U32 res = mMipChain[0].getWidth();
+
+ for (int i = 0; i < mMipChain.size(); ++i)
+ {
+ LL_PROFILE_GPU_ZONE("probe radiance gen");
+ static LLStaticHashedString sMipLevel("mipLevel");
+ static LLStaticHashedString sRoughness("roughness");
+ static LLStaticHashedString sWidth("u_width");
+ static LLStaticHashedString sStrength("probe_strength");
+
+ gRadianceGenProgram.uniform1f(sRoughness, (F32)i / (F32)(mMipChain.size() - 1));
+ gRadianceGenProgram.uniform1f(sMipLevel, i);
+ gRadianceGenProgram.uniform1i(sWidth, mProbeResolution);
+ gRadianceGenProgram.uniform1f(sStrength, 1);
+
+ for (int cf = 0; cf < 6; ++cf)
+ { // for each cube face
+ LLCoordFrame frame;
+ frame.lookAt(LLVector3(0, 0, 0), LLCubeMapArray::sClipToCubeLookVecs[cf], LLCubeMapArray::sClipToCubeUpVecs[cf]);
+
+ F32 mat[16];
+ frame.getOpenGLRotation(mat);
+ gGL.loadMatrix(mat);
+
+ mVertexBuffer->drawArrays(gGL.TRIANGLE_STRIP, 0, 4);
+
+ glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, i, 0, 0, probe->mCubeIndex * 6 + cf, 0, 0, res, res);
+ }
+
+ if (i != mMipChain.size() - 1)
+ {
+ res /= 2;
+ glViewport(0, 0, res, res);
+ }
+ }
+
+ gRadianceGenProgram.unbind();
+ }
+
+ mMipChain[0].flush();
+ }
+}
+
+void LLHeroProbeManager::updateUniforms()
+{
+ if (!LLPipeline::sReflectionProbesEnabled)
+ {
+ return;
+ }
+
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
+
+ struct HeroProbeData
+ {
+ LLVector4 heroPosition[1];
+ GLint heroProbeCount = 1;
+ };
+
+ HeroProbeData hpd;
+
+ LLMatrix4a modelview;
+ modelview.loadu(gGLModelView);
+ LLVector4a oa; // scratch space for transformed origin
+ oa.set(0, 0, 0, 0);
+ hpd.heroProbeCount = 1;
+ modelview.affineTransform(mProbes[0]->mOrigin, oa);
+ hpd.heroPosition[0].set(oa.getF32ptr());
+
+ //copy rpd into uniform buffer object
+ if (mUBO == 0)
+ {
+ glGenBuffers(1, &mUBO);
+ }
+
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmsu - update buffer");
+ glBindBuffer(GL_UNIFORM_BUFFER, mUBO);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(HeroProbeData), &hpd, GL_STREAM_DRAW);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+ }
+}
+
+void LLHeroProbeManager::setUniforms()
+{
+ if (!LLPipeline::sReflectionProbesEnabled)
+ {
+ return;
+ }
+
+ if (mUBO == 0)
+ {
+ updateUniforms();
+ }
+ glBindBufferBase(GL_UNIFORM_BUFFER, 1, mUBO);
+}
+
+void LLHeroProbeManager::renderDebug()
+{
+ gDebugProgram.bind();
+
+ for (auto& probe : mProbes)
+ {
+ renderReflectionProbe(probe);
+ }
+
+ gDebugProgram.unbind();
+}
+
+void LLHeroProbeManager::initReflectionMaps()
+{
+ U32 count = LL_MAX_HERO_PROBE_COUNT;
+
+ if (mTexture.isNull() || mReflectionProbeCount != count || mReset)
+ {
+ mReset = false;
+ mReflectionProbeCount = count;
+ mProbeResolution = gSavedSettings.getS32("RenderHeroProbeResolution");
+ mMaxProbeLOD = log2f(mProbeResolution) - 1.f; // number of mips - 1
+
+ mTexture = new LLCubeMapArray();
+
+ // store mReflectionProbeCount+2 cube maps, final two cube maps are used for render target and radiance map generation source)
+ mTexture->allocate(mProbeResolution, 3, mReflectionProbeCount + 2);
+
+ if (mDefaultProbe.isNull())
+ {
+ llassert(mProbes.empty()); // default probe MUST be the first probe created
+ mDefaultProbe = new LLReflectionMap();
+ mProbes.push_back(mDefaultProbe);
+ }
+
+ llassert(mProbes[0] == mDefaultProbe);
+
+ // For hero probes, we treat this as the main mirror probe.
+
+ mDefaultProbe->mCubeIndex = 0;
+ mDefaultProbe->mCubeArray = mTexture;
+ mDefaultProbe->mDistance = gSavedSettings.getF32("RenderHeroProbeDistance");
+ mDefaultProbe->mRadius = 4096.f;
+ mDefaultProbe->mProbeIndex = 0;
+ touch_default_probe(mDefaultProbe);
+
+ mProbes.push_back(mDefaultProbe);
+ }
+
+ if (mVertexBuffer.isNull())
+ {
+ U32 mask = LLVertexBuffer::MAP_VERTEX;
+ LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(mask);
+ buff->allocateBuffer(4, 0);
+
+ LLStrider<LLVector3> v;
+
+ buff->getVertexStrider(v);
+
+ v[0] = LLVector3(-1, -1, -1);
+ v[1] = LLVector3(1, -1, -1);
+ v[2] = LLVector3(-1, 1, -1);
+ v[3] = LLVector3(1, 1, -1);
+
+ buff->unmapBuffer();
+
+ mVertexBuffer = buff;
+ }
+}
+
+void LLHeroProbeManager::cleanup()
+{
+ mVertexBuffer = nullptr;
+ mRenderTarget.release();
+ mHeroRenderTarget.release();
+
+ mMipChain.clear();
+
+ mTexture = nullptr;
+
+ mProbes.clear();
+
+ mReflectionMaps.clear();
+
+ mDefaultProbe = nullptr;
+ mUpdatingProbe = nullptr;
+
+ glDeleteBuffers(1, &mUBO);
+ mUBO = 0;
+
+ mHeroVOList.clear();
+ mNearestHero = nullptr;
+}
+
+void LLHeroProbeManager::doOcclusion()
+{
+ LLVector4a eye;
+ eye.load3(LLViewerCamera::instance().getOrigin().mV);
+
+ for (auto& probe : mProbes)
+ {
+ if (probe != nullptr && probe != mDefaultProbe)
+ {
+ probe->doOcclusion(eye);
+ }
+ }
+}
+
+void LLHeroProbeManager::registerHeroDrawable(LLVOVolume* drawablep)
+{
+ if (mHeroVOList.find(drawablep) == mHeroVOList.end())
+ {
+ mHeroVOList.insert(drawablep);
+ LL_INFOS() << "Mirror drawable registered." << LL_ENDL;
+ }
+}
+
+void LLHeroProbeManager::unregisterHeroDrawable(LLVOVolume* drawablep)
+{
+ if (mHeroVOList.find(drawablep) != mHeroVOList.end())
+ {
+ mHeroVOList.erase(drawablep);
+ }
+}
+
+bool LLHeroProbeManager::isViableMirror(LLFace* face) const
+{
+ return face == mCurrentFace;
+}
diff --git a/indra/newview/llheroprobemanager.h b/indra/newview/llheroprobemanager.h
new file mode 100644
index 0000000000..68cfdbfd99
--- /dev/null
+++ b/indra/newview/llheroprobemanager.h
@@ -0,0 +1,142 @@
+/**
+ * @file llheroprobemanager.h
+ * @brief LLHeroProbeManager class declaration
+ *
+ * $LicenseInfo:firstyear=2022&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2022, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#pragma once
+
+#include "llreflectionmap.h"
+#include "llrendertarget.h"
+#include "llcubemaparray.h"
+#include "llcubemap.h"
+#include "lldrawable.h"
+
+class LLSpatialGroup;
+class LLViewerObject;
+
+// number of reflection probes to keep in vram
+#define LL_MAX_HERO_PROBE_COUNT 2
+
+class alignas(16) LLHeroProbeManager
+{
+ LL_ALIGN_NEW
+public:
+ enum class DetailLevel
+ {
+ STATIC_ONLY = 0,
+ STATIC_AND_DYNAMIC,
+ REALTIME = 2
+ };
+
+ // allocate an environment map of the given resolution
+ LLHeroProbeManager();
+
+ // release any GL state
+ void cleanup();
+
+ // maintain reflection probes
+ void update();
+
+ // debug display, called from llspatialpartition if reflection
+ // probe debug display is active
+ void renderDebug();
+
+ // call once at startup to allocate cubemap arrays
+ void initReflectionMaps();
+
+ // perform occlusion culling on all active reflection probes
+ void doOcclusion();
+
+ void registerHeroDrawable(LLVOVolume* drawablep);
+ void unregisterHeroDrawable(LLVOVolume* drawablep);
+
+ bool isViableMirror(LLFace* face) const;
+
+ bool isMirrorPass() const { return mRenderingMirror; }
+
+ LLPlane currentMirrorClip() const { return mCurrentClipPlane; }
+
+private:
+ friend class LLPipeline;
+
+ // update UBO used for rendering (call only once per render pipe flush)
+ void updateUniforms();
+
+ // bind UBO used for rendering
+ void setUniforms();
+
+ // render target for cube snapshots
+ // used to generate mipmaps without doing a copy-to-texture
+ LLRenderTarget mRenderTarget;
+
+ LLRenderTarget mHeroRenderTarget;
+
+ std::vector<LLRenderTarget> mMipChain;
+
+ // storage for reflection probe radiance maps (plus two scratch space cubemaps)
+ LLPointer<LLCubeMapArray> mTexture;
+
+ // vertex buffer for pushing verts to filter shaders
+ LLPointer<LLVertexBuffer> mVertexBuffer;
+
+ LLPlane mCurrentClipPlane;
+
+ // update the specified face of the specified probe
+ void updateProbeFace(LLReflectionMap* probe, U32 face, F32 near_clip);
+
+ // list of active reflection maps
+ std::vector<LLPointer<LLReflectionMap> > mProbes;
+
+ // handle to UBO
+ U32 mUBO = 0;
+
+ // list of maps being used for rendering
+ std::vector<LLReflectionMap*> mReflectionMaps;
+
+ LLReflectionMap* mUpdatingProbe = nullptr;
+
+ LLPointer<LLReflectionMap> mDefaultProbe; // default reflection probe to fall back to for pixels with no probe influences (should always be at cube index 0)
+
+ // number of reflection probes to use for rendering
+ U32 mReflectionProbeCount;
+
+ // resolution of reflection probes
+ U32 mProbeResolution = 1024;
+
+ // maximum LoD of reflection probes (mip levels - 1)
+ F32 mMaxProbeLOD = 6.f;
+
+ F32 mHeroProbeStrength = 1.f;
+ bool mIsInTransition = false;
+
+ // if true, reset all probe render state on the next update (for teleports and sky changes)
+ bool mReset = false;
+
+ bool mRenderingMirror = false;
+
+ std::set<LLVOVolume*> mHeroVOList;
+ LLVOVolume* mNearestHero;
+ LLFace* mCurrentFace;
+};
+
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index cb28fb4770..51aa2f4891 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -1768,6 +1768,7 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
getChild<LLUICtrl>("shinyOffsetV")->setValue(offset_y);
getChild<LLUICtrl>("glossiness")->setValue(material->getSpecularLightExponent());
getChild<LLUICtrl>("environment")->setValue(material->getEnvironmentIntensity());
+ getChild<LLUICtrl>("mirror")->setValue(material->getEnvironmentIntensity());
updateShinyControls(!material->getSpecularID().isNull(), true);
}
diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index d36662c11b..89c3c67286 100644
--- a/indra/newview/llpanelface.h
+++ b/indra/newview/llpanelface.h
@@ -143,6 +143,7 @@ protected:
void sendTexGen(); // applies and sends bump map
void sendShiny(U32 shininess); // applies and sends shininess
void sendFullbright(); // applies and sends full bright
+
void sendGlow();
void alignTestureLayer();
@@ -232,7 +233,7 @@ protected:
static void onCommitShiny( LLUICtrl* ctrl, void* userdata);
static void onCommitAlphaMode( LLUICtrl* ctrl, void* userdata);
static void onCommitFullbright( LLUICtrl* ctrl, void* userdata);
- static void onCommitGlow( LLUICtrl* ctrl, void *userdata);
+ static void onCommitGlow( LLUICtrl* ctrl, void *userdata);
static void onCommitPlanarAlign( LLUICtrl* ctrl, void* userdata);
static void onCommitRepeatsPerMeter( LLUICtrl* ctrl, void* userinfo);
diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp
index d6c36bbfb7..2bad5d4235 100644
--- a/indra/newview/llpanelvolume.cpp
+++ b/indra/newview/llpanelvolume.cpp
@@ -114,6 +114,11 @@ BOOL LLPanelVolume::postBuild()
getChild<LLUICtrl>("FlexForceZ")->setValidateBeforeCommit(precommitValidate);
}
+ // Mirror Parameters
+ {
+ childSetCommitCallback("Mirror Checkbox Ctrl", onCommitIsMirror, this);
+ }
+
// LIGHT Parameters
{
childSetCommitCallback("Light Checkbox Ctrl",onCommitIsLight,this);
@@ -305,6 +310,10 @@ void LLPanelVolume::getState( )
getChildView("select_single")->setEnabled(true);
}
+ BOOL is_mirror = volobjp && volobjp->isMirror();
+ getChild<LLUICtrl>("Mirror Checkbox Ctrl")->setValue(is_mirror);
+ getChildView("Mirror Checkbox Ctrl")->setEnabled(editable && single_volume && volobjp);
+
// Light properties
BOOL is_light = volobjp && volobjp->getIsLight();
getChild<LLUICtrl>("Light Checkbox Ctrl")->setValue(is_light);
@@ -746,6 +755,21 @@ void LLPanelVolume::sendIsLight()
LL_INFOS() << "update light sent" << LL_ENDL;
}
+void LLPanelVolume::sendIsMirror()
+{
+ LLViewerObject* objectp = mObject;
+ if (!objectp || (objectp->getPCode() != LL_PCODE_VOLUME))
+ {
+ return;
+ }
+ LLVOVolume *volobjp = (LLVOVolume *)objectp;
+
+ BOOL value = getChild<LLUICtrl>("Mirror Checkbox Ctrl")->getValue();
+ volobjp->setIsMirror(value);
+ LL_INFOS() << "update mirror sent" << LL_ENDL;
+}
+
+
void LLPanelVolume::sendIsReflectionProbe()
{
LLViewerObject* objectp = mObject;
@@ -1412,6 +1436,12 @@ void LLPanelVolume::onCommitIsLight( LLUICtrl* ctrl, void* userdata )
self->sendIsLight();
}
+void LLPanelVolume::onCommitIsMirror( LLUICtrl* ctrl, void* userdata )
+{
+ LLPanelVolume* self = (LLPanelVolume*) userdata;
+ self->sendIsMirror();
+}
+
// static
void LLPanelVolume::setLightTextureID(const LLUUID &asset_id, const LLUUID &item_id, LLVOVolume* volobjp)
{
diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h
index 01b7ebb75c..a658351624 100644
--- a/indra/newview/llpanelvolume.h
+++ b/indra/newview/llpanelvolume.h
@@ -58,6 +58,7 @@ public:
void sendIsLight();
+ void sendIsMirror();
// when an object is becoming a refleciton probe, present a dialog asking for confirmation
// otherwise, send the reflection probe update immediately
void sendIsReflectionProbe();
@@ -71,6 +72,7 @@ public:
static void onCommitIsLight( LLUICtrl* ctrl, void* userdata);
static void onCommitLight( LLUICtrl* ctrl, void* userdata);
+ static void onCommitIsMirror( LLUICtrl* ctrl, void* userdata);
static void onCommitIsReflectionProbe(LLUICtrl* ctrl, void* userdata);
static void onCommitProbe(LLUICtrl* ctrl, void* userdata);
void onCommitIsFlexible( LLUICtrl* ctrl, void* userdata);
diff --git a/indra/newview/llreflectionmap.cpp b/indra/newview/llreflectionmap.cpp
index ec54fa1165..5fc9851709 100644
--- a/indra/newview/llreflectionmap.cpp
+++ b/indra/newview/llreflectionmap.cpp
@@ -49,7 +49,7 @@ LLReflectionMap::~LLReflectionMap()
}
}
-void LLReflectionMap::update(U32 resolution, U32 face)
+void LLReflectionMap::update(U32 resolution, U32 face, bool force_dynamic, F32 near_clip, bool useClipPlane, LLPlane clipPlane)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
mLastUpdateTime = gFrameTimeSeconds;
@@ -63,7 +63,10 @@ void LLReflectionMap::update(U32 resolution, U32 face)
{
resolution /= 2;
}
- gViewerWindow->cubeSnapshot(LLVector3(mOrigin), mCubeArray, mCubeIndex, face, getNearClip(), getIsDynamic());
+
+ F32 clip = (near_clip > 0) ? near_clip : getNearClip();
+
+ gViewerWindow->cubeSnapshot(LLVector3(mOrigin), mCubeArray, mCubeIndex, face, clip, getIsDynamic() || force_dynamic, useClipPlane, clipPlane);
}
void LLReflectionMap::autoAdjustOrigin()
diff --git a/indra/newview/llreflectionmap.h b/indra/newview/llreflectionmap.h
index 7ea0fe6187..9e888f20d0 100644
--- a/indra/newview/llreflectionmap.h
+++ b/indra/newview/llreflectionmap.h
@@ -36,6 +36,15 @@ class alignas(16) LLReflectionMap : public LLRefCount
{
LL_ALIGN_NEW
public:
+
+ enum class ProbeType
+ {
+ ALL = 0,
+ RADIANCE,
+ IRRADIANCE,
+ REFLECTION
+ };
+
// allocate an environment map of the given resolution
LLReflectionMap();
@@ -43,7 +52,7 @@ public:
// update this environment map
// resolution - size of cube map to generate
- void update(U32 resolution, U32 face);
+ void update(U32 resolution, U32 face, bool force_dynamic = false, F32 near_clip = -1.f, bool useClipPlane = false, LLPlane clipPlane = LLPlane(LLVector3(0, 0, 0), LLVector3(0, 0, 1)));
// for volume partition probes, try to place this probe in the best spot
void autoAdjustOrigin();
@@ -127,5 +136,7 @@ public:
GLuint mOcclusionQuery = 0;
bool mOccluded = false;
U32 mOcclusionPendingFrames = 0;
+
+ ProbeType mType;
};
diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp
index 915c8893a4..b793cc3bdd 100644
--- a/indra/newview/llreflectionmapmanager.cpp
+++ b/indra/newview/llreflectionmapmanager.cpp
@@ -300,8 +300,8 @@ void LLReflectionMapManager::update()
}
}
- if (realtime &&
- closestDynamic == nullptr &&
+ if (realtime &&
+ closestDynamic == nullptr &&
probe->mCubeIndex != -1 &&
probe->getIsDynamic())
{
@@ -316,7 +316,7 @@ void LLReflectionMapManager::update()
// should do a full irradiance pass on "odd" frames and a radiance pass on "even" frames
closestDynamic->autoAdjustOrigin();
- // store and override the value of "isRadiancePass" -- parts of the render pipe rely on "isRadiancePass" to set
+ // store and override the value of "isRadiancePass" -- parts of the render pipe rely on "isRadiancePass" to set
// lighting values etc
bool radiance_pass = isRadiancePass();
mRadiancePass = mRealtimeRadiancePass;
@@ -556,7 +556,7 @@ void LLReflectionMapManager::doProbeUpdate()
// Do the reflection map update render passes.
// For every 12 calls of this function, one complete reflection probe radiance map and irradiance map is generated
-// First six passes render the scene with direct lighting only into a scratch space cube map at the end of the cube map array and generate
+// First six passes render the scene with direct lighting only into a scratch space cube map at the end of the cube map array and generate
// a simple mip chain (not convolution filter).
// At the end of these passes, an irradiance map is generated for this probe and placed into the irradiance cube map array at the index for this probe
// 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.
@@ -717,6 +717,7 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face)
mTexture->bind(channel);
gRadianceGenProgram.uniform1i(sSourceIdx, sourceIdx);
gRadianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_MAX_LOD, mMaxProbeLOD);
+ gRadianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_STRENGTH, 1.f);
U32 res = mMipChain[0].getWidth();
@@ -881,14 +882,14 @@ void LLReflectionMapManager::updateUniforms()
// see class3/deferred/reflectionProbeF.glsl
struct ReflectionProbeData
{
- // for box probes, matrix that transforms from camera space to a [-1, 1] cube representing the bounding box of
+ // for box probes, matrix that transforms from camera space to a [-1, 1] cube representing the bounding box of
// the box probe
- LLMatrix4 refBox[LL_MAX_REFLECTION_PROBE_COUNT];
+ LLMatrix4 refBox[LL_MAX_REFLECTION_PROBE_COUNT];
// for sphere probes, origin (xyz) and radius (w) of refmaps in clip space
- LLVector4 refSphere[LL_MAX_REFLECTION_PROBE_COUNT];
+ LLVector4 refSphere[LL_MAX_REFLECTION_PROBE_COUNT];
- // extra parameters
+ // extra parameters
// x - irradiance scale
// y - radiance scale
// z - fade in
@@ -900,14 +901,14 @@ void LLReflectionMapManager::updateUniforms()
// [i][1] - index into "refNeighbor" for probes that intersect this probe
// [i][2] - number of probes that intersect this probe, or -1 for no neighbors
// [i][3] - priority (probe type stored in sign bit - positive for spheres, negative for boxes)
- GLint refIndex[LL_MAX_REFLECTION_PROBE_COUNT][4];
+ GLint refIndex[LL_MAX_REFLECTION_PROBE_COUNT][4];
// list of neighbor indices
- GLint refNeighbor[4096];
+ GLint refNeighbor[4096];
GLint refBucket[256][4]; //lookup table for which index to start with for the given Z depth
// numbrer of active refmaps
- GLint refmapCount;
+ GLint refmapCount;
};
mReflectionMaps.resize(mReflectionProbeCount);
@@ -1124,7 +1125,7 @@ void LLReflectionMapManager::setUniforms()
}
if (mUBO == 0)
- {
+ {
updateUniforms();
}
glBindBufferBase(GL_UNIFORM_BUFFER, 1, mUBO);
@@ -1305,8 +1306,8 @@ void LLReflectionMapManager::initReflectionMaps()
}
}
-void LLReflectionMapManager::cleanup()
-{
+void LLReflectionMapManager::cleanup()
+{
mVertexBuffer = nullptr;
mRenderTarget.release();
diff --git a/indra/newview/llreflectionmapmanager.h b/indra/newview/llreflectionmapmanager.h
index b77a33da89..72707df7b0 100644
--- a/indra/newview/llreflectionmapmanager.h
+++ b/indra/newview/llreflectionmapmanager.h
@@ -43,21 +43,23 @@ class LLViewerObject;
// reflection probe mininum scale
#define LL_REFLECTION_PROBE_MINIMUM_SCALE 1.f;
+void renderReflectionProbe(LLReflectionMap* probe);
+
class alignas(16) LLReflectionMapManager
{
LL_ALIGN_NEW
public:
- enum class DetailLevel
+ enum class DetailLevel
{
STATIC_ONLY = 0,
STATIC_AND_DYNAMIC,
REALTIME = 2
};
- // allocate an environment map of the given resolution
+ // allocate an environment map of the given resolution
LLReflectionMapManager();
- // release any GL state
+ // release any GL state
void cleanup();
// maintain reflection probes
@@ -108,6 +110,7 @@ public:
private:
friend class LLPipeline;
+ friend class LLHeroProbeManager;
// initialize mCubeFree array to default values
void initCubeFree();
@@ -119,7 +122,7 @@ private:
// returns -1 if allocation failed
S32 allocateCubeIndex();
- // update the neighbors of the given probe
+ // update the neighbors of the given probe
void updateNeighbors(LLReflectionMap* probe);
// update UBO used for rendering (call only once per render pipe flush)
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 04ca62e0ec..a1e7d69ae4 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -1063,7 +1063,7 @@ void display_cube_face()
LLSpatialGroup::sNoDelete = TRUE;
S32 occlusion = LLPipeline::sUseOcclusion;
- LLPipeline::sUseOcclusion = 0; // occlusion data is from main camera point of view, don't read or write it during cube snapshots
+ LLPipeline::sUseOcclusion = 1; // occlusion data is from main camera point of view, don't read or write it during cube snapshots
//gDepthDirty = TRUE; //let "real" render pipe know it can't trust the depth buffer for occlusion data
static LLCullResult result;
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index a1d068461e..74d9397318 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -313,7 +313,9 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe
mLastUpdateCached(FALSE),
mCachedMuteListUpdateTime(0),
mCachedOwnerInMuteList(false),
- mRiggedAttachedWarned(false)
+ mRiggedAttachedWarned(false),
+mIsMirror(false),
+mMirrorPlacementMode(3)
{
if (!is_global)
{
@@ -1147,6 +1149,39 @@ U32 LLViewerObject::extractSpatialExtents(LLDataPackerBinaryBuffer *dp, LLVector
return parent_id;
}
+void detectMirror(const std::string &str, bool &mirror, U8 &mode)
+{
+
+ std::stringstream ss(str);
+ std::string word;
+ while (ss >> word)
+ {
+ if (word == "IsMirror")
+ {
+ mirror = true;
+ }
+
+ if (mirror)
+ {
+ bool num = false;
+ std::string::const_iterator it = word.begin();
+ while (it != word.end())
+ {
+ num = std::isdigit(*it);
+ ++it;
+
+ if (!num)
+ break;
+ }
+
+ if (num)
+ {
+ mode = atoi(word.c_str());
+ }
+ }
+ }
+}
+
U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
void **user_data,
U32 block_num,
@@ -1523,11 +1558,14 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
std::string temp_string;
mesgsys->getStringFast(_PREHASH_ObjectData, _PREHASH_Text, temp_string, block_num );
+ detectMirror(temp_string, mIsMirror, mMirrorPlacementMode);
+
LLColor4U coloru;
mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_TextColor, coloru.mV, 4, block_num);
-
+
// alpha was flipped so that it zero encoded better
coloru.mV[3] = 255 - coloru.mV[3];
+
mText->setColor(LLColor4(coloru));
mText->setString(temp_string);
@@ -1907,6 +1945,9 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
{
std::string temp_string;
dp->unpackString(temp_string, "Text");
+
+ detectMirror(temp_string, mIsMirror, mMirrorPlacementMode);
+
LLColor4U coloru;
dp->unpackBinaryDataFixed(coloru.mV, 4, "Color");
coloru.mV[3] = 255 - coloru.mV[3];
@@ -5303,7 +5344,6 @@ S32 LLViewerObject::setTEFullbright(const U8 te, const U8 fullbright)
return retval;
}
-
S32 LLViewerObject::setTEMediaFlags(const U8 te, const U8 media_flags)
{
// this might need work for media type
@@ -6237,6 +6277,11 @@ LLViewerObject::ExtraParameter* LLViewerObject::createNewParameterEntry(U16 para
new_block = new LLReflectionProbeParams();
break;
}
+ case LLNetworkData::PARAMS_MIRROR:
+ {
+ new_block = new LLMirrorParams();
+ break;
+ }
default:
{
LL_INFOS_ONCE() << "Unknown param type: " << param_type << LL_ENDL;
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 898b21e1ae..c165f164a8 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -257,6 +257,8 @@ public:
virtual BOOL isRiggedMesh() const { return FALSE; }
virtual BOOL hasLightTexture() const { return FALSE; }
virtual BOOL isReflectionProbe() const { return FALSE; }
+ virtual BOOL isMirror() const { return FALSE; }
+ virtual U8 mirrorPlacementMode() const { return 0; }
// This method returns true if the object is over land owned by
// the agent, one of its groups, or it encroaches and
@@ -877,6 +879,9 @@ protected:
F32 mPhysicsCost;
F32 mLinksetPhysicsCost;
+ bool mIsMirror;
+ U8 mMirrorPlacementMode;
+
// If true, "shrink wrap" this volume in its spatial partition. See "shrinkWrap"
bool mShouldShrinkWrap = false;
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 61ccc1d43f..2380e112aa 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -2074,6 +2074,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
gDeferredSoftenProgram.addPermutation("HAS_SUN_SHADOW", "1");
}
+ gDeferredSoftenProgram.addPermutation("HERO_PROBES", "1");
+
if (gSavedSettings.getBOOL("RenderDeferredSSAO"))
{ //if using SSAO, take screen space light map into account as if shadows are enabled
gDeferredSoftenProgram.mShaderLevel = llmax(gDeferredSoftenProgram.mShaderLevel, 2);
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index ba2b6e1c7c..e0ec8eec25 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -5304,7 +5304,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, F32 near_clip, bool dynamic_render)
+BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubearray, S32 cubeIndex, S32 face, F32 near_clip, bool dynamic_render, bool useCustomClipPlane, LLPlane clipPlane)
{
// NOTE: implementation derived from LLFloater360Capture::capture360Images() and simpleSnapshot
LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;
@@ -5335,6 +5335,14 @@ BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubea
camera->setOrigin(origin);
camera->setNear(near_clip);
+ LLPlane previousClipPlane;
+
+ if (useCustomClipPlane)
+ {
+ previousClipPlane = camera->getUserClipPlane();
+ camera->setUserClipPlane(clipPlane);
+ }
+
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); // stencil buffer is deprecated | GL_STENCIL_BUFFER_BIT);
U32 dynamic_render_types[] = {
@@ -5441,6 +5449,11 @@ BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubea
gPipeline.resetDrawOrders();
mWorldViewRectRaw = window_rect;
+
+ if (useCustomClipPlane)
+ {
+ camera->setUserClipPlane(previousClipPlane);
+ }
// restore original view/camera/avatar settings settings
*camera = saved_camera;
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index 6e8a5b2f4e..4da6a1360f 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -374,7 +374,8 @@ public:
// index - cube index in the array to use (cube index, not face-layer)
// 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, bool render_avatars);
+ BOOL cubeSnapshot(const LLVector3 &origin, LLCubeMapArray *cubearray, S32 index, S32 face, F32 near_clip, bool render_avatars,
+ bool customCullingPlane = false, LLPlane cullingPlane = LLPlane(LLVector3(0, 0, 0), LLVector3(0, 0, 1)));
// special implementation of simpleSnapshot for reflection maps
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index ec2f490742..91e64d611c 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -249,6 +249,9 @@ LLVOVolume::~LLVOVolume()
mTextureAnimp = NULL;
delete mVolumeImpl;
mVolumeImpl = NULL;
+
+ if (mIsMirror)
+ gPipeline.mHeroProbeManager.unregisterHeroDrawable(this);
gMeshRepo.unregisterMesh(this);
@@ -996,7 +999,12 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline)
{
updateReflectionProbePtr();
}
-
+
+ if (isMirror())
+ {
+ gPipeline.mHeroProbeManager.registerHeroDrawable(this);
+ }
+
updateRadius();
bool force_update = true; // avoid non-alpha mDistance update being optimized away
mDrawable->updateDistance(*LLViewerCamera::getInstance(), force_update);
@@ -3319,6 +3327,48 @@ F32 LLVOVolume::getLightCutoff() const
}
}
+bool LLVOVolume::setIsMirror(BOOL is_mirror)
+{
+ BOOL was_mirror = isMirror();
+ if (is_mirror != was_mirror)
+ {
+ if (is_mirror)
+ {
+ setParameterEntryInUse(LLNetworkData::PARAMS_MIRROR, TRUE, true);
+ }
+ else
+ {
+ setParameterEntryInUse(LLNetworkData::PARAMS_MIRROR, FALSE, true);
+ }
+ }
+
+ updateMirrorDrawable();
+
+ return was_mirror != is_mirror;
+}
+
+void LLVOVolume::updateMirrorDrawable()
+{
+ if (isMirror())
+ {
+ gPipeline.mHeroProbeManager.registerHeroDrawable(this);
+ }
+ else
+ {
+ gPipeline.mHeroProbeManager.unregisterHeroDrawable(this);
+ }
+}
+
+BOOL LLVOVolume::isMirror() const
+{
+ return mIsMirror;
+}
+
+U8 LLVOVolume::mirrorPlacementMode() const
+{
+ return mMirrorPlacementMode;
+}
+
BOOL LLVOVolume::isReflectionProbe() const
{
return getParameterEntryInUse(LLNetworkData::PARAMS_REFLECTION_PROBE);
@@ -4369,6 +4419,11 @@ void LLVOVolume::parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_u
}
updateReflectionProbePtr();
+
+ if (isMirror())
+ gPipeline.mHeroProbeManager.registerHeroDrawable(this);
+ else
+ gPipeline.mHeroProbeManager.unregisterHeroDrawable(this);
}
void LLVOVolume::updateReflectionProbePtr()
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index aadc1fbcf3..848f455e2a 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -294,6 +294,11 @@ public:
F32 getLightRadius() const;
F32 getLightFalloff(const F32 fudge_factor = 1.f) const;
F32 getLightCutoff() const;
+
+ // Mirrors
+ bool setIsMirror(BOOL is_mirror);
+ void updateMirrorDrawable();
+ U8 mirrorPlacementMode() const override;
// Reflection Probes
bool setIsReflectionProbe(BOOL is_probe);
@@ -307,6 +312,8 @@ public:
F32 getReflectionProbeNearClip() const;
bool getReflectionProbeIsBox() const;
bool getReflectionProbeIsDynamic() const;
+
+ BOOL isMirror() const override;
// Flexible Objects
U32 getVolumeInterfaceID() const;
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 9266c84540..c18f503c61 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -637,6 +637,7 @@ void LLPipeline::cleanup()
mCubeVB = NULL;
mReflectionMapManager.cleanup();
+ mHeroProbeManager.cleanup();
}
//============================================================================
@@ -767,6 +768,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
{ // hacky -- allocate auxillary buffer
gCubeSnapshot = TRUE;
mReflectionMapManager.initReflectionMaps();
+ mHeroProbeManager.initReflectionMaps();
mRT = &mAuxillaryRT;
U32 res = mReflectionMapManager.mProbeResolution * 4; //multiply by 4 because probes will be 16x super sampled
allocateScreenBuffer(res, res, samples);
@@ -2402,6 +2404,26 @@ void LLPipeline::doOcclusion(LLCamera& camera)
gGL.setColorMask(true, true);
}
+
+ if (sReflectionProbesEnabled && sUseOcclusion > 1 && !LLPipeline::sShadowRender && !gCubeSnapshot)
+ {
+ gGL.setColorMask(false, false);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+ LLGLDisable cull(GL_CULL_FACE);
+
+ gOcclusionCubeProgram.bind();
+
+ if (mCubeVB.isNull())
+ { //cube VB will be used for issuing occlusion queries
+ mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX);
+ }
+ mCubeVB->setBuffer();
+
+ mHeroProbeManager.doOcclusion();
+ gOcclusionCubeProgram.unbind();
+
+ gGL.setColorMask(true, true);
+ }
if (LLPipeline::sUseOcclusion > 1 &&
(sCull->hasOcclusionGroups() || LLVOCachePartition::sNeedsOcclusionCheck))
@@ -3779,6 +3801,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera, bool do_occlusion)
{
//update reflection probe uniform
mReflectionMapManager.updateUniforms();
+ mHeroProbeManager.updateUniforms();
}
U32 cur_type = 0;
@@ -8444,6 +8467,14 @@ void LLPipeline::bindReflectionProbes(LLGLSLShader& shader)
mReflectionMapManager.mIrradianceMaps->bind(channel);
bound = true;
}
+
+ channel = shader.enableTexture(LLShaderMgr::HERO_PROBE, LLTexUnit::TT_CUBE_MAP_ARRAY);
+ if (channel > -1 && mHeroProbeManager.mTexture.notNull())
+ {
+ mHeroProbeManager.mTexture->bind(channel);
+ bound = true;
+ }
+
if (bound)
{
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index d4c6432e55..299eaedea7 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -39,6 +39,7 @@
#include "lldrawable.h"
#include "llrendertarget.h"
#include "llreflectionmapmanager.h"
+#include "llheroprobemanager.h"
#include <stack>
@@ -448,6 +449,7 @@ public:
void handleShadowDetailChanged();
LLReflectionMapManager mReflectionMapManager;
+ LLHeroProbeManager mHeroProbeManager;
private:
void unloadShaders();
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index 9966fe0b56..510351b471 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -2410,7 +2410,15 @@ even though the user gets a free copy.
name="object_horizontal"
top_pad="10"
width="278" />
-
+ <check_box
+ height="16"
+ label="Mirror"
+ layout="topleft"
+ left="10"
+ name="Mirror Checkbox Ctrl"
+ tool_tip="Causes object to be a mirror"
+ top_pad="8"
+ width="60" />
<check_box
height="16"
label="Light"