summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorDave Parks <davep@lindenlab.com>2022-05-16 17:21:08 +0000
committerDave Parks <davep@lindenlab.com>2022-05-16 17:21:08 +0000
commit3400e5fd302c0d9dea6386c4d5bf38876f2cc287 (patch)
treee791863ef5dabe1a6fb6cba59771607912362ab7 /indra
parent6c1fdac9df52ff920860066905a08db748ab0d95 (diff)
SL-17284 Reflection probe tuning and optimization take 1
Diffstat (limited to 'indra')
-rw-r--r--indra/llrender/CMakeLists.txt2
-rw-r--r--indra/llrender/llcubemap.cpp10
-rw-r--r--indra/llrender/llcubemaparray.cpp113
-rw-r--r--indra/llrender/llcubemaparray.h60
-rw-r--r--indra/llrender/llgl.cpp33
-rw-r--r--indra/llrender/llgl.h1
-rw-r--r--indra/llrender/llglheaders.h9
-rw-r--r--indra/llrender/llglslshader.cpp61
-rw-r--r--indra/llrender/llglslshader.h3
-rw-r--r--indra/llrender/llimagegl.cpp51
-rw-r--r--indra/llrender/llrender.cpp4
-rw-r--r--indra/llrender/llrender.h3
-rw-r--r--indra/llrender/llshadermgr.cpp13
-rw-r--r--indra/llrender/llshadermgr.h2
-rw-r--r--indra/newview/app_settings/settings.xml11
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/aoUtil.glsl14
-rw-r--r--indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl29
-rw-r--r--indra/newview/app_settings/shaders/class1/interface/reflectionmipF.glsl75
-rw-r--r--indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl274
-rw-r--r--indra/newview/llagentcamera.cpp6
-rw-r--r--indra/newview/lldrawpoolalpha.cpp4
-rw-r--r--indra/newview/lldrawpoolbump.cpp1
-rw-r--r--indra/newview/lldrawpoolpbropaque.cpp2
-rw-r--r--indra/newview/llreflectionmap.cpp171
-rw-r--r--indra/newview/llreflectionmap.h51
-rw-r--r--indra/newview/llreflectionmapmanager.cpp516
-rw-r--r--indra/newview/llreflectionmapmanager.h77
-rw-r--r--indra/newview/llspatialpartition.cpp117
-rw-r--r--indra/newview/llspatialpartition.h19
-rw-r--r--indra/newview/llviewerdisplay.cpp121
-rw-r--r--indra/newview/llviewermenu.cpp10
-rw-r--r--indra/newview/llviewershadermgr.cpp20
-rw-r--r--indra/newview/llviewershadermgr.h1
-rw-r--r--indra/newview/llviewerwindow.cpp99
-rw-r--r--indra/newview/llviewerwindow.h6
-rw-r--r--indra/newview/llvovolume.cpp10
-rw-r--r--indra/newview/llworld.cpp3
-rw-r--r--indra/newview/pipeline.cpp505
-rw-r--r--indra/newview/pipeline.h3
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml16
40 files changed, 2060 insertions, 466 deletions
diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt
index baab09a104..a30f47f1d9 100644
--- a/indra/llrender/CMakeLists.txt
+++ b/indra/llrender/CMakeLists.txt
@@ -31,6 +31,7 @@ include_directories(SYSTEM
set(llrender_SOURCE_FILES
llatmosphere.cpp
llcubemap.cpp
+ llcubemaparray.cpp
llfontbitmapcache.cpp
llfontfreetype.cpp
llfontgl.cpp
@@ -58,6 +59,7 @@ set(llrender_HEADER_FILES
llatmosphere.h
llcubemap.h
+ llcubemaparray.h
llfontgl.h
llfontfreetype.h
llfontbitmapcache.h
diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp
index 6d872d0763..473447ad72 100644
--- a/indra/llrender/llcubemap.cpp
+++ b/indra/llrender/llcubemap.cpp
@@ -219,13 +219,17 @@ void LLCubeMap::initEnvironmentMap(const std::vector<LLPointer<LLImageRaw> >& ra
void LLCubeMap::generateMipMaps()
{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
+
mImages[0]->setUseMipMaps(TRUE);
mImages[0]->setHasMipMaps(TRUE);
enableTexture(0);
bind();
- mImages[0]->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
- glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
- glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
+ mImages[0]->setFilteringOption(LLTexUnit::TFO_BILINEAR);
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("cmgmm - glGenerateMipmap");
+ glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
+ }
gGL.getTexUnit(0)->disable();
disable();
}
diff --git a/indra/llrender/llcubemaparray.cpp b/indra/llrender/llcubemaparray.cpp
new file mode 100644
index 0000000000..e4081c1154
--- /dev/null
+++ b/indra/llrender/llcubemaparray.cpp
@@ -0,0 +1,113 @@
+/**
+ * @file llcubemaparray.cpp
+ * @brief LLCubeMap 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 "linden_common.h"
+
+#include "llworkerthread.h"
+
+#include "llcubemaparray.h"
+
+#include "v4coloru.h"
+#include "v3math.h"
+#include "v3dmath.h"
+#include "m3math.h"
+#include "m4math.h"
+
+#include "llrender.h"
+#include "llglslshader.h"
+
+#include "llglheaders.h"
+
+//#pragma optimize("", off)
+
+// MUST match order of OpenGL face-layers
+GLenum LLCubeMapArray::sTargets[6] =
+{
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
+};
+
+LLCubeMapArray::LLCubeMapArray()
+ : mTextureStage(0)
+{
+
+}
+
+LLCubeMapArray::~LLCubeMapArray()
+{
+}
+
+void LLCubeMapArray::allocate(U32 resolution, U32 components, U32 count)
+{
+ U32 texname = 0;
+
+ LLImageGL::generateTextures(1, &texname);
+
+ mImage = new LLImageGL(resolution, resolution, components, TRUE);
+ mImage->setTexName(texname);
+ mImage->setTarget(sTargets[0], LLTexUnit::TT_CUBE_MAP_ARRAY);
+
+ mImage->setUseMipMaps(TRUE);
+ mImage->setHasMipMaps(TRUE);
+
+ bind(0);
+
+ glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY_ARB, 0, GL_RGB, resolution, resolution, count*6, 0,
+ GL_RGB, GL_UNSIGNED_BYTE, nullptr);
+
+ mImage->setAddressMode(LLTexUnit::TAM_CLAMP);
+
+ mImage->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
+
+ glGenerateMipmap(GL_TEXTURE_CUBE_MAP_ARRAY_ARB);
+
+ unbind();
+}
+
+void LLCubeMapArray::bind(S32 stage)
+{
+ mTextureStage = stage;
+ gGL.getTexUnit(stage)->bindManual(LLTexUnit::TT_CUBE_MAP_ARRAY, getGLName(), TRUE);
+}
+
+void LLCubeMapArray::unbind()
+{
+ gGL.getTexUnit(mTextureStage)->unbind(LLTexUnit::TT_CUBE_MAP_ARRAY);
+ mTextureStage = -1;
+}
+
+GLuint LLCubeMapArray::getGLName()
+{
+ return mImage->getTexName();
+}
+
+void LLCubeMapArray::destroyGL()
+{
+ mImage = NULL;
+}
diff --git a/indra/llrender/llcubemaparray.h b/indra/llrender/llcubemaparray.h
new file mode 100644
index 0000000000..52e21f1dda
--- /dev/null
+++ b/indra/llrender/llcubemaparray.h
@@ -0,0 +1,60 @@
+/**
+ * @file llcubemaparray.h
+ * @brief LLCubeMap class definition
+ *
+ * $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 "llgl.h"
+
+#include <vector>
+
+class LLVector3;
+
+// Environment map hack!
+class LLCubeMapArray : public LLRefCount
+{
+public:
+ LLCubeMapArray();
+
+ static GLenum sTargets[6];
+
+ // allocate a cube map array
+ // res - resolution of each cube face
+ // components - number of components per pixel
+ // count - number of cube maps in the array
+ void allocate(U32 res, U32 components, U32 count);
+ void bind(S32 stage);
+ void unbind();
+
+ GLuint getGLName();
+
+ void destroyGL();
+
+protected:
+ friend class LLTexUnit;
+ ~LLCubeMapArray();
+ LLPointer<LLImageGL> mImage;
+ S32 mTextureStage;
+};
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 639d1fba32..6023796f7c 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -89,9 +89,10 @@ void APIENTRY gl_debug_callback(GLenum source,
if (gGLDebugLoggingEnabled)
{
- if (severity != GL_DEBUG_SEVERITY_HIGH_ARB &&
- severity != GL_DEBUG_SEVERITY_MEDIUM_ARB &&
- severity != GL_DEBUG_SEVERITY_LOW_ARB)
+ if (severity != GL_DEBUG_SEVERITY_HIGH_ARB // &&
+ //severity != GL_DEBUG_SEVERITY_MEDIUM_ARB &&
+ //severity != GL_DEBUG_SEVERITY_LOW_ARB
+ )
{ //suppress out-of-spec messages sent by nvidia driver (mostly vertexbuffer hints)
return;
}
@@ -316,6 +317,15 @@ PFNGLGETUNIFORMIVARBPROC glGetUniformivARB = NULL;
PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB = NULL;
PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer = NULL;
+// GL_ARB_uniform_buffer_object
+PFNGLGETUNIFORMINDICESPROC glGetUniformIndices = NULL;
+PFNGLGETACTIVEUNIFORMSIVPROC glGetActiveUniformsiv = NULL;
+PFNGLGETACTIVEUNIFORMNAMEPROC glGetActiveUniformName = NULL;
+PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex = NULL;
+PFNGLGETACTIVEUNIFORMBLOCKIVPROC glGetActiveUniformBlockiv = NULL;
+PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glGetActiveUniformBlockName = NULL;
+PFNGLUNIFORMBLOCKBINDINGPROC glUniformBlockBinding = NULL;
+
#if LL_WINDOWS
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
#endif
@@ -436,6 +446,7 @@ LLGLManager::LLGLManager() :
mHasTextureRectangle(FALSE),
mHasTextureMultisample(FALSE),
mHasTransformFeedback(FALSE),
+ mHasUniformBufferObject(FALSE),
mMaxSampleMaskWords(0),
mMaxColorTextureSamples(0),
mMaxDepthTextureSamples(0),
@@ -1054,6 +1065,7 @@ void LLGLManager::initExtensions()
mHasTextureMultisample = ExtensionExists("GL_ARB_texture_multisample", gGLHExts.mSysExts);
mHasDebugOutput = ExtensionExists("GL_ARB_debug_output", gGLHExts.mSysExts);
mHasTransformFeedback = mGLVersion >= 4.f ? TRUE : FALSE;
+ mHasUniformBufferObject = ExtensionExists("GL_ARB_uniform_buffer_object", gGLHExts.mSysExts);
#if !LL_DARWIN
mHasPointParameters = ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts);
#endif
@@ -1286,6 +1298,10 @@ void LLGLManager::initExtensions()
mGLMaxVertexRange = 0;
mGLMaxIndexRange = 0;
}
+
+ // same with glTexImage3D et al
+ glTexImage3D = (PFNGLTEXIMAGE3DPROC)GLH_EXT_GET_PROC_ADDRESS("glTexImage3D");
+ glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)GLH_EXT_GET_PROC_ADDRESS("glCopyTexSubImage3D");
#endif // !LL_LINUX || LL_LINUX_NV_GL_HEADERS
#if LL_LINUX_NV_GL_HEADERS
// nvidia headers are critically different from mesa-esque
@@ -1319,6 +1335,17 @@ void LLGLManager::initExtensions()
glPointParameterfvARB = (PFNGLPOINTPARAMETERFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glPointParameterfvARB");
}
+ if (mHasUniformBufferObject)
+ {
+ glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)GLH_EXT_GET_PROC_ADDRESS("glGetUniformIndices");
+ glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetUniformIndices");
+ glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC)GLH_EXT_GET_PROC_ADDRESS("glGetActiveUniformName");
+ glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)GLH_EXT_GET_PROC_ADDRESS("glGetUniformBlockIndex");
+ glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetActiveUniformBlockiv");
+ glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)GLH_EXT_GET_PROC_ADDRESS("glGetActiveUniformBlockName");
+ glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)GLH_EXT_GET_PROC_ADDRESS("glUniformBlockBinding");
+ }
+
// Assume shader capabilities
glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteObjectARB");
glGetHandleARB = (PFNGLGETHANDLEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetHandleARB");
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index 52338364e6..eea53ed01e 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -104,6 +104,7 @@ public:
BOOL mHasTextureRectangle;
BOOL mHasTextureMultisample;
BOOL mHasTransformFeedback;
+ BOOL mHasUniformBufferObject;
S32 mMaxSampleMaskWords;
S32 mMaxColorTextureSamples;
S32 mMaxDepthTextureSamples;
diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h
index 3d93cc0762..aa429505c1 100644
--- a/indra/llrender/llglheaders.h
+++ b/indra/llrender/llglheaders.h
@@ -564,6 +564,15 @@ extern PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB;
extern PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB;
extern PFNGLGETDEBUGMESSAGELOGARBPROC glGetDebugMessageLogARB;
+// GL_ARB_uniform_buffer_object
+extern PFNGLGETUNIFORMINDICESPROC glGetUniformIndices;
+extern PFNGLGETACTIVEUNIFORMSIVPROC glGetActiveUniformsiv;
+extern PFNGLGETACTIVEUNIFORMNAMEPROC glGetActiveUniformName;
+extern PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex;
+extern PFNGLGETACTIVEUNIFORMBLOCKIVPROC glGetActiveUniformBlockiv;
+extern PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glGetActiveUniformBlockName;
+extern PFNGLUNIFORMBLOCKBINDINGPROC glUniformBlockBinding;
+
#elif LL_DARWIN
//----------------------------------------------------------------------------
// LL_DARWIN
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index a52dcd5aa1..0212c605c3 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -780,7 +780,8 @@ GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type, GLint
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
if ((type >= GL_SAMPLER_1D_ARB && type <= GL_SAMPLER_2D_RECT_SHADOW_ARB) ||
- type == GL_SAMPLER_2D_MULTISAMPLE)
+ type == GL_SAMPLER_2D_MULTISAMPLE ||
+ type == GL_SAMPLER_CUBE_MAP_ARRAY_ARB)
{ //this here is a texture
GLint ret = mActiveTextureChannels;
if (size == 1)
@@ -1289,6 +1290,30 @@ void LLGLSLShader::uniform1iv(U32 index, U32 count, const GLint* v)
}
}
+void LLGLSLShader::uniform4iv(U32 index, U32 count, const GLint* v)
+{
+ if (mProgramObject)
+ {
+ if (mUniform.size() <= index)
+ {
+ LL_SHADER_UNIFORM_ERRS() << "Uniform index out of bounds." << LL_ENDL;
+ return;
+ }
+
+ if (mUniform[index] >= 0)
+ {
+ const auto& iter = mValue.find(mUniform[index]);
+ LLVector4 vec(v[0], v[1], v[2], v[3]);
+ if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
+ {
+ glUniform1ivARB(mUniform[index], count, v);
+ mValue[mUniform[index]] = vec;
+ }
+ }
+ }
+}
+
+
void LLGLSLShader::uniform1fv(U32 index, U32 count, const GLfloat* v)
{
if (mProgramObject)
@@ -1526,6 +1551,40 @@ void LLGLSLShader::uniform1i(const LLStaticHashedString& uniform, GLint v)
}
}
+void LLGLSLShader::uniform1iv(const LLStaticHashedString& uniform, U32 count, const GLint* v)
+{
+ GLint location = getUniformLocation(uniform);
+
+ if (location >= 0)
+ {
+ LLVector4 vec(v[0], 0, 0, 0);
+ const auto& iter = mValue.find(location);
+ if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
+ {
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+ glUniform1ivARB(location, count, v);
+ mValue[location] = vec;
+ }
+ }
+}
+
+void LLGLSLShader::uniform4iv(const LLStaticHashedString& uniform, U32 count, const GLint* v)
+{
+ GLint location = getUniformLocation(uniform);
+
+ if (location >= 0)
+ {
+ LLVector4 vec(v[0], v[1], v[2], v[3]);
+ const auto& iter = mValue.find(location);
+ if (iter == mValue.end() || shouldChange(iter->second, vec) || count != 1)
+ {
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
+ glUniform4ivARB(location, count, v);
+ mValue[location] = vec;
+ }
+ }
+}
+
void LLGLSLShader::uniform2i(const LLStaticHashedString& uniform, GLint i, GLint j)
{
GLint location = getUniformLocation(uniform);
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index 7d6b341d3d..fe0aaae467 100644
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -178,6 +178,7 @@ public:
void uniform3f(U32 index, GLfloat x, GLfloat y, GLfloat z);
void uniform4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
void uniform1iv(U32 index, U32 count, const GLint* i);
+ void uniform4iv(U32 index, U32 count, const GLint* i);
void uniform1fv(U32 index, U32 count, const GLfloat* v);
void uniform2fv(U32 index, U32 count, const GLfloat* v);
void uniform3fv(U32 index, U32 count, const GLfloat* v);
@@ -188,6 +189,8 @@ public:
void uniformMatrix3x4fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v);
void uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v);
void uniform1i(const LLStaticHashedString& uniform, GLint i);
+ void uniform1iv(const LLStaticHashedString& uniform, U32 count, const GLint* v);
+ void uniform4iv(const LLStaticHashedString& uniform, U32 count, const GLint* v);
void uniform1f(const LLStaticHashedString& uniform, GLfloat v);
void uniform2f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y);
void uniform3f(const LLStaticHashedString& uniform, GLfloat x, GLfloat y, GLfloat z);
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 9bd3a0a6b0..f2da859e23 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -1688,26 +1688,38 @@ void LLImageGL::syncToMainThread(LLGLuint new_tex_name)
LL_PROFILE_ZONE_NAMED("cglt - sync");
if (gGLManager.mHasSync)
{
- // post a sync to the main thread (will execute before tex name swap lambda below)
- // glFlush calls here are partly superstitious and partly backed by observation
- // on AMD hardware
- glFlush();
- auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
- glFlush();
- LL::WorkQueue::postMaybe(
- mMainQueue,
- [=]()
- {
- LL_PROFILE_ZONE_NAMED("cglt - wait sync");
- {
- LL_PROFILE_ZONE_NAMED("glWaitSync");
- glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
- }
+ if (gGLManager.mIsNVIDIA)
+ {
+ // wait for texture upload to finish before notifying main thread
+ // upload is complete
+ auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+ glFlush();
+ glClientWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
+ glDeleteSync(sync);
+ }
+ else
+ {
+ // post a sync to the main thread (will execute before tex name swap lambda below)
+ // glFlush calls here are partly superstitious and partly backed by observation
+ // on AMD hardware
+ glFlush();
+ auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+ glFlush();
+ LL::WorkQueue::postMaybe(
+ mMainQueue,
+ [=]()
{
- LL_PROFILE_ZONE_NAMED("glDeleteSync");
- glDeleteSync(sync);
- }
- });
+ LL_PROFILE_ZONE_NAMED("cglt - wait sync");
+ {
+ LL_PROFILE_ZONE_NAMED("glWaitSync");
+ glWaitSync(sync, 0, GL_TIMEOUT_IGNORED);
+ }
+ {
+ LL_PROFILE_ZONE_NAMED("glDeleteSync");
+ glDeleteSync(sync);
+ }
+ });
+ }
}
else
{
@@ -1726,6 +1738,7 @@ void LLImageGL::syncToMainThread(LLGLuint new_tex_name)
});
}
+
void LLImageGL::syncTexName(LLGLuint texname)
{
if (texname != 0)
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index a03a27cf94..3adb47f493 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -71,6 +71,7 @@ static const GLenum sGLTextureType[] =
GL_TEXTURE_2D,
GL_TEXTURE_RECTANGLE_ARB,
GL_TEXTURE_CUBE_MAP_ARB,
+ GL_TEXTURE_CUBE_MAP_ARRAY_ARB,
GL_TEXTURE_2D_MULTISAMPLE,
GL_TEXTURE_3D
};
@@ -888,6 +889,9 @@ void LLRender::init()
glCullFace(GL_BACK);
+ // necessary for reflection maps
+ glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+
if (sGLCoreProfile && !LLVertexBuffer::sUseVAO)
{ //bind a dummy vertex array object so we're core profile compliant
#ifdef GL_ARB_vertex_array_object
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index e2489876e4..095ed400f4 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -52,7 +52,7 @@ class LLTexture ;
#define LL_MATRIX_STACK_DEPTH 32
-class LLTexUnit
+class LLTexUnit
{
friend class LLRender;
public:
@@ -63,6 +63,7 @@ public:
TT_TEXTURE = 0, // Standard 2D Texture
TT_RECT_TEXTURE, // Non power of 2 texture
TT_CUBE_MAP, // 6-sided cube map texture
+ TT_CUBE_MAP_ARRAY, // Array of cube maps
TT_MULTISAMPLE_TEXTURE, // see GL_ARB_texture_multisample
TT_TEXTURE_3D, // standard 3D Texture
TT_NONE, // No texture type is currently enabled
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index cd7ec478bb..8e8f44e99b 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -712,8 +712,15 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
{
if (major_version >= 4)
{
- //set version to 400
- shader_code_text[shader_code_count++] = strdup("#version 400\n");
+ //set version to 400 or 420
+ if (minor_version >= 20)
+ {
+ shader_code_text[shader_code_count++] = strdup("#version 420\n");
+ }
+ else
+ {
+ shader_code_text[shader_code_count++] = strdup("#version 400\n");
+ }
}
else if (major_version == 3)
{
@@ -1155,7 +1162,7 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("bumpMap");
mReservedUniforms.push_back("bumpMap2");
mReservedUniforms.push_back("environmentMap");
- mReservedUniforms.push_back("reflectionMap");
+ mReservedUniforms.push_back("reflectionProbes");
mReservedUniforms.push_back("cloud_noise_texture");
mReservedUniforms.push_back("cloud_noise_texture_next");
mReservedUniforms.push_back("fullbright");
diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h
index 7ca4862ed9..663ba28b6d 100644
--- a/indra/llrender/llshadermgr.h
+++ b/indra/llrender/llshadermgr.h
@@ -80,7 +80,7 @@ public:
BUMP_MAP, // "bumpMap"
BUMP_MAP2, // "bumpMap2"
ENVIRONMENT_MAP, // "environmentMap"
- REFLECTION_MAP, // "reflectionMap"
+ REFLECTION_PROBES, // "reflectionProbes"
CLOUD_NOISE_MAP, // "cloud_noise_texture"
CLOUD_NOISE_MAP_NEXT, // "cloud_noise_texture_next"
FULLBRIGHT, // "fullbright"
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 20b708fe99..284b779be3 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -10269,6 +10269,17 @@
<integer>2</integer>
</map>
+ <key>RenderReflectionProbeDrawDistance</key>
+ <map>
+ <key>Comment</key>
+ <string>Camera far clip to use when updating reflection probes.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>64</real>
+ </map>
<key>RenderReflectionRes</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/app_settings/shaders/class1/deferred/aoUtil.glsl b/indra/newview/app_settings/shaders/class1/deferred/aoUtil.glsl
index 23adbded5e..73c125bbdc 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/aoUtil.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/aoUtil.glsl
@@ -29,8 +29,6 @@ uniform sampler2DRect depthMap;
uniform float ssao_radius;
uniform float ssao_max_radius;
-uniform float ssao_factor;
-uniform float ssao_factor_inv;
uniform mat4 inv_proj;
uniform vec2 screen_res;
@@ -83,14 +81,14 @@ float calcAmbientOcclusion(vec4 pos, vec3 norm, vec2 pos_screen)
{
float ret = 1.0;
vec3 pos_world = pos.xyz;
- vec2 noise_reflect = texture2D(noiseMap, pos_screen.xy/128.0).xy;
+
float angle_hidden = 0.0;
float points = 0;
- float scale = min(ssao_radius / -pos_world.z, ssao_max_radius);
-
// it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?)
+ float scale = min(ssao_radius / -pos_world.z, ssao_max_radius);
+ vec2 noise_reflect = texture2D(noiseMap, pos_screen.xy/128.0).xy;
for (int i = 0; i < 8; i++)
{
vec2 samppos_screen = pos_screen + scale * reflect(getKern(i), noise_reflect);
@@ -105,14 +103,14 @@ float calcAmbientOcclusion(vec4 pos, vec3 norm, vec2 pos_screen)
//(k should vary inversely with # of samples, but this is taken care of later)
float funky_val = (dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) ? 1.0 : 0.0;
- angle_hidden = angle_hidden + funky_val * min(1.0/dist2, ssao_factor_inv);
+ angle_hidden = angle_hidden + funky_val * min(1.0/dist2, 1.0);
// 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion"
float diffz_val = (diff.z > -1.0) ? 1.0 : 0.0;
points = points + diffz_val;
}
-
- angle_hidden = min(ssao_factor*angle_hidden/points, 1.0);
+
+ angle_hidden = min(angle_hidden/points, 1.0);
float points_val = (points > 0.0) ? 1.0 : 0.0;
ret = (1.0 - (points_val * angle_hidden));
diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
index 596d0274af..fa3634f3b6 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
@@ -69,36 +69,47 @@ void main()
tc_mod *= 2.0;
tc += ( (tc_mod - 0.5) * kern[1].z * dlt * 0.5 );
- for (int i = 1; i < 4; i++)
+ // TODO: move this to kern instead of building kernel per pixel
+ vec3 k[7];
+ k[0] = kern[0];
+ k[2] = kern[1];
+ k[4] = kern[2];
+ k[6] = kern[3];
+
+ k[1] = (k[0]+k[2])*0.5f;
+ k[3] = (k[2]+k[4])*0.5f;
+ k[5] = (k[4]+k[6])*0.5f;
+
+ for (int i = 1; i < 7; i++)
{
- vec2 samptc = tc + kern[i].z*dlt;
+ vec2 samptc = tc + k[i].z*dlt*2.0;
vec3 samppos = getPosition(samptc).xyz;
float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane
if (d*d <= pointplanedist_tolerance_pow2)
{
- col += texture2DRect(lightMap, samptc)*kern[i].xyxx;
- defined_weight += kern[i].xy;
+ col += texture2DRect(lightMap, samptc)*k[i].xyxx;
+ defined_weight += k[i].xy;
}
}
- for (int i = 1; i < 4; i++)
+ for (int i = 1; i < 7; i++)
{
- vec2 samptc = tc - kern[i].z*dlt;
+ vec2 samptc = tc - k[i].z*dlt*2.0;
vec3 samppos = getPosition(samptc).xyz;
float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane
if (d*d <= pointplanedist_tolerance_pow2)
{
- col += texture2DRect(lightMap, samptc)*kern[i].xyxx;
- defined_weight += kern[i].xy;
+ col += texture2DRect(lightMap, samptc)*k[i].xyxx;
+ defined_weight += k[i].xy;
}
}
col /= defined_weight.xyxx;
- col.y *= col.y;
+ //col.y *= max(col.y, 0.75);
frag_color = col;
diff --git a/indra/newview/app_settings/shaders/class1/interface/reflectionmipF.glsl b/indra/newview/app_settings/shaders/class1/interface/reflectionmipF.glsl
new file mode 100644
index 0000000000..ea687aab4f
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/interface/reflectionmipF.glsl
@@ -0,0 +1,75 @@
+/**
+ * @file reflectionmipF.glsl
+ *
+ * $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$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+/*[EXTRA_CODE_HERE]*/
+
+#ifdef DEFINE_GL_FRAGCOLOR
+out vec4 frag_color;
+#else
+#define frag_color gl_FragColor
+#endif
+
+uniform sampler2DRect screenMap;
+
+VARYING vec2 vary_texcoord0;
+
+void main()
+{
+ float w[9];
+
+ float c = 1.0/16.0; //corner weight
+ float e = 1.0/8.0; //edge weight
+ float m = 1.0/4.0; //middle weight
+
+ //float wsum = c*4+e*4+m;
+
+ w[0] = c; w[1] = e; w[2] = c;
+ w[3] = e; w[4] = m; w[5] = e;
+ w[6] = c; w[7] = e; w[8] = c;
+
+ vec2 tc[9];
+
+ float ed = 1;
+ float cd = 1;
+
+
+ tc[0] = vec2(-cd, cd); tc[1] = vec2(0, ed); tc[2] = vec2(cd, cd);
+ tc[3] = vec2(-ed, 0); tc[4] = vec2(0, 0); tc[5] = vec2(ed, 0);
+ tc[6] = vec2(-cd, -cd); tc[7] = vec2(0, -ed); tc[8] = vec2(cd, -1);
+
+ vec3 color = vec3(0,0,0);
+
+ for (int i = 0; i < 9; ++i)
+ {
+ color += texture2DRect(screenMap, vary_texcoord0.xy+tc[i]).rgb * w[i];
+ //color += texture2DRect(screenMap, vary_texcoord0.xy+tc[i]*2.0).rgb * w[i]*0.5;
+ }
+
+ //color /= wsum;
+
+ frag_color = vec4(color, 1.0);
+}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
index 5bb64e18a7..3a1287e910 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
@@ -26,9 +26,10 @@
#extension GL_ARB_texture_rectangle : enable
#extension GL_ARB_shader_texture_lod : enable
-/*[EXTRA_CODE_HERE]*/
+#define FLT_MAX 3.402823466e+38
-#define REFMAP_COUNT 8
+#define REFMAP_COUNT 256
+#define REF_SAMPLE_COUNT 64 //maximum number of samples to consider
#ifdef DEFINE_GL_FRAGCOLOR
out vec4 frag_color;
@@ -42,12 +43,26 @@ uniform sampler2DRect normalMap;
uniform sampler2DRect lightMap;
uniform sampler2DRect depthMap;
uniform samplerCube environmentMap;
-uniform samplerCube reflectionMap[REFMAP_COUNT];
+uniform samplerCubeArray reflectionProbes;
uniform sampler2D lightFunc;
-uniform int refmapCount;
-
-uniform vec3 refOrigin[REFMAP_COUNT];
+layout (std140, binding = 1) uniform ReflectionProbes
+{
+ // list of sphere based reflection probes sorted by distance to camera (closest first)
+ vec4 refSphere[REFMAP_COUNT];
+ // index of cube map in reflectionProbes for a corresponding reflection probe
+ // e.g. cube map channel of refSphere[2] is stored in refIndex[2]
+ // refIndex.x - cubemap channel in reflectionProbes
+ // refIndex.y - index in refNeighbor of neighbor list (index is ivec4 index, not int index)
+ // refIndex.z - number of neighbors
+ ivec4 refIndex[REFMAP_COUNT];
+
+ // neighbor list data (refSphere indices, not cubemap array layer)
+ ivec4 refNeighbor[1024];
+
+ // number of reflection probes present in refSphere
+ int refmapCount;
+};
uniform float blur_size;
uniform float blur_fidelity;
@@ -80,7 +95,116 @@ vec3 srgb_to_linear(vec3 c);
vec4 applyWaterFogView(vec3 pos, vec4 color);
#endif
+// list of probeIndexes shader will actually use after "getRefIndex" is called
+// (stores refIndex/refSphere indices, NOT rerflectionProbes layer)
+int probeIndex[REF_SAMPLE_COUNT];
+
+// number of probes stored in probeIndex
+int probeInfluences = 0;
+
+
+// return true if probe at index i influences position pos
+bool shouldSampleProbe(int i, vec3 pos)
+{
+ vec3 delta = pos.xyz - refSphere[i].xyz;
+ float d = dot(delta, delta);
+ float r2 = refSphere[i].w;
+ r2 *= r2;
+ return d < r2;
+}
+
+// populate "probeIndex" with N probe indices that influence pos where N is REF_SAMPLE_COUNT
+// overall algorithm --
+void getRefIndex(vec3 pos)
+{
+ // TODO: make some sort of structure that reduces the number of distance checks
+ for (int i = 0; i < refmapCount; ++i)
+ {
+ // found an influencing probe
+ if (shouldSampleProbe(i, pos))
+ {
+ probeIndex[probeInfluences] = i;
+ ++probeInfluences;
+
+ int neighborIdx = refIndex[i].y;
+ if (neighborIdx != -1)
+ {
+ int neighborCount = min(refIndex[i].z, REF_SAMPLE_COUNT-1);
+
+ int count = 0;
+ while (count < neighborCount)
+ {
+ // check up to REF_SAMPLE_COUNT-1 neighbors (neighborIdx is ivec4 index)
+
+ int idx = refNeighbor[neighborIdx].x;
+ if (shouldSampleProbe(idx, pos))
+ {
+ probeIndex[probeInfluences++] = idx;
+ if (probeInfluences == REF_SAMPLE_COUNT)
+ {
+ return;
+ }
+ }
+ count++;
+ if (count == neighborCount)
+ {
+ return;
+ }
+
+ idx = refNeighbor[neighborIdx].y;
+ if (shouldSampleProbe(idx, pos))
+ {
+ probeIndex[probeInfluences++] = idx;
+ if (probeInfluences == REF_SAMPLE_COUNT)
+ {
+ return;
+ }
+ }
+ count++;
+ if (count == neighborCount)
+ {
+ return;
+ }
+
+ idx = refNeighbor[neighborIdx].z;
+ if (shouldSampleProbe(idx, pos))
+ {
+ probeIndex[probeInfluences++] = idx;
+ if (probeInfluences == REF_SAMPLE_COUNT)
+ {
+ return;
+ }
+ }
+ count++;
+ if (count == neighborCount)
+ {
+ return;
+ }
+
+ idx = refNeighbor[neighborIdx].w;
+ if (shouldSampleProbe(idx, pos))
+ {
+ probeIndex[probeInfluences++] = idx;
+ if (probeInfluences == REF_SAMPLE_COUNT)
+ {
+ return;
+ }
+ }
+ count++;
+ if (count == neighborCount)
+ {
+ return;
+ }
+
+ ++neighborIdx;
+ }
+
+ return;
+ }
+ }
+ }
+}
// from https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection
@@ -120,13 +244,10 @@ bool intersect(const Ray &ray) const
} */
// adapted -- assume that origin is inside sphere, return distance from origin to edge of sphere
-float sphereIntersect(vec3 origin, vec3 dir, vec4 sph )
+float sphereIntersect(vec3 origin, vec3 dir, vec3 center, float radius2)
{
float t0, t1; // solutions for t if the ray intersects
- vec3 center = sph.xyz;
- float radius2 = sph.w * sph.w;
-
vec3 L = center - origin;
float tca = dot(L,dir);
@@ -139,33 +260,78 @@ float sphereIntersect(vec3 origin, vec3 dir, vec4 sph )
return t1;
}
+// Tap a sphere based reflection probe
+// pos - position of pixel
+// dir - pixel normal
+// lod - which mip to bias towards (lower is higher res, sharper reflections)
+// c - center of probe
+// r2 - radius of probe squared
+// i - index of probe
+// vi - point at which reflection vector struck the influence volume, in clip space
+vec3 tapRefMap(vec3 pos, vec3 dir, float lod, vec3 c, float r2, int i, out vec3 vi)
+{
+ //lod = max(lod, 1);
+// parallax adjustment
+ float d = sphereIntersect(pos, dir, c, r2);
+
+ {
+ vec3 v = pos + dir * d;
+ vi = v;
+ v -= c.xyz;
+ v = env_mat * v;
+
+ float min_lod = textureQueryLod(reflectionProbes,v).y; // lower is higher res
+ return textureLod(reflectionProbes, vec4(v.xyz, refIndex[i].x), max(min_lod, lod)).rgb;
+ //return texture(reflectionProbes, vec4(v.xyz, refIndex[i].x)).rgb;
+ }
+}
+
vec3 sampleRefMap(vec3 pos, vec3 dir, float lod)
{
float wsum = 0.0;
-
vec3 col = vec3(0,0,0);
+ float vd2 = dot(pos,pos); // view distance squared
- for (int i = 0; i < refmapCount; ++i)
- //int i = 0;
+ for (int idx = 0; idx < probeInfluences; ++idx)
{
- float r = 16.0;
- vec3 delta = pos.xyz-refOrigin[i].xyz;
- if (length(delta) < r)
+ int i = probeIndex[idx];
+ float r = refSphere[i].w; // radius of sphere volume
+ float rr = r*r; // radius squred
+ float r1 = r * 0.1; // 75% of radius (outer sphere to start interpolating down)
+ vec3 delta = pos.xyz-refSphere[i].xyz;
+ float d2 = dot(delta,delta);
+ float r2 = r1*r1;
+
{
- float w = 1.0/max(dot(delta, delta), r);
- w *= w;
- w *= w;
+ vec3 vi;
+ vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, rr, i, vi);
+
+ float w = 1.0/d2;
- // parallax adjustment
- float d = sphereIntersect(pos, dir, vec4(refOrigin[i].xyz, r));
+ float atten = 1.0-max(d2-r2, 0.0)/(rr-r2);
+ w *= atten;
- {
- vec3 v = pos + dir * d;
- v -= refOrigin[i].xyz;
- v = env_mat * v;
+ col += refcol*w;
+
+ wsum += w;
+ }
+ }
- float min_lod = textureQueryLod(reflectionMap[i],v).y; // lower is higher res
- col += textureLod(reflectionMap[i], v, max(min_lod, lod)).rgb*w;
+ if (probeInfluences <= 1)
+ { //edge-of-scene probe or no probe influence, mix in with embiggened version of probes closest to camera
+ for (int idx = 0; idx < 8; ++idx)
+ {
+ int i = idx;
+ vec3 delta = pos.xyz-refSphere[i].xyz;
+ float d2 = dot(delta,delta);
+
+ {
+ vec3 vi;
+ vec3 refcol = tapRefMap(pos, dir, lod, refSphere[i].xyz, d2, i, vi);
+
+ float w = 1.0/d2;
+ w *= w;
+ col += refcol*w;
wsum += w;
}
}
@@ -175,13 +341,6 @@ vec3 sampleRefMap(vec3 pos, vec3 dir, float lod)
{
col *= 1.0/wsum;
}
- else
- {
- // this pixel not covered by a probe, fallback to "full scene" environment map
- vec3 v = env_mat * dir;
- float min_lod = textureQueryLod(environmentMap, v).y; // lower is higher res
- col = textureLod(environmentMap, v, max(min_lod, lod)).rgb;
- }
return col;
}
@@ -202,13 +361,26 @@ vec3 sampleAmbient(vec3 pos, vec3 dir, float lod)
col *= 0.333333;
- return col*0.6; // fudge darker
+ return col*0.8; // fudge darker
}
+// brighten a color so that at least one component is 1
+vec3 brighten(vec3 c)
+{
+ float m = max(max(c.r, c.g), c.b);
+
+ if (m == 0)
+ {
+ return vec3(1,1,1);
+ }
+
+ return c * 1.0/m;
+}
+
void main()
{
- float reflection_lods = 11; // TODO -- base this on resolution of reflection map instead of hard coding
+ float reflection_lods = 8; // TODO -- base this on resolution of reflection map instead of hard coding
vec2 tc = vary_fragcoord.xy;
float depth = texture2DRect(depthMap, tc.xy).r;
@@ -238,14 +410,16 @@ void main()
vec3 amblit;
vec3 additive;
vec3 atten;
+
+ getRefIndex(pos.xyz);
+
calcAtmosphericVars(pos.xyz, light_dir, ambocc, sunlit, amblit, additive, atten, true);
//vec3 amb_vec = env_mat * norm.xyz;
- vec3 ambenv = sampleAmbient(pos.xyz, norm.xyz, reflection_lods-1);
- amblit = mix(ambenv, amblit, amblit);
- color.rgb = amblit;
-
+ vec3 ambenv = sampleAmbient(pos.xyz, norm.xyz, reflection_lods);
+ amblit = max(ambenv, amblit);
+ color.rgb = amblit*ambocc;
//float ambient = min(abs(dot(norm.xyz, sun_dir.xyz)), 1.0);
//ambient *= 0.5;
@@ -255,6 +429,7 @@ void main()
vec3 sun_contrib = min(da, scol) * sunlit;
color.rgb += sun_contrib;
+ color.rgb = min(color.rgb, vec3(1,1,1));
color.rgb *= diffuse.rgb;
vec3 refnormpersp = reflect(pos.xyz, norm.xyz);
@@ -274,26 +449,23 @@ void main()
float lod = (1.0-spec.a)*reflection_lods;
vec3 reflected_color = sampleRefMap(pos.xyz, normalize(refnormpersp), lod);
- reflected_color *= 0.5; // fudge darker, not sure where there's a multiply by two and it's late
+ reflected_color *= 0.35; // fudge darker
float fresnel = 1.0+dot(normalize(pos.xyz), norm.xyz);
- fresnel += spec.a;
- fresnel *= fresnel;
- //fresnel *= spec.a;
+ float minf = spec.a * 0.1;
+ fresnel = fresnel * (1.0-minf) + minf;
reflected_color *= spec.rgb*min(fresnel, 1.0);
- //reflected_color = srgb_to_linear(reflected_color);
- vec3 mixer = clamp(color.rgb + vec3(1,1,1) - spec.rgb, vec3(0,0,0), vec3(1,1,1));
- color.rgb = mix(reflected_color, color, mixer);
+ color.rgb += reflected_color;
}
color.rgb = mix(color.rgb, diffuse.rgb, diffuse.a);
if (envIntensity > 0.0)
{ // add environmentmap
- vec3 reflected_color = sampleRefMap(pos.xyz, normalize(refnormpersp), 0.0);
+ vec3 reflected_color = sampleRefMap(pos.xyz, normalize(refnormpersp), 0.0)*0.5; //fudge darker
float fresnel = 1.0+dot(normalize(pos.xyz), norm.xyz);
fresnel *= fresnel;
- fresnel = fresnel * 0.95 + 0.05;
- reflected_color *= fresnel;
+ fresnel = min(fresnel+envIntensity, 1.0);
+ reflected_color *= (envIntensity*fresnel)*brighten(spec.rgb);
color = mix(color.rgb, reflected_color, envIntensity);
}
@@ -311,5 +483,7 @@ void main()
// convert to linear as fullscreen lights need to sum in linear colorspace
// and will be gamma (re)corrected downstream...
+ //color = vec3(ambocc);
+ //color = ambenv;
frag_color.rgb = srgb_to_linear(color.rgb);
}
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index 84a41113be..8d02bec53e 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -1188,12 +1188,18 @@ void LLAgentCamera::updateLookAt(const S32 mouse_x, const S32 mouse_y)
static LLTrace::BlockTimerStatHandle FTM_UPDATE_CAMERA("Camera");
+extern BOOL gCubeSnapshot;
+
//-----------------------------------------------------------------------------
// updateCamera()
//-----------------------------------------------------------------------------
void LLAgentCamera::updateCamera()
{
LL_RECORD_BLOCK_TIME(FTM_UPDATE_CAMERA);
+ if (gCubeSnapshot)
+ {
+ return;
+ }
// - changed camera_skyward to the new global "mCameraUpVector"
mCameraUpVector = LLVector3::z_axis;
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index eebd89f77f..47330debd3 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -129,6 +129,8 @@ static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma, bool d
}
}
+extern BOOL gCubeSnapshot;
+
void LLDrawPoolAlpha::renderPostDeferred(S32 pass)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
@@ -155,7 +157,7 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass)
forwardRender();
// final pass, render to depth for depth of field effects
- if (!LLPipeline::sImpostorRender && gSavedSettings.getBOOL("RenderDepthOfField"))
+ if (!LLPipeline::sImpostorRender && gSavedSettings.getBOOL("RenderDepthOfField") && !gCubeSnapshot)
{
//update depth buffer sampler
gPipeline.mScreen.flush();
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 2892fc6f9f..0df0137b7a 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -735,6 +735,7 @@ void LLDrawPoolBump::renderDeferred(S32 pass)
void LLDrawPoolBump::renderPostDeferred(S32 pass)
{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL
for (int i = 0; i < 2; ++i)
{ // two passes -- static and rigged
mRigged = (i == 1);
diff --git a/indra/newview/lldrawpoolpbropaque.cpp b/indra/newview/lldrawpoolpbropaque.cpp
index 64850424f4..2478aa0cff 100644
--- a/indra/newview/lldrawpoolpbropaque.cpp
+++ b/indra/newview/lldrawpoolpbropaque.cpp
@@ -87,6 +87,6 @@ void LLDrawPoolPBROpaque::renderDeferred(S32 pass)
// TODO: handle under water?
// if (LLPipeline::sUnderWaterRender)
// PASS_SIMPLE or PASS_MATERIAL
- pushBatches(LLRenderPass::PASS_SIMPLE, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+ //pushBatches(LLRenderPass::PASS_SIMPLE, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
}
diff --git a/indra/newview/llreflectionmap.cpp b/indra/newview/llreflectionmap.cpp
index b75dba877e..0cf2f22822 100644
--- a/indra/newview/llreflectionmap.cpp
+++ b/indra/newview/llreflectionmap.cpp
@@ -29,36 +29,183 @@
#include "llreflectionmap.h"
#include "pipeline.h"
#include "llviewerwindow.h"
+#include "llviewerregion.h"
+
+extern F32SecondsImplicit gFrameTimeSeconds;
LLReflectionMap::LLReflectionMap()
{
+ mLastUpdateTime = gFrameTimeSeconds;
}
-void LLReflectionMap::update(const LLVector3& origin, U32 resolution)
+void LLReflectionMap::update(U32 resolution, U32 face)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
+ mLastUpdateTime = gFrameTimeSeconds;
+ llassert(mCubeArray.notNull());
+ llassert(mCubeIndex != -1);
llassert(LLPipeline::sRenderDeferred);
-
- // make sure resolution is < gPipeline.mDeferredScreen.getWidth()
-
+
+ // make sure we don't walk off the edge of the render target
while (resolution > gPipeline.mDeferredScreen.getWidth() ||
resolution > gPipeline.mDeferredScreen.getHeight())
{
resolution /= 2;
}
+ gViewerWindow->cubeSnapshot(LLVector3(mOrigin), mCubeArray, mCubeIndex, face);
+}
- if (resolution == 0)
- {
- return;
+bool LLReflectionMap::shouldUpdate()
+{
+ const F32 UPDATE_INTERVAL = 10.f; // update no more than this often
+ const F32 TIMEOUT_INTERVAL = 30.f; // update no less than this often
+ const F32 RENDER_TIMEOUT = 1.f; // don't update if hasn't been used for rendering for this long
+
+ if (mLastBindTime > gFrameTimeSeconds - RENDER_TIMEOUT)
+ {
+ if (mDirty && mLastUpdateTime < gFrameTimeSeconds - UPDATE_INTERVAL)
+ {
+ return true;
+ }
+
+ if (mLastUpdateTime < gFrameTimeSeconds - TIMEOUT_INTERVAL)
+ {
+ return true;
+ }
}
- mOrigin.load3(origin.mV);
+ return false;
+}
+
+void LLReflectionMap::dirty()
+{
+ mDirty = true;
+ mLastUpdateTime = gFrameTimeSeconds;
+}
+
+void LLReflectionMap::autoAdjustOrigin()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
+
+ if (mGroup)
+ {
+ const LLVector4a* bounds = mGroup->getBounds();
+ auto* node = mGroup->getOctreeNode();
+
+ if (mGroup->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_TERRAIN)
+ {
+ // for terrain, make probes float a couple meters above the highest point in the surface patch
+ mOrigin = bounds[0];
+ mOrigin.getF32ptr()[2] += bounds[1].getF32ptr()[2] + 3.f;
+
+ // update radius to encompass bounding box
+ LLVector4a d;
+ d.setAdd(bounds[0], bounds[1]);
+ d.sub(mOrigin);
+ mRadius = d.getLength3().getF32();
+ }
+ else if (mGroup->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_VOLUME)
+ {
+ // cast a ray towards 8 corners of bounding box
+ // nudge origin towards center of empty space
+
+ if (node->isLeaf() || node->getChildCount() > 1 || node->getData().size() > 0)
+ { // use center of object bounding box for leaf nodes or nodes with multiple child nodes
+ mOrigin = bounds[0];
- mCubeMap = new LLCubeMap(false);
- mCubeMap->initReflectionMap(resolution);
+ LLVector4a start;
+ LLVector4a end;
- gViewerWindow->cubeSnapshot(origin, mCubeMap);
+ LLVector4a size = bounds[1];
- mCubeMap->generateMipMaps();
+ LLVector4a corners[] =
+ {
+ { 1, 1, 1 },
+ { -1, 1, 1 },
+ { 1, -1, 1 },
+ { -1, -1, 1 },
+ { 1, 1, -1 },
+ { -1, 1, -1 },
+ { 1, -1, -1 },
+ { -1, -1, -1 }
+ };
+
+ for (int i = 0; i < 8; ++i)
+ {
+ corners[i].mul(size);
+ corners[i].add(bounds[0]);
+ }
+
+ LLVector4a extents[2];
+ extents[0].setAdd(bounds[0], bounds[1]);
+ extents[1].setSub(bounds[0], bounds[1]);
+
+ bool hit = false;
+ for (int i = 0; i < 8; ++i)
+ {
+ int face = -1;
+ LLVector4a intersection;
+ LLDrawable* drawable = mGroup->lineSegmentIntersect(bounds[0], corners[i], true, false, &face, &intersection);
+ if (drawable != nullptr)
+ {
+ hit = true;
+ update_min_max(extents[0], extents[1], intersection);
+ }
+ else
+ {
+ update_min_max(extents[0], extents[1], corners[i]);
+ }
+ }
+
+ if (hit)
+ {
+ mOrigin.setAdd(extents[0], extents[1]);
+ mOrigin.mul(0.5f);
+ }
+
+ // make sure radius encompasses all objects
+ LLSimdScalar r2 = 0.0;
+ for (int i = 0; i < 8; ++i)
+ {
+ LLVector4a v;
+ v.setSub(corners[i], mOrigin);
+
+ LLSimdScalar d = v.dot3(v);
+
+ if (d > r2)
+ {
+ r2 = d;
+ }
+ }
+
+ mRadius = llmax(sqrtf(r2.getF32()), 8.f);
+ }
+ else
+ {
+ // use center of octree node volume for nodes that are just branches without data
+ mOrigin = node->getCenter();
+
+ // update radius to encompass entire octree node volume
+ mRadius = node->getSize().getLength3().getF32();
+
+ //mOrigin = bounds[0];
+ //mRadius = bounds[1].getLength3().getF32();
+
+ }
+ }
+ }
}
+bool LLReflectionMap::intersects(LLReflectionMap* other)
+{
+ LLVector4a delta;
+ delta.setSub(other->mOrigin, mOrigin);
+
+ F32 dist = delta.dot3(delta).getF32();
+
+ F32 r2 = mRadius + other->mRadius;
+
+ r2 *= r2;
+
+ return dist < r2;
+}
diff --git a/indra/newview/llreflectionmap.h b/indra/newview/llreflectionmap.h
index 7d39e7e562..ed1c2680b6 100644
--- a/indra/newview/llreflectionmap.h
+++ b/indra/newview/llreflectionmap.h
@@ -26,26 +26,61 @@
#pragma once
-#include "llcubemap.h"
+#include "llcubemaparray.h"
+#include "llmemory.h"
-class LLReflectionMap : public LLRefCount
+class LLSpatialGroup;
+
+class alignas(16) LLReflectionMap : public LLRefCount
{
+ LL_ALIGN_NEW
public:
// allocate an environment map of the given resolution
LLReflectionMap();
// update this environment map
- // origin - position in agent space to generate environment map from in agent space
// resolution - size of cube map to generate
- void update(const LLVector3& origin, U32 resolution);
-
- // point at which environment map was generated from (in agent space)
- LLVector4a mOrigin;
+ void update(U32 resolution, U32 face);
+
+ // return true if this probe should update *now*
+ bool shouldUpdate();
+ // Mark this reflection map as needing an update (resets last update time, so spamming this call will cause a cube map to never update)
+ void dirty();
+
+ // for volume partition probes, try to place this probe in the best spot
+ void autoAdjustOrigin();
+
+ // return true if given Reflection Map's influence volume intersect's with this one's
+ bool intersects(LLReflectionMap* other);
+
+ // point at which environment map was last generated from (in agent space)
+ LLVector4a mOrigin;
+
// distance from viewer camera
F32 mDistance;
+ // radius of this probe's affected area
+ F32 mRadius = 16.f;
+
+ // last time this probe was updated (or when its update timer got reset)
+ F32 mLastUpdateTime = 0.f;
+
+ // last time this probe was bound for rendering
+ F32 mLastBindTime = 0.f;
+
// cube map used to sample this environment map
- LLPointer<LLCubeMap> mCubeMap;
+ LLPointer<LLCubeMapArray> mCubeArray;
+ S32 mCubeIndex = -1; // index into cube map array or -1 if not currently stored in cube map array
+
+ // index into array packed by LLReflectionMapManager::getReflectionMaps
+ // WARNING -- only valid immediately after call to getReflectionMaps
+ S32 mProbeIndex = -1;
+
+ // set of any LLReflectionMaps that intersect this map (maintained by LLReflectionMapManager
+ std::vector<LLReflectionMap*> mNeighbors;
+
+ LLSpatialGroup* mGroup = nullptr;
+ bool mDirty = true;
};
diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp
index 95b72e1d3b..a6b704d57d 100644
--- a/indra/newview/llreflectionmapmanager.cpp
+++ b/indra/newview/llreflectionmapmanager.cpp
@@ -28,30 +28,84 @@
#include "llreflectionmapmanager.h"
#include "llviewercamera.h"
+#include "llspatialpartition.h"
+#include "llviewerregion.h"
+#include "pipeline.h"
+#include "llviewershadermgr.h"
+
+extern BOOL gCubeSnapshot;
+extern BOOL gTeleportDisplay;
+
+//#pragma optimize("", off)
LLReflectionMapManager::LLReflectionMapManager()
{
-
+ for (int i = 0; i < LL_REFLECTION_PROBE_COUNT; ++i)
+ {
+ mCubeFree[i] = true;
+ }
}
struct CompareReflectionMapDistance
{
-
+
};
struct CompareProbeDistance
{
- bool operator()(const LLReflectionMap& lhs, const LLReflectionMap& rhs)
+ bool operator()(const LLPointer<LLReflectionMap>& lhs, const LLPointer<LLReflectionMap>& rhs)
{
- return lhs.mDistance < rhs.mDistance;
+ return lhs->mDistance < rhs->mDistance;
}
};
// helper class to seed octree with probes
void LLReflectionMapManager::update()
{
+ if (!LLPipeline::sRenderDeferred || gTeleportDisplay)
+ {
+ return;
+ }
+
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
+ llassert(!gCubeSnapshot); // assert a snapshot is not in progress
+ if (LLAppViewer::instance()->logoutRequestSent())
+ {
+ return;
+ }
+
+ // =============== TODO -- move to an init function =================
+
+ if (mTexture.isNull())
+ {
+ mTexture = new LLCubeMapArray();
+ mTexture->allocate(LL_REFLECTION_PROBE_RESOLUTION, 3, LL_REFLECTION_PROBE_COUNT);
+ }
+
+ if (!mRenderTarget.isComplete())
+ {
+ U32 color_fmt = GL_RGBA;
+ const bool use_depth_buffer = true;
+ const bool use_stencil_buffer = true;
+ U32 targetRes = LL_REFLECTION_PROBE_RESOLUTION * 4; // super sample
+ mRenderTarget.allocate(targetRes, targetRes, color_fmt, use_depth_buffer, use_stencil_buffer, LLTexUnit::TT_RECT_TEXTURE);
+ }
+
+ if (mMipChain.empty())
+ {
+ U32 res = LL_REFLECTION_PROBE_RESOLUTION*2;
+ U32 count = log2((F32)res) + 0.5f;
+
+ mMipChain.resize(count);
+ for (int i = 0; i < count; ++i)
+ {
+ mMipChain[i].allocate(res, res, GL_RGB, false, false, LLTexUnit::TT_RECT_TEXTURE);
+ res /= 2;
+ }
+ }
+
+ // =============== TODO -- move to an init function =================
// naively drop probes every 16m as we move the camera around for now
// later, use LLSpatialPartition to manage probes
@@ -61,46 +115,462 @@ void LLReflectionMapManager::update()
LLVector4a camera_pos;
camera_pos.load3(LLViewerCamera::instance().getOrigin().mV);
- for (auto& probe : mProbes)
+ // process kill list
+ for (int i = 0; i < mProbes.size(); )
{
- LLVector4a d;
- d.setSub(camera_pos, probe.mOrigin);
- probe.mDistance = d.getLength3().getF32();
+ auto& iter = std::find(mKillList.begin(), mKillList.end(), mProbes[i]);
+ if (iter != mKillList.end())
+ {
+ deleteProbe(i);
+ mProbes.erase(mProbes.begin() + i);
+ mKillList.erase(iter);
+ }
+ else
+ {
+ ++i;
+ }
}
- if (mProbes.empty() || mProbes[0].mDistance > PROBE_SPACING)
+ mKillList.clear();
+
+ // process create list
+ for (auto& probe : mCreateList)
{
- addProbe(LLViewerCamera::instance().getOrigin());
+ mProbes.push_back(probe);
}
- // update distance to camera for all probes
- std::sort(mProbes.begin(), mProbes.end(), CompareProbeDistance());
+ mCreateList.clear();
+
+ const F32 UPDATE_INTERVAL = 10.f; //update no more than once every 5 seconds
+
+ bool did_update = false;
+
+ if (mUpdatingProbe != nullptr)
+ {
+ did_update = true;
+ doProbeUpdate();
+ }
- if (mProbes.size() > MAX_PROBES)
+ for (int i = 0; i < mProbes.size(); ++i)
{
- mProbes.resize(MAX_PROBES);
+ LLReflectionMap* probe = mProbes[i];
+ if (probe->getNumRefs() == 1)
+ { // no references held outside manager, delete this probe
+ deleteProbe(i);
+ --i;
+ continue;
+ }
+
+ probe->mProbeIndex = i;
+
+ LLVector4a d;
+
+ if (probe->shouldUpdate() && !did_update && i < LL_REFLECTION_PROBE_COUNT)
+ {
+ if (probe->mCubeIndex == -1)
+ {
+ probe->mCubeArray = mTexture;
+ probe->mCubeIndex = allocateCubeIndex();
+ }
+
+ did_update = true; // only update one probe per frame
+ probe->autoAdjustOrigin();
+
+ mUpdatingProbe = probe;
+ doProbeUpdate();
+ probe->mDirty = false;
+ }
+
+ d.setSub(camera_pos, probe->mOrigin);
+ probe->mDistance = d.getLength3().getF32()-probe->mRadius;
}
+
+ // update distance to camera for all probes
+ std::sort(mProbes.begin(), mProbes.end(), CompareProbeDistance());
}
void LLReflectionMapManager::addProbe(const LLVector3& pos)
{
- LLReflectionMap probe;
- probe.update(pos, 1024);
- mProbes.push_back(probe);
+ //LLReflectionMap* probe = new LLReflectionMap();
+ //probe->update(pos, 1024);
+ //mProbes.push_back(probe);
+}
+
+LLReflectionMap* LLReflectionMapManager::addProbe(LLSpatialGroup* group)
+{
+ LLReflectionMap* probe = new LLReflectionMap();
+ probe->mGroup = group;
+ probe->mOrigin = group->getOctreeNode()->getCenter();
+ probe->mDirty = true;
+
+ if (gCubeSnapshot)
+ { //snapshot is in progress, mProbes is being iterated over, defer insertion until next update
+ mCreateList.push_back(probe);
+ }
+ else
+ {
+ mProbes.push_back(probe);
+ }
+
+ return probe;
}
void LLReflectionMapManager::getReflectionMaps(std::vector<LLReflectionMap*>& maps)
{
- // just null out for now
- U32 i = 0;
- for (i = 0; i < maps.size() && i < mProbes.size(); ++i)
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
+
+ U32 count = 0;
+ U32 lastIdx = 0;
+ for (U32 i = 0; count < maps.size() && i < mProbes.size(); ++i)
+ {
+ mProbes[i]->mLastBindTime = gFrameTimeSeconds; // something wants to use this probe, indicate it's been requested
+ if (mProbes[i]->mCubeIndex != -1)
+ {
+ mProbes[i]->mProbeIndex = count;
+ maps[count++] = mProbes[i];
+ }
+ else
+ {
+ mProbes[i]->mProbeIndex = -1;
+ }
+ lastIdx = i;
+ }
+
+ // set remaining probe indices to -1
+ for (U32 i = lastIdx+1; i < mProbes.size(); ++i)
+ {
+ mProbes[i]->mProbeIndex = -1;
+ }
+
+ // null terminate list
+ if (count < maps.size())
+ {
+ maps[count] = nullptr;
+ }
+}
+
+LLReflectionMap* LLReflectionMapManager::registerSpatialGroup(LLSpatialGroup* group)
+{
+ if (group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_VOLUME)
+ {
+ OctreeNode* node = group->getOctreeNode();
+ F32 size = node->getSize().getF32ptr()[0];
+ if (size >= 7.f && size <= 17.f)
+ {
+ return addProbe(group);
+ }
+ }
+
+ if (group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_TERRAIN)
+ {
+ OctreeNode* node = group->getOctreeNode();
+ F32 size = node->getSize().getF32ptr()[0];
+ if (size >= 15.f && size <= 17.f)
+ {
+ return addProbe(group);
+ }
+ }
+
+ return nullptr;
+}
+
+S32 LLReflectionMapManager::allocateCubeIndex()
+{
+ for (int i = 0; i < LL_REFLECTION_PROBE_COUNT; ++i)
+ {
+ if (mCubeFree[i])
+ {
+ mCubeFree[i] = false;
+ return i;
+ }
+ }
+
+ // no cubemaps free, steal one from the back of the probe list
+ for (int i = mProbes.size() - 1; i >= LL_REFLECTION_PROBE_COUNT; --i)
+ {
+ if (mProbes[i]->mCubeIndex != -1)
+ {
+ S32 ret = mProbes[i]->mCubeIndex;
+ mProbes[i]->mCubeIndex = -1;
+ return ret;
+ }
+ }
+
+ llassert(false); // should never fail to allocate, something is probably wrong with mCubeFree
+ return -1;
+}
+
+void LLReflectionMapManager::deleteProbe(U32 i)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
+ LLReflectionMap* probe = mProbes[i];
+
+ if (probe->mCubeIndex != -1)
+ { // mark the cube index used by this probe as being free
+ mCubeFree[probe->mCubeIndex] = true;
+ }
+ if (mUpdatingProbe == probe)
+ {
+ mUpdatingProbe = nullptr;
+ mUpdatingFace = 0;
+ }
+
+ // remove from any Neighbors lists
+ for (auto& other : probe->mNeighbors)
+ {
+ auto& iter = std::find(other->mNeighbors.begin(), other->mNeighbors.end(), probe);
+ llassert(iter != other->mNeighbors.end());
+ other->mNeighbors.erase(iter);
+ }
+
+ mProbes.erase(mProbes.begin() + i);
+}
+
+
+void LLReflectionMapManager::doProbeUpdate()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
+ llassert(mUpdatingProbe != nullptr);
+
+ mRenderTarget.bindTarget();
+ mUpdatingProbe->update(mRenderTarget.getWidth(), mUpdatingFace);
+ mRenderTarget.flush();
+
+ // generate mipmaps
{
- maps[i] = &(mProbes[i]);
+ LLGLDepthTest depth(GL_FALSE, GL_FALSE);
+ LLGLDisable cull(GL_CULL_FACE);
+
+ gReflectionMipProgram.bind();
+ gGL.matrixMode(gGL.MM_MODELVIEW);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+
+ gGL.matrixMode(gGL.MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+
+ gGL.flush();
+ U32 res = LL_REFLECTION_PROBE_RESOLUTION*4;
+
+ S32 mips = log2((F32) LL_REFLECTION_PROBE_RESOLUTION)+0.5f;
+
+ for (int i = 0; i < mMipChain.size(); ++i)
+ {
+ mMipChain[i].bindTarget();
+
+ if (i == 0)
+ {
+ gGL.getTexUnit(0)->bind(&mRenderTarget);
+ }
+ else
+ {
+ gGL.getTexUnit(0)->bind(&(mMipChain[i - 1]));
+ }
+
+ gGL.begin(gGL.QUADS);
+
+ gGL.texCoord2f(0, 0);
+ gGL.vertex2f(-1, -1);
+
+ gGL.texCoord2f(res, 0);
+ gGL.vertex2f(1, -1);
+
+ gGL.texCoord2f(res, res);
+ gGL.vertex2f(1, 1);
+
+ gGL.texCoord2f(0, res);
+ gGL.vertex2f(-1, 1);
+ gGL.end();
+ gGL.flush();
+
+ res /= 2;
+
+ S32 mip = i - (mMipChain.size() - mips);
+
+ if (mip >= 0)
+ {
+ mTexture->bind(0);
+ glCopyTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, mip, 0, 0, mUpdatingProbe->mCubeIndex * 6 + mUpdatingFace, 0, 0, res, res);
+ mTexture->unbind();
+ }
+ mMipChain[i].flush();
+ }
+
+ gGL.popMatrix();
+ gGL.matrixMode(gGL.MM_MODELVIEW);
+ gGL.popMatrix();
+
+ gReflectionMipProgram.unbind();
+ }
+
+ if (++mUpdatingFace == 6)
+ {
+ updateNeighbors(mUpdatingProbe);
+ mUpdatingProbe = nullptr;
+ mUpdatingFace = 0;
+ }
+}
+
+void LLReflectionMapManager::rebuild()
+{
+ for (auto& probe : mProbes)
+ {
+ probe->mLastUpdateTime = 0.f;
}
+}
- for (++i; i < maps.size(); ++i)
+void LLReflectionMapManager::shift(const LLVector4a& offset)
+{
+ for (auto& probe : mProbes)
{
- maps[i] = nullptr;
+ probe->mOrigin.add(offset);
}
}
+void LLReflectionMapManager::updateNeighbors(LLReflectionMap* probe)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
+
+ //remove from existing neighbors
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmun - clear");
+
+ for (auto& other : probe->mNeighbors)
+ {
+ auto& iter = std::find(other->mNeighbors.begin(), other->mNeighbors.end(), probe);
+ llassert(iter != other->mNeighbors.end()); // <--- bug davep if this ever happens, something broke badly
+ other->mNeighbors.erase(iter);
+ }
+
+ probe->mNeighbors.clear();
+ }
+
+ // search for new neighbors
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmun - search");
+ for (auto& other : mProbes)
+ {
+ if (other != probe)
+ {
+ if (probe->intersects(other))
+ {
+ probe->mNeighbors.push_back(other);
+ other->mNeighbors.push_back(probe);
+ }
+ }
+ }
+ }
+}
+
+void LLReflectionMapManager::setUniforms()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
+
+ // structure for packing uniform buffer object
+ // see class2/deferred/softenLightF.glsl
+ struct ReflectionProbeData
+ {
+ LLVector4 refSphere[LL_REFLECTION_PROBE_COUNT]; //origin and radius of refmaps in clip space
+ GLint refIndex[LL_REFLECTION_PROBE_COUNT][4];
+ GLint refNeighbor[4096];
+ GLint refmapCount;
+ };
+
+ mReflectionMaps.resize(LL_REFLECTION_PROBE_COUNT);
+ getReflectionMaps(mReflectionMaps);
+
+ ReflectionProbeData rpd;
+
+ // load modelview matrix into matrix 4a
+ LLMatrix4a modelview;
+ modelview.loadu(gGLModelView);
+ LLVector4a oa; // scratch space for transformed origin
+
+ S32 count = 0;
+ U32 nc = 0; // neighbor "cursor" - index into refNeighbor to start writing the next probe's list of neighbors
+
+ for (auto* refmap : mReflectionMaps)
+ {
+ if (refmap == nullptr)
+ {
+ break;
+ }
+
+ llassert(refmap->mProbeIndex == count);
+ llassert(mReflectionMaps[refmap->mProbeIndex] == refmap);
+
+ llassert(refmap->mCubeIndex >= 0); // should always be true, if not, getReflectionMaps is bugged
+
+ {
+ //LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmsu - refSphere");
+
+ modelview.affineTransform(refmap->mOrigin, oa);
+ rpd.refSphere[count].set(oa.getF32ptr());
+ rpd.refSphere[count].mV[3] = refmap->mRadius;
+ }
+
+ rpd.refIndex[count][0] = refmap->mCubeIndex;
+ llassert(nc % 4 == 0);
+ rpd.refIndex[count][1] = nc / 4;
+
+ 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");
+ //pack neghbor list
+ for (auto& neighbor : refmap->mNeighbors)
+ {
+ if (ni >= 4096)
+ { // out of space
+ break;
+ }
+
+ GLint idx = neighbor->mProbeIndex;
+ if (idx == -1)
+ {
+ continue;
+ }
+
+ // this neighbor may be sampled
+ rpd.refNeighbor[ni++] = idx;
+ }
+ }
+
+ if (nc == ni)
+ {
+ //no neighbors, tag as empty
+ rpd.refIndex[count][1] = -1;
+ }
+ else
+ {
+ rpd.refIndex[count][2] = ni - nc;
+
+ // move the cursor forward
+ nc = ni;
+ if (nc % 4 != 0)
+ { // jump to next power of 4 for compatibility with ivec4
+ nc += 4 - (nc % 4);
+ }
+ }
+
+
+ count++;
+ }
+
+ rpd.refmapCount = count;
+
+ //copy rpd into uniform buffer object
+ if (mUBO == 0)
+ {
+ glGenBuffersARB(1, &mUBO);
+ }
+
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmsu - update buffer");
+ glBindBufferARB(GL_UNIFORM_BUFFER, mUBO);
+ glBufferDataARB(GL_UNIFORM_BUFFER, sizeof(ReflectionProbeData), &rpd, GL_STREAM_DRAW);
+ glBindBufferARB(GL_UNIFORM_BUFFER, 0);
+ }
+
+ glBindBufferBase(GL_UNIFORM_BUFFER, 1, mUBO);
+}
diff --git a/indra/newview/llreflectionmapmanager.h b/indra/newview/llreflectionmapmanager.h
index 40e925d916..24ac40b264 100644
--- a/indra/newview/llreflectionmapmanager.h
+++ b/indra/newview/llreflectionmapmanager.h
@@ -27,9 +27,20 @@
#pragma once
#include "llreflectionmap.h"
+#include "llrendertarget.h"
+#include "llcubemaparray.h"
-class LLReflectionMapManager
+class LLSpatialGroup;
+
+// number of reflection probes to keep in vram
+#define LL_REFLECTION_PROBE_COUNT 256
+
+// reflection probe resolution
+#define LL_REFLECTION_PROBE_RESOLUTION 256
+
+class alignas(16) LLReflectionMapManager
{
+ LL_ALIGN_NEW
public:
// allocate an environment map of the given resolution
LLReflectionMapManager();
@@ -40,12 +51,74 @@ public:
// drop a reflection probe at the specified position in agent space
void addProbe(const LLVector3& pos);
+ // add a probe for the given spatial group
+ LLReflectionMap* addProbe(LLSpatialGroup* group);
+
// Populate "maps" with the N most relevant Reflection Maps where N is no more than maps.size()
// If less than maps.size() ReflectionMaps are available, will assign trailing elements to nullptr.
// maps -- presized array of Reflection Map pointers
void getReflectionMaps(std::vector<LLReflectionMap*>& maps);
+ // called by LLSpatialGroup constructor
+ // If spatial group should receive a Reflection Probe, will create one for the specified spatial group
+ LLReflectionMap* registerSpatialGroup(LLSpatialGroup* group);
+
+ // force an update of all probes
+ void rebuild();
+
+ // called on region crossing to "shift" probes into new coordinate frame
+ void shift(const LLVector4a& offset);
+
+private:
+ friend class LLPipeline;
+
+ // delete the probe with the given index in mProbes
+ void deleteProbe(U32 i);
+
+ // get a free cube index
+ // if no cube indices are free, free one starting from the back of the probe list
+ S32 allocateCubeIndex();
+
+ // update the neighbors of the given probe
+ void updateNeighbors(LLReflectionMap* probe);
+
+ void setUniforms();
+
+ // render target for cube snapshots
+ // used to generate mipmaps without doing a copy-to-texture
+ LLRenderTarget mRenderTarget;
+
+ std::vector<LLRenderTarget> mMipChain;
+
+ // storage for reflection probes
+ LLPointer<LLCubeMapArray> mTexture;
+
+ // array indicating if a particular cubemap is free
+ bool mCubeFree[LL_REFLECTION_PROBE_COUNT];
+
+ // start tracking the given spatial group
+ void trackGroup(LLSpatialGroup* group);
+
+ // perform an update on the currently updating Probe
+ void doProbeUpdate();
+
// list of active reflection maps
- std::vector<LLReflectionMap> mProbes;
+ std::vector<LLPointer<LLReflectionMap> > mProbes;
+
+ // list of reflection maps to kill
+ std::vector<LLPointer<LLReflectionMap> > mKillList;
+
+ // list of reflection maps to create
+ std::vector<LLPointer<LLReflectionMap> > mCreateList;
+
+ // handle to UBO
+ U32 mUBO = 0;
+
+ // list of maps being used for rendering
+ std::vector<LLReflectionMap*> mReflectionMaps;
+
+ LLReflectionMap* mUpdatingProbe = nullptr;
+ U32 mUpdatingFace = 0;
+
};
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 5c648c11e1..5909cd1f4c 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -554,9 +554,12 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : LLO
sg_assert(mOctreeNode->getListenerCount() == 0);
setState(SG_INITIAL_STATE_MASK);
gPipeline.markRebuild(this, TRUE);
+
+ // let the reflection map manager know about this spatial group
+ mReflectionProbe = gPipeline.mReflectionMapManager.registerSpatialGroup(this);
- mRadius = 1;
- mPixelArea = 1024.f;
+ mRadius = 1;
+ mPixelArea = 1024.f;
}
void LLSpatialGroup::updateDistance(LLCamera &camera)
@@ -735,8 +738,17 @@ BOOL LLSpatialGroup::changeLOD()
return FALSE;
}
+void LLSpatialGroup::dirtyReflectionProbe()
+{
+ if (mReflectionProbe != nullptr)
+ {
+ mReflectionProbe->dirty();
+ }
+}
+
void LLSpatialGroup::handleInsertion(const TreeNode* node, LLViewerOctreeEntry* entry)
{
+ dirtyReflectionProbe();
addObject((LLDrawable*)entry->getDrawable());
unbound();
setState(OBJECT_DIRTY);
@@ -744,6 +756,7 @@ void LLSpatialGroup::handleInsertion(const TreeNode* node, LLViewerOctreeEntry*
void LLSpatialGroup::handleRemoval(const TreeNode* node, LLViewerOctreeEntry* entry)
{
+ dirtyReflectionProbe();
removeObject((LLDrawable*)entry->getDrawable(), TRUE);
LLViewerOctreeGroup::handleRemoval(node, entry);
}
@@ -780,6 +793,8 @@ void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* c
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL
+ dirtyReflectionProbe();
+
if (child->getListenerCount() == 0)
{
new LLSpatialGroup(child, getSpatialPartition());
@@ -794,6 +809,11 @@ void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* c
assert_states_valid(this);
}
+void LLSpatialGroup::handleChildRemoval(const oct_node* parent, const oct_node* child)
+{
+ dirtyReflectionProbe();
+}
+
void LLSpatialGroup::destroyGL(bool keep_occlusion)
{
setState(LLSpatialGroup::GEOM_DIRTY | LLSpatialGroup::IMAGE_DIRTY);
@@ -1398,7 +1418,9 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* result
return 0;
}
-
+
+extern BOOL gCubeSnapshot;
+
S32 LLSpatialPartition::cull(LLCamera &camera, bool do_occlusion)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL;
@@ -1417,7 +1439,7 @@ S32 LLSpatialPartition::cull(LLCamera &camera, bool do_occlusion)
LLOctreeCullShadow culler(&camera);
culler.traverse(mOctree);
}
- else if (mInfiniteFarClip || !LLPipeline::sUseFarClip)
+ else if (mInfiniteFarClip || (!LLPipeline::sUseFarClip && !gCubeSnapshot))
{
LLOctreeCullNoFarClip culler(&camera);
culler.traverse(mOctree);
@@ -1737,12 +1759,71 @@ void renderOctree(LLSpatialGroup* group)
}
}*/
}
-
+
// LLSpatialGroup::OctreeNode* node = group->mOctreeNode;
// gGL.diffuseColor4f(0,1,0,1);
// drawBoxOutline(LLVector3(node->getCenter()), LLVector3(node->getSize()));
}
+void renderReflectionProbes(LLSpatialGroup* group)
+{
+ if (group->mReflectionProbe)
+ { // draw lines from corners of object aabb to reflection probe
+
+ const LLVector4a* bounds = group->getBounds();
+ LLVector4a o = bounds[0];
+
+ gGL.flush();
+ gGL.diffuseColor4f(0, 0, 1, 1);
+ F32* c = o.getF32ptr();
+
+ const F32* bc = bounds[0].getF32ptr();
+ const F32* bs = bounds[1].getF32ptr();
+
+ // daaw blue lines from corners to center of node
+ gGL.begin(gGL.LINES);
+ gGL.vertex3fv(c);
+ gGL.vertex3f(bc[0] + bs[0], bc[1] + bs[1], bc[2] + bs[2]);
+ gGL.vertex3fv(c);
+ gGL.vertex3f(bc[0] - bs[0], bc[1] + bs[1], bc[2] + bs[2]);
+ gGL.vertex3fv(c);
+ gGL.vertex3f(bc[0] + bs[0], bc[1] - bs[1], bc[2] + bs[2]);
+ gGL.vertex3fv(c);
+ gGL.vertex3f(bc[0] - bs[0], bc[1] - bs[1], bc[2] + bs[2]);
+
+ gGL.vertex3fv(c);
+ gGL.vertex3f(bc[0] + bs[0], bc[1] + bs[1], bc[2] - bs[2]);
+ gGL.vertex3fv(c);
+ gGL.vertex3f(bc[0] - bs[0], bc[1] + bs[1], bc[2] - bs[2]);
+ gGL.vertex3fv(c);
+ gGL.vertex3f(bc[0] + bs[0], bc[1] - bs[1], bc[2] - bs[2]);
+ gGL.vertex3fv(c);
+ gGL.vertex3f(bc[0] - bs[0], bc[1] - bs[1], bc[2] - bs[2]);
+ gGL.end();
+
+ F32* po = group->mReflectionProbe->mOrigin.getF32ptr();
+ //draw yellow line from center of node to reflection probe origin
+ gGL.flush();
+ gGL.diffuseColor4f(1, 1, 0, 1);
+ gGL.begin(gGL.LINES);
+ gGL.vertex3fv(c);
+ gGL.vertex3fv(po);
+ gGL.end();
+ gGL.flush();
+
+ //draw orange line from probe to neighbors
+ gGL.flush();
+ gGL.diffuseColor4f(1, 0.5f, 0, 1);
+ gGL.begin(gGL.LINES);
+ for (auto& probe : group->mReflectionProbe->mNeighbors)
+ {
+ gGL.vertex3fv(po);
+ gGL.vertex3fv(probe->mOrigin.getF32ptr());
+ }
+ gGL.end();
+ gGL.flush();
+ }
+}
std::set<LLSpatialGroup*> visible_selected_groups;
void renderVisibility(LLSpatialGroup* group, LLCamera* camera)
@@ -3289,6 +3370,12 @@ public:
stop_glerror();
}
+ //draw reflection probes and links between them
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_REFLECTION_PROBES))
+ {
+ renderReflectionProbes(group);
+ }
+
//render visibility wireframe
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
{
@@ -3703,7 +3790,8 @@ void LLSpatialPartition::renderDebug()
//LLPipeline::RENDER_DEBUG_BUILD_QUEUE |
LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA |
LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY |
- LLPipeline::RENDER_DEBUG_TEXEL_DENSITY))
+ LLPipeline::RENDER_DEBUG_TEXEL_DENSITY |
+ LLPipeline::RENDER_DEBUG_REFLECTION_PROBES))
{
return;
}
@@ -3947,6 +4035,23 @@ LLDrawable* LLSpatialPartition::lineSegmentIntersect(const LLVector4a& start, co
return drawable;
}
+LLDrawable* LLSpatialGroup::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
+ BOOL pick_transparent,
+ BOOL pick_rigged,
+ S32* face_hit, // return the face hit
+ LLVector4a* intersection, // return the intersection point
+ LLVector2* tex_coord, // return the texture coordinates of the intersection point
+ LLVector4a* normal, // return the surface normal at the intersection point
+ LLVector4a* tangent // return the surface tangent at the intersection point
+)
+
+{
+ LLOctreeIntersect intersect(start, end, pick_transparent, pick_rigged, face_hit, intersection, tex_coord, normal, tangent);
+ LLDrawable* drawable = intersect.check(getOctreeNode());
+
+ return drawable;
+}
+
LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset,
LLViewerTexture* texture, LLVertexBuffer* buffer,
bool selected,
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index acfcd63686..a30660b2de 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -53,6 +53,7 @@ class LLSpatialPartition;
class LLSpatialBridge;
class LLSpatialGroup;
class LLViewerRegion;
+class LLReflectionMap;
void pushVerts(LLFace* face, U32 mask);
@@ -300,6 +301,17 @@ public:
void drawObjectBox(LLColor4 col);
+ LLDrawable* lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
+ BOOL pick_transparent,
+ BOOL pick_rigged,
+ S32* face_hit, // return the face hit
+ LLVector4a* intersection = NULL, // return the intersection point
+ LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point
+ LLVector4a* normal = NULL, // return the surface normal at the intersection point
+ LLVector4a* tangent = NULL // return the surface tangent at the intersection point
+ );
+
+
LLSpatialPartition* getSpatialPartition() {return (LLSpatialPartition*)mSpatialPartition;}
//LISTENER FUNCTIONS
@@ -307,6 +319,7 @@ public:
virtual void handleRemoval(const TreeNode* node, LLViewerOctreeEntry* face);
virtual void handleDestruction(const TreeNode* node);
virtual void handleChildAddition(const OctreeNode* parent, OctreeNode* child);
+ virtual void handleChildRemoval(const oct_node* parent, const oct_node* child);
public:
LL_ALIGN_16(LLVector4a mViewAngle);
@@ -314,6 +327,8 @@ public:
F32 mObjectBoxSize; //cached mObjectBounds[1].getLength3()
+ void dirtyReflectionProbe();
+
protected:
virtual ~LLSpatialGroup();
@@ -338,6 +353,10 @@ public:
F32 mPixelArea;
F32 mRadius;
+
+ // Reflection Probe associated with this node (if any)
+ LLPointer<LLReflectionMap> mReflectionProbe = nullptr;
+
} LL_ALIGN_POSTFIX(64);
class LLGeometryManager
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 6a2b06d9b5..f375852dfe 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -97,6 +97,7 @@ BOOL gResizeScreenTexture = FALSE;
BOOL gResizeShadowTexture = FALSE;
BOOL gWindowResized = FALSE;
BOOL gSnapshot = FALSE;
+BOOL gCubeSnapshot = FALSE;
BOOL gShaderProfileFrame = FALSE;
// This is how long the sim will try to teleport you before giving up.
@@ -193,15 +194,23 @@ void display_update_camera()
// Cut draw distance in half when customizing avatar,
// but on the viewer only.
F32 final_far = gAgentCamera.mDrawDistance;
- if (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode())
+ if (gCubeSnapshot)
+ {
+ final_far = gSavedSettings.getF32("RenderReflectionProbeDrawDistance");
+ }
+ else if (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode())
+
{
final_far *= 0.5f;
}
LLViewerCamera::getInstance()->setFar(final_far);
gViewerWindow->setup3DRender();
- // Update land visibility too
- LLWorld::getInstance()->setLandFarClip(final_far);
+ if (!gCubeSnapshot)
+ {
+ // Update land visibility too
+ LLWorld::getInstance()->setLandFarClip(final_far);
+ }
}
// Write some stats to LL_INFOS()
@@ -1048,6 +1057,112 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
}
}
+// WIP simplified copy of display() that does minimal work
+void display_cube_face()
+{
+ LL_RECORD_BLOCK_TIME(FTM_RENDER);
+ llassert(!gSnapshot);
+ llassert(!gTeleportDisplay);
+ llassert(LLPipeline::sRenderDeferred);
+ llassert(LLStartUp::getStartupState() >= STATE_PRECACHE);
+ llassert(!LLAppViewer::instance()->logoutRequestSent());
+ llassert(!gRestoreGL);
+ llassert(!gUseWireframe);
+
+ bool rebuild = false;
+
+ LLGLSDefault gls_default;
+ LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE, GL_LEQUAL);
+
+ LLVertexBuffer::unbind();
+
+ gPipeline.disableLights();
+
+ gPipeline.mBackfaceCull = TRUE;
+
+ LLViewerCamera::getInstance()->setNear(MIN_NEAR_PLANE);
+ gViewerWindow->setup3DViewport();
+
+ if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+ { //don't draw hud objects in this frame
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+ }
+
+ if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES))
+ { //don't draw hud particles in this frame
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
+ }
+
+ display_update_camera();
+
+ 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
+ //gDepthDirty = TRUE; //let "real" render pipe know it can't trust the depth buffer for occlusion data
+
+ static LLCullResult result;
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
+ LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater();
+ gPipeline.updateCull(*LLViewerCamera::getInstance(), result);
+
+ gGL.setColorMask(true, true);
+ glClearColor(0, 0, 0, 0);
+ gPipeline.generateSunShadow(*LLViewerCamera::getInstance());
+
+ glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+
+ {
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
+ gPipeline.stateSort(*LLViewerCamera::getInstance(), result);
+
+ if (rebuild)
+ {
+ //////////////////////////////////////
+ //
+ // rebuildPools
+ //
+ //
+ gPipeline.rebuildPools();
+ stop_glerror();
+ }
+ }
+
+ LLPipeline::sUseOcclusion = occlusion;
+
+ LLAppViewer::instance()->pingMainloopTimeout("Display:RenderStart");
+
+ LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE;
+
+ gGL.setColorMask(true, true);
+
+ gPipeline.mDeferredScreen.bindTarget();
+ glClearColor(1, 0, 1, 1);
+ gPipeline.mDeferredScreen.clear();
+
+ gGL.setColorMask(true, false);
+
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
+
+ gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance());
+
+ gGL.setColorMask(true, true);
+
+ gPipeline.mDeferredScreen.flush();
+
+ gPipeline.renderDeferredLighting(&gPipeline.mScreen);
+
+ LLPipeline::sUnderWaterRender = FALSE;
+
+ // Finalize scene
+ gPipeline.renderFinalize();
+
+ LLSpatialGroup::sNoDelete = FALSE;
+ gPipeline.clearReferences();
+
+ gPipeline.rebuildGroups();
+}
+
void render_hud_attachments()
{
gGL.matrixMode(LLRender::MM_PROJECTION);
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index f5ea060e82..8732bde35c 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -1081,6 +1081,10 @@ U64 info_display_from_string(std::string info_display)
{
return LLPipeline::RENDER_DEBUG_IMPOSTORS;
}
+ else if ("reflection probes" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_REFLECTION_PROBES;
+ }
else
{
LL_WARNS() << "unrecognized feature name '" << info_display << "'" << LL_ENDL;
@@ -8304,9 +8308,9 @@ void handle_cache_clear_immediately()
LLNotificationsUtil::add("ConfirmClearCache", LLSD(), LLSD(), callback_clear_cache_immediately);
}
-void handle_override_environment_map()
+void handle_rebuild_reflection_probes()
{
- gPipeline.overrideEnvironmentMap();
+ gPipeline.mReflectionMapManager.rebuild();
}
@@ -9409,7 +9413,7 @@ void initialize_menus()
//Develop (clear cache immediately)
commit.add("Develop.ClearCache", boost::bind(&handle_cache_clear_immediately) );
//Develop (override environment map)
- commit.add("Develop.OverrideEnvironmentMap", boost::bind(&handle_override_environment_map));
+ commit.add("Develop.RebuildReflectionProbes", boost::bind(&handle_rebuild_reflection_probes));
// Admin >Object
view_listener_t::addMenu(new LLAdminForceTakeCopy(), "Admin.ForceTakeCopy");
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 50a0ff07fc..94af320a73 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -82,6 +82,7 @@ LLGLSLShader gOcclusionCubeProgram;
LLGLSLShader gCustomAlphaProgram;
LLGLSLShader gGlowCombineProgram;
LLGLSLShader gSplatTextureRectProgram;
+LLGLSLShader gReflectionMipProgram;
LLGLSLShader gGlowCombineFXAAProgram;
LLGLSLShader gTwoTextureAddProgram;
LLGLSLShader gTwoTextureCompareProgram;
@@ -635,7 +636,6 @@ void LLViewerShaderMgr::setShaders()
}
if (loaded)
-
{
loaded = loadTransformShaders();
if (loaded)
@@ -746,6 +746,7 @@ void LLViewerShaderMgr::unloadShaders()
gCustomAlphaProgram.unload();
gGlowCombineProgram.unload();
gSplatTextureRectProgram.unload();
+ gReflectionMipProgram.unload();
gGlowCombineFXAAProgram.unload();
gTwoTextureAddProgram.unload();
gTwoTextureCompareProgram.unload();
@@ -3587,7 +3588,6 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
}
}
-
if (success)
{
gTwoTextureAddProgram.mName = "Two Texture Add Shader";
@@ -3763,6 +3763,22 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
success = gAlphaMaskProgram.createShader(NULL, NULL);
}
+ if (success)
+ {
+ gReflectionMipProgram.mName = "Reflection Mip Shader";
+ gReflectionMipProgram.mShaderFiles.clear();
+ gReflectionMipProgram.mShaderFiles.push_back(make_pair("interface/splattexturerectV.glsl", GL_VERTEX_SHADER_ARB));
+ gReflectionMipProgram.mShaderFiles.push_back(make_pair("interface/reflectionmipF.glsl", GL_FRAGMENT_SHADER_ARB));
+ gReflectionMipProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE];
+ success = gReflectionMipProgram.createShader(NULL, NULL);
+ if (success)
+ {
+ gReflectionMipProgram.bind();
+ gReflectionMipProgram.uniform1i(sScreenMap, 0);
+ gReflectionMipProgram.unbind();
+ }
+ }
+
if( !success )
{
mShaderLevel[SHADER_INTERFACE] = 0;
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index 50a3daebaa..f0187db302 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -161,6 +161,7 @@ extern LLGLSLShader gOcclusionCubeProgram;
extern LLGLSLShader gCustomAlphaProgram;
extern LLGLSLShader gGlowCombineProgram;
extern LLGLSLShader gSplatTextureRectProgram;
+extern LLGLSLShader gReflectionMipProgram;
extern LLGLSLShader gGlowCombineFXAAProgram;
extern LLGLSLShader gDebugProgram;
extern LLGLSLShader gClipProgram;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index f562a9458b..9bda4bbf92 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -228,6 +228,7 @@ extern BOOL gDebugClicks;
extern BOOL gDisplaySwapBuffers;
extern BOOL gDepthDirty;
extern BOOL gResizeScreenTexture;
+extern BOOL gCubeSnapshot;
LLViewerWindow *gViewerWindow = NULL;
@@ -5267,29 +5268,30 @@ BOOL LLViewerWindow::simpleSnapshot(LLImageRaw* raw, S32 image_width, S32 image_
return true;
}
-BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMap* cubemap)
+void display_cube_face();
+
+BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMapArray* cubearray, S32 cubeIndex, S32 face)
{
// NOTE: implementation derived from LLFloater360Capture::capture360Images() and simpleSnapshot
LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;
llassert(LLPipeline::sRenderDeferred);
+ llassert(!gCubeSnapshot); //assert a snapshot isn't already in progress
- U32 res = cubemap->getResolution();
+ U32 res = LLRenderTarget::sCurResX;
llassert(res <= gPipeline.mDeferredScreen.getWidth());
llassert(res <= gPipeline.mDeferredScreen.getHeight());
-
-
// save current view/camera settings so we can restore them afterwards
S32 old_occlusion = LLPipeline::sUseOcclusion;
// set new parameters specific to the 360 requirements
LLPipeline::sUseOcclusion = 0;
LLViewerCamera* camera = LLViewerCamera::getInstance();
- LLVector3 old_origin = camera->getOrigin();
- F32 old_fov = camera->getView();
- F32 old_aspect = camera->getAspect();
- F32 old_yaw = camera->getYaw();
+
+ LLViewerCamera saved_camera = LLViewerCamera::instance();
+ glh::matrix4f saved_proj = get_current_projection();
+ glh::matrix4f saved_mod = get_current_modelview();
// camera constants for the square, cube map capture image
camera->setAspect(1.0); // must set aspect ratio first to avoid undesirable clamping of vertical FoV
@@ -5297,8 +5299,6 @@ BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMap* cubemap)
camera->yaw(0.0);
camera->setOrigin(origin);
- gDisplaySwapBuffers = FALSE;
-
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
BOOL prev_draw_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI) ? TRUE : FALSE;
@@ -5306,55 +5306,38 @@ BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMap* cubemap)
{
LLPipeline::toggleRenderDebugFeature(LLPipeline::RENDER_DEBUG_FEATURE_UI);
}
-
- LLPipeline::sShowHUDAttachments = FALSE;
- LLRect window_rect = getWorldViewRectRaw();
-
- LLRenderTarget scratch_space; // TODO: hold onto "scratch space" render target and allocate oncer per session (allocate takes > 1ms)
- U32 color_fmt = GL_RGBA;
- const bool use_depth_buffer = true;
- const bool use_stencil_buffer = true;
- if (scratch_space.allocate(res, res, color_fmt, use_depth_buffer, use_stencil_buffer))
- {
- mWorldViewRectRaw.set(0, res, res, 0);
- scratch_space.bindTarget();
- }
- else
+ BOOL prev_draw_particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES);
+ if (prev_draw_particles)
{
- return FALSE;
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PARTICLES);
}
+ LLPipeline::sShowHUDAttachments = FALSE;
+ LLRect window_rect = getWorldViewRectRaw();
- // "target" parameter of glCopyTexImage2D for each side of cubemap
- U32 targets[6] = {
- GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
- GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
- GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
- GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
- GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
- GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB
- };
+ mWorldViewRectRaw.set(0, res, res, 0);
- // these are the 6 directions we will point the camera, see LLCubeMap::mTargets
+ // these are the 6 directions we will point the camera, see LLCubeMapArray::sTargets
LLVector3 look_dirs[6] = {
- LLVector3(-1, 0, 0),
LLVector3(1, 0, 0),
- LLVector3(0, -1, 0),
+ LLVector3(-1, 0, 0),
LLVector3(0, 1, 0),
- LLVector3(0, 0, -1),
- LLVector3(0, 0, 1)
+ LLVector3(0, -1, 0),
+ LLVector3(0, 0, 1),
+ LLVector3(0, 0, -1)
};
LLVector3 look_upvecs[6] = {
LLVector3(0, -1, 0),
LLVector3(0, -1, 0),
- LLVector3(0, 0, -1),
LLVector3(0, 0, 1),
+ LLVector3(0, 0, -1),
LLVector3(0, -1, 0),
LLVector3(0, -1, 0)
};
// for each of six sides of cubemap
- for (int i = 0; i < 6; ++i)
+ //for (int i = 0; i < 6; ++i)
+ int i = face;
{
// set up camera to look in each direction
camera->lookDir(look_dirs[i], look_upvecs[i]);
@@ -5368,22 +5351,12 @@ BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMap* cubemap)
gDisplaySwapBuffers = FALSE;
// actually render the scene
- const U32 subfield = 0;
- const bool do_rebuild = true;
- const F32 zoom = 1.0;
- const bool for_snapshot = TRUE;
- display(do_rebuild, zoom, subfield, for_snapshot);
-
- // copy results to cube map face
- cubemap->enable(0);
- cubemap->bind();
- glCopyTexImage2D(targets[i], 0, GL_RGB, 0, 0, res, res, 0);
- gGL.getTexUnit(0)->disable();
- cubemap->disable();
+ gCubeSnapshot = TRUE;
+ display_cube_face();
+ gCubeSnapshot = FALSE;
}
- gDisplaySwapBuffers = FALSE;
- gDepthDirty = TRUE;
+ gDisplaySwapBuffers = TRUE;
if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
{
@@ -5393,23 +5366,23 @@ BOOL LLViewerWindow::cubeSnapshot(const LLVector3& origin, LLCubeMap* cubemap)
}
}
+ if (prev_draw_particles)
+ {
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PARTICLES);
+ }
+
LLPipeline::sShowHUDAttachments = TRUE;
gPipeline.resetDrawOrders();
mWorldViewRectRaw = window_rect;
- scratch_space.flush();
- scratch_space.release();
// restore original view/camera/avatar settings settings
- camera->setAspect(old_aspect);
- camera->setView(old_fov);
- camera->yaw(old_yaw);
- camera->setOrigin(old_origin);
-
+ *camera = saved_camera;
+ set_current_modelview(saved_mod);
+ set_current_projection(saved_proj);
LLPipeline::sUseOcclusion = old_occlusion;
// ====================================================
-
return true;
}
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index be4e9a17a5..ac7f8b2e39 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -69,6 +69,7 @@ class LLViewerWindowListener;
class LLVOPartGroup;
class LLPopupView;
class LLCubeMap;
+class LLCubeMapArray;
#define PICK_HALF_WIDTH 5
#define PICK_DIAMETER (2 * PICK_HALF_WIDTH + 1)
@@ -365,8 +366,9 @@ public:
// take a cubemap snapshot
// origin - vantage point to take the snapshot from
- // cubemap - cubemap to store the results
- BOOL cubeSnapshot(const LLVector3& origin, LLCubeMap* cubemap);
+ // 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);
// special implementation of simpleSnapshot for reflection maps
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 17d92fda38..ef6ee4b910 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -106,6 +106,7 @@ LLPointer<LLObjectMediaDataClient> LLVOVolume::sObjectMediaClient = NULL;
LLPointer<LLObjectMediaNavigateClient> LLVOVolume::sObjectMediaNavigateClient = NULL;
extern BOOL gGLDebugLoggingEnabled;
+extern BOOL gCubeSnapshot;
// Implementation class of LLMediaDataClientObject. See llmediadataclient.h
class LLMediaDataClientObjectImpl : public LLMediaDataClientObject
@@ -718,7 +719,7 @@ void LLVOVolume::updateTextureVirtualSize(bool forced)
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
// Update the pixel area of all faces
- if (mDrawable.isNull())
+ if (mDrawable.isNull() || gCubeSnapshot)
{
return;
}
@@ -3388,6 +3389,11 @@ F32 LLVOVolume::getSpotLightPriority() const
void LLVOVolume::updateSpotLightPriority()
{
+ if (gCubeSnapshot)
+ {
+ return;
+ }
+
F32 r = getLightRadius();
LLVector3 pos = mDrawable->getPositionAgent();
@@ -5497,6 +5503,8 @@ static inline void add_face(T*** list, U32* count, T* face)
void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME;
+ llassert(!gCubeSnapshot);
+
if (group->changeLOD())
{
group->mLastUpdateDistance = group->mDistance;
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 8abb49fba8..8837038d02 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -820,7 +820,7 @@ void LLWorld::updateNetStats()
void LLWorld::printPacketsLost()
{
- LL_INFOS() << "Simulators:" << LL_ENDL;
+ LL_INFOS() << "Simulators:" << LL_ENDL;
LL_INFOS() << "----------" << LL_ENDL;
LLCircuitData *cdp = NULL;
@@ -855,6 +855,7 @@ F32 LLWorld::getLandFarClip() const
void LLWorld::setLandFarClip(const F32 far_clip)
{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
static S32 const rwidth = (S32)REGION_WIDTH_U32;
S32 const n1 = (llceil(mLandFarClip) - 1) / rwidth;
S32 const n2 = (llceil(far_clip) - 1) / rwidth;
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index ef616f5d83..5eb9817fc4 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -227,6 +227,7 @@ extern S32 gBoxFrame;
//extern BOOL gHideSelectedObjects;
extern BOOL gDisplaySwapBuffers;
extern BOOL gDebugGL;
+extern BOOL gCubeSnapshot;
bool gAvatarBacklight = false;
@@ -2006,6 +2007,7 @@ void LLPipeline::updateMove()
//static
F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera)
{
+ llassert(!gCubeSnapshot); // shouldn't be doing ANY of this during cube snap shots
LLVector3 lookAt = center - camera.getOrigin();
F32 dist = lookAt.length();
@@ -2475,7 +2477,7 @@ void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)
group->setVisible();
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && !gCubeSnapshot)
{
group->updateDistance(camera);
}
@@ -2581,6 +2583,8 @@ void LLPipeline::downsampleDepthBuffer(LLRenderTarget& source, LLRenderTarget& d
void LLPipeline::doOcclusion(LLCamera& camera, LLRenderTarget& source, LLRenderTarget& dest, LLRenderTarget* scratch_space)
{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
+ llassert(!gCubeSnapshot);
downsampleDepthBuffer(source, dest, scratch_space);
dest.bindTarget();
doOcclusion(camera);
@@ -2823,7 +2827,7 @@ void LLPipeline::rebuildPriorityGroups()
void LLPipeline::rebuildGroups()
{
- if (mGroupQ2.empty())
+ if (mGroupQ2.empty() || gCubeSnapshot)
{
return;
}
@@ -2873,6 +2877,10 @@ void LLPipeline::updateGeom(F32 max_dtime)
LLPointer<LLDrawable> drawablep;
LL_RECORD_BLOCK_TIME(FTM_GEO_UPDATE);
+ if (gCubeSnapshot)
+ {
+ return;
+ }
assertInitialized();
@@ -3112,6 +3120,8 @@ void LLPipeline::shiftObjects(const LLVector3 &offset)
}
}
+ mReflectionMapManager.shift(offseta);
+
LLHUDText::shiftAll(offset);
LLHUDNameTag::shiftAll(offset);
@@ -3292,7 +3302,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
}
}
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && !gCubeSnapshot)
{
LLSpatialGroup* last_group = NULL;
BOOL fov_changed = LLViewerCamera::getInstance()->isDefaultFOVChanged();
@@ -3374,7 +3384,7 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
stateSort(drawablep, camera);
}
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && !gCubeSnapshot)
{ //avoid redundant stateSort calls
group->mLastUpdateDistance = group->mDistance;
}
@@ -3443,7 +3453,7 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera)
}
}
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && !gCubeSnapshot)
{
//if (drawablep->isVisible()) isVisible() check here is redundant, if it wasn't visible, it wouldn't be here
{
@@ -3721,21 +3731,26 @@ void LLPipeline::postSort(LLCamera& camera)
assertInitialized();
LL_PUSH_CALLSTACKS();
- //rebuild drawable geometry
- for (LLCullResult::sg_iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i)
- {
- LLSpatialGroup* group = *i;
- if (!sUseOcclusion ||
- !group->isOcclusionState(LLSpatialGroup::OCCLUDED))
- {
- group->rebuildGeom();
- }
- }
- LL_PUSH_CALLSTACKS();
- //rebuild groups
- sCull->assertDrawMapsEmpty();
- rebuildPriorityGroups();
+ if (!gCubeSnapshot)
+ {
+ //rebuild drawable geometry
+ for (LLCullResult::sg_iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i)
+ {
+ LLSpatialGroup* group = *i;
+ if (!sUseOcclusion ||
+ !group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ {
+ group->rebuildGeom();
+ }
+ }
+ LL_PUSH_CALLSTACKS();
+ //rebuild groups
+ sCull->assertDrawMapsEmpty();
+
+ rebuildPriorityGroups();
+ }
+
LL_PUSH_CALLSTACKS();
@@ -3751,7 +3766,7 @@ void LLPipeline::postSort(LLCamera& camera)
continue;
}
- if (group->hasState(LLSpatialGroup::NEW_DRAWINFO) && group->hasState(LLSpatialGroup::GEOM_DIRTY))
+ if (group->hasState(LLSpatialGroup::NEW_DRAWINFO) && group->hasState(LLSpatialGroup::GEOM_DIRTY) && !gCubeSnapshot)
{ //no way this group is going to be drawable without a rebuild
group->rebuildGeom();
}
@@ -3769,7 +3784,7 @@ void LLPipeline::postSort(LLCamera& camera)
LLDrawInfo* info = *k;
sCull->pushDrawInfo(j->first, info);
- if (!sShadowRender && !sReflectionRender)
+ if (!sShadowRender && !sReflectionRender && !gCubeSnapshot)
{
touchTextures(info);
addTrianglesDrawn(info->mCount, info->mDrawMode);
@@ -3784,7 +3799,7 @@ void LLPipeline::postSort(LLCamera& camera)
if (alpha != group->mDrawMap.end())
{ //store alpha groups for sorting
LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge();
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD && !gCubeSnapshot)
{
if (bridge)
{
@@ -4411,7 +4426,7 @@ void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate)
gGL.loadMatrix(gGLModelView);
if (occlude)
- {
+ { // catch uncommon condition where pools at drawpool grass and later are disabled
occlude = false;
gGLLastMatrix = NULL;
gGL.loadMatrix(gGLModelView);
@@ -4607,6 +4622,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion)
if (occlude && cur_type >= LLDrawPool::POOL_GRASS)
{
+ llassert(!gCubeSnapshot); // never do occlusion culling on cube snapshots
occlude = false;
gGLLastMatrix = NULL;
gGL.loadMatrix(gGLModelView);
@@ -5925,6 +5941,7 @@ void LLPipeline::setupAvatarLights(bool for_edit)
static F32 calc_light_dist(LLVOVolume* light, const LLVector3& cam_pos, F32 max_dist)
{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
F32 inten = light->getLightIntensity();
if (inten < .001f)
{
@@ -5948,9 +5965,10 @@ static F32 calc_light_dist(LLVOVolume* light, const LLVector3& cam_pos, F32 max_
void LLPipeline::calcNearbyLights(LLCamera& camera)
{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
assertInitialized();
- if (LLPipeline::sReflectionRender)
+ if (LLPipeline::sReflectionRender || gCubeSnapshot)
{
return;
}
@@ -6133,6 +6151,7 @@ void LLPipeline::calcNearbyLights(LLCamera& camera)
void LLPipeline::setupHWLights(LLDrawPool* pool)
{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
assertInitialized();
LLEnvironment& environment = LLEnvironment::instance();
@@ -7608,7 +7627,8 @@ void LLPipeline::renderFinalize()
bool dof_enabled = !LLViewerCamera::getInstance()->cameraUnderWater() &&
(RenderDepthOfFieldInEditMode || !LLToolMgr::getInstance()->inBuildMode()) &&
- RenderDepthOfField;
+ RenderDepthOfField &&
+ !gCubeSnapshot;
bool multisample = RenderFSAASamples > 1 && mFXAABuffer.isComplete();
@@ -8196,45 +8216,13 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_
}
}
- channel = shader.enableTexture(LLShaderMgr::REFLECTION_MAP, LLTexUnit::TT_CUBE_MAP);
- if (channel > -1)
+ channel = shader.enableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP_ARRAY);
+ if (channel > -1 && mReflectionMapManager.mTexture.notNull())
{
- mReflectionMaps.resize(8); //TODO -- declare the number of reflection maps the shader knows about somewhere sane
- mReflectionMapManager.getReflectionMaps(mReflectionMaps);
- LLVector3 origin[8]; //origin of refmaps in clip space
-
- // load modelview matrix into matrix 4a
- LLMatrix4a modelview;
- modelview.loadu(gGLModelView);
- LLVector4a oa; // scratch space for transformed origin
-
- S32 count = 0;
- for (auto* refmap : mReflectionMaps)
- {
- if (refmap)
- {
- LLCubeMap* cubemap = refmap->mCubeMap;
- if (cubemap)
- {
- cubemap->enable(channel + count);
- cubemap->bind();
-
- modelview.affineTransform(refmap->mOrigin, oa);
- origin[count].set(oa.getF32ptr());
-
- count++;
- }
- }
- }
-
- if (count > 0)
- {
- LLStaticHashedString refmapCount("refmapCount");
- LLStaticHashedString refOrigin("refOrigin");
- shader.uniform1i(refmapCount, count);
- shader.uniform3fv(refOrigin, count, (F32*)origin);
- setup_env_mat = true;
- }
+ // see comments in class2/deferred/softenLightF.glsl for what these uniforms mean
+ mReflectionMapManager.mTexture->bind(channel);
+ mReflectionMapManager.setUniforms();
+ setup_env_mat = true;
}
if (setup_env_mat)
@@ -8276,7 +8264,14 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_
}
}
- shader.uniform4fv(LLShaderMgr::DEFERRED_SHADOW_CLIP, 1, mSunClipPlanes.mV);
+ /*if (gCubeSnapshot)
+ { // we only really care about the first two values, but the shader needs increasing separation between clip planes
+ shader.uniform4f(LLShaderMgr::DEFERRED_SHADOW_CLIP, 1.f, 64.f, 128.f, 256.f);
+ }
+ else*/
+ {
+ shader.uniform4fv(LLShaderMgr::DEFERRED_SHADOW_CLIP, 1, mSunClipPlanes.mV);
+ }
shader.uniform1f(LLShaderMgr::DEFERRED_SUN_WASH, RenderDeferredSunWash);
shader.uniform1f(LLShaderMgr::DEFERRED_SHADOW_NOISE, RenderShadowNoise);
shader.uniform1f(LLShaderMgr::DEFERRED_BLUR_SIZE, RenderShadowBlurSize);
@@ -8469,66 +8464,78 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
}
if (RenderDeferredSSAO)
- { // soften direct lighting lightmap
- LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - soften shadow");
- // blur lightmap
- screen_target->bindTarget();
- glClearColor(1, 1, 1, 1);
- screen_target->clear(GL_COLOR_BUFFER_BIT);
- glClearColor(0, 0, 0, 0);
-
- bindDeferredShader(gDeferredBlurLightProgram);
- mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
- LLVector3 go = RenderShadowGaussian;
- const U32 kern_length = 4;
- F32 blur_size = RenderShadowBlurSize;
- F32 dist_factor = RenderShadowBlurDistFactor;
-
- // sample symmetrically with the middle sample falling exactly on 0.0
- F32 x = 0.f;
-
- LLVector3 gauss[32]; // xweight, yweight, offset
-
- for (U32 i = 0; i < kern_length; i++)
- {
- gauss[i].mV[0] = llgaussian(x, go.mV[0]);
- gauss[i].mV[1] = llgaussian(x, go.mV[1]);
- gauss[i].mV[2] = x;
- x += 1.f;
+ {
+ /*if (gCubeSnapshot)
+ { // SSAO and shadows disabled in reflection maps
+ deferred_light_target->bindTarget();
+ glClearColor(1, 1, 1, 1);
+ deferred_light_target->clear();
+ glClearColor(0, 0, 0, 0);
+ deferred_light_target->flush();
}
+ else*/
+ {
+ // soften direct lighting lightmap
+ LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - soften shadow");
+ // blur lightmap
+ screen_target->bindTarget();
+ glClearColor(1, 1, 1, 1);
+ screen_target->clear(GL_COLOR_BUFFER_BIT);
+ glClearColor(0, 0, 0, 0);
- gDeferredBlurLightProgram.uniform2f(sDelta, 1.f, 0.f);
- gDeferredBlurLightProgram.uniform1f(sDistFactor, dist_factor);
- gDeferredBlurLightProgram.uniform3fv(sKern, kern_length, gauss[0].mV);
- gDeferredBlurLightProgram.uniform1f(sKernScale, blur_size * (kern_length / 2.f - 0.5f));
+ bindDeferredShader(gDeferredBlurLightProgram);
+ mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+ LLVector3 go = RenderShadowGaussian;
+ const U32 kern_length = 4;
+ F32 blur_size = RenderShadowBlurSize;
+ F32 dist_factor = RenderShadowBlurDistFactor;
- {
- LLGLDisable blend(GL_BLEND);
- LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
- stop_glerror();
- mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
- stop_glerror();
- }
+ // sample symmetrically with the middle sample falling exactly on 0.0
+ F32 x = 0.f;
+
+ LLVector3 gauss[32]; // xweight, yweight, offset
- screen_target->flush();
- unbindDeferredShader(gDeferredBlurLightProgram);
+ for (U32 i = 0; i < kern_length; i++)
+ {
+ gauss[i].mV[0] = llgaussian(x, go.mV[0]);
+ gauss[i].mV[1] = llgaussian(x, go.mV[1]);
+ gauss[i].mV[2] = x;
+ x += 1.f;
+ }
- bindDeferredShader(gDeferredBlurLightProgram, screen_target);
+ gDeferredBlurLightProgram.uniform2f(sDelta, 1.f, 0.f);
+ gDeferredBlurLightProgram.uniform1f(sDistFactor, dist_factor);
+ gDeferredBlurLightProgram.uniform3fv(sKern, kern_length, gauss[0].mV);
+ gDeferredBlurLightProgram.uniform1f(sKernScale, blur_size * (kern_length / 2.f - 0.5f));
- mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
- deferred_light_target->bindTarget();
+ {
+ LLGLDisable blend(GL_BLEND);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+ stop_glerror();
+ mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+ stop_glerror();
+ }
- gDeferredBlurLightProgram.uniform2f(sDelta, 0.f, 1.f);
+ screen_target->flush();
+ unbindDeferredShader(gDeferredBlurLightProgram);
- {
- LLGLDisable blend(GL_BLEND);
- LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
- stop_glerror();
- mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
- stop_glerror();
+ bindDeferredShader(gDeferredBlurLightProgram, screen_target);
+
+ mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+ deferred_light_target->bindTarget();
+
+ gDeferredBlurLightProgram.uniform2f(sDelta, 0.f, 1.f);
+
+ {
+ LLGLDisable blend(GL_BLEND);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+ stop_glerror();
+ mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+ stop_glerror();
+ }
+ deferred_light_target->flush();
+ unbindDeferredShader(gDeferredBlurLightProgram);
}
- deferred_light_target->flush();
- unbindDeferredShader(gDeferredBlurLightProgram);
}
stop_glerror();
@@ -8595,7 +8602,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
gPipeline.popRenderTypeMask();
}
- bool render_local = RenderLocalLights;
+ bool render_local = RenderLocalLights; // && !gCubeSnapshot;
if (render_local)
{
@@ -8604,9 +8611,12 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
LLDrawable::drawable_list_t spot_lights;
LLDrawable::drawable_list_t fullscreen_spot_lights;
- for (U32 i = 0; i < 2; i++)
+ if (!gCubeSnapshot)
{
- mTargetShadowSpotLight[i] = NULL;
+ for (U32 i = 0; i < 2; i++)
+ {
+ mTargetShadowSpotLight[i] = NULL;
+ }
}
std::list<LLVector4> light_colors;
@@ -8942,6 +8952,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target)
popRenderTypeMask();
}
+ if (!gCubeSnapshot)
{
// render highlights, etc.
renderHighlights();
@@ -9053,6 +9064,7 @@ void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep)
shader.uniform1f(LLShaderMgr::PROJECTOR_SHADOW_FADE, 1.f);
}
+ if (!gCubeSnapshot)
{
LLDrawable* potential = drawablep;
//determine if this is a good light for casting shadows
@@ -9146,14 +9158,10 @@ void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
}
}
- channel = shader.disableTexture(LLShaderMgr::REFLECTION_MAP, LLTexUnit::TT_CUBE_MAP);
- if (channel > -1)
+ channel = shader.disableTexture(LLShaderMgr::REFLECTION_PROBES, LLTexUnit::TT_CUBE_MAP);
+ if (channel > -1 && mReflectionMapManager.mTexture.notNull())
{
- for (int i = 0; i < mReflectionMaps.size(); ++i)
- {
- gGL.getTexUnit(channel + i)->disable();
- }
-
+ mReflectionMapManager.mTexture->unbind();
if (channel == 0)
{
gGL.getTexUnit(channel)->enable(LLTexUnit::TT_TEXTURE);
@@ -9176,7 +9184,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
- if (!assertInitialized())
+ if (!assertInitialized() || gCubeSnapshot)
{
return;
}
@@ -9767,7 +9775,10 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
LLRenderTarget& occlusion_source = mShadow[LLViewerCamera::sCurCameraID - 1];
- doOcclusion(shadow_cam, occlusion_source, occlusion_target);
+ if (occlude > 1)
+ {
+ doOcclusion(shadow_cam, occlusion_source, occlusion_target);
+ }
if (use_shader)
{
@@ -10163,6 +10174,12 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
clip = RenderShadowOrthoClipPlanes;
mSunOrthoClipPlanes = LLVector4(clip, clip.mV[2]*clip.mV[2]/clip.mV[1]);
+ //if (gCubeSnapshot)
+ { //always do a single 64m shadow in reflection maps
+ mSunClipPlanes.set(64.f, 128.f, 256.f);
+ mSunOrthoClipPlanes.set(64.f, 128.f, 256.f);
+ }
+
//currently used for amount to extrude frusta corners for constructing shadow frusta
//LLVector3 n = RenderShadowNearDist;
//F32 nearDist[] = { n.mV[0], n.mV[1], n.mV[2], n.mV[2] };
@@ -10279,9 +10296,8 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
// convenience array of 4 near clip plane distances
F32 dist[] = { near_clip, mSunClipPlanes.mV[0], mSunClipPlanes.mV[1], mSunClipPlanes.mV[2], mSunClipPlanes.mV[3] };
-
if (mSunDiffuse == LLColor4::black)
- { //sun diffuse is totally black, shadows don't matter
+ { //sun diffuse is totally shadows don't matter
LLGLDepthTest depth(GL_TRUE);
for (S32 j = 0; j < 4; j++)
@@ -10293,7 +10309,21 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
}
else
{
- for (S32 j = 0; j < 4; j++)
+ /*if (gCubeSnapshot)
+ {
+ // do one shadow split for cube snapshots, clear the rest
+ mSunClipPlanes.set(64.f, 64.f, 64.f);
+ dist[1] = dist[2] = dist[3] = dist[4] = 64.f;
+ for (S32 j = 1; j < 4; j++)
+ {
+ mShadow[j].bindTarget();
+ mShadow[j].clear();
+ mShadow[j].flush();
+ }
+ }*/
+
+ //for (S32 j = 0; j < (gCubeSnapshot ? 1 : 4); j++)
+ for (S32 j = 0; j < 4; j++)
{
if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA))
{
@@ -10672,142 +10702,145 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
if (gen_shadow)
{
- LLTrace::CountStatHandle<>* velocity_stat = LLViewerCamera::getVelocityStat();
- F32 fade_amt = gFrameIntervalSeconds.value()
- * llmax(LLTrace::get_frame_recording().getLastRecording().getSum(*velocity_stat) / LLTrace::get_frame_recording().getLastRecording().getDuration().value(), 1.0);
-
- //update shadow targets
- for (U32 i = 0; i < 2; i++)
- { //for each current shadow
- LLViewerCamera::sCurCameraID = (LLViewerCamera::eCameraID)(LLViewerCamera::CAMERA_SHADOW4+i);
-
- if (mShadowSpotLight[i].notNull() &&
- (mShadowSpotLight[i] == mTargetShadowSpotLight[0] ||
- mShadowSpotLight[i] == mTargetShadowSpotLight[1]))
- { //keep this spotlight
- mSpotLightFade[i] = llmin(mSpotLightFade[i]+fade_amt, 1.f);
- }
- else
- { //fade out this light
- mSpotLightFade[i] = llmax(mSpotLightFade[i]-fade_amt, 0.f);
+ if (!gCubeSnapshot) //skip updating spot shadow maps during cubemap updates
+ {
+ LLTrace::CountStatHandle<>* velocity_stat = LLViewerCamera::getVelocityStat();
+ F32 fade_amt = gFrameIntervalSeconds.value()
+ * llmax(LLTrace::get_frame_recording().getLastRecording().getSum(*velocity_stat) / LLTrace::get_frame_recording().getLastRecording().getDuration().value(), 1.0);
+
+ //update shadow targets
+ for (U32 i = 0; i < 2; i++)
+ { //for each current shadow
+ LLViewerCamera::sCurCameraID = (LLViewerCamera::eCameraID)(LLViewerCamera::CAMERA_SHADOW4+i);
+
+ if (mShadowSpotLight[i].notNull() &&
+ (mShadowSpotLight[i] == mTargetShadowSpotLight[0] ||
+ mShadowSpotLight[i] == mTargetShadowSpotLight[1]))
+ { //keep this spotlight
+ mSpotLightFade[i] = llmin(mSpotLightFade[i]+fade_amt, 1.f);
+ }
+ else
+ { //fade out this light
+ mSpotLightFade[i] = llmax(mSpotLightFade[i]-fade_amt, 0.f);
- if (mSpotLightFade[i] == 0.f || mShadowSpotLight[i].isNull())
- { //faded out, grab one of the pending spots (whichever one isn't already taken)
- if (mTargetShadowSpotLight[0] != mShadowSpotLight[(i+1)%2])
- {
- mShadowSpotLight[i] = mTargetShadowSpotLight[0];
- }
- else
- {
- mShadowSpotLight[i] = mTargetShadowSpotLight[1];
- }
- }
- }
- }
+ if (mSpotLightFade[i] == 0.f || mShadowSpotLight[i].isNull())
+ { //faded out, grab one of the pending spots (whichever one isn't already taken)
+ if (mTargetShadowSpotLight[0] != mShadowSpotLight[(i+1)%2])
+ {
+ mShadowSpotLight[i] = mTargetShadowSpotLight[0];
+ }
+ else
+ {
+ mShadowSpotLight[i] = mTargetShadowSpotLight[1];
+ }
+ }
+ }
+ }
+
+ for (S32 i = 0; i < 2; i++)
+ {
+ set_current_modelview(saved_view);
+ set_current_projection(saved_proj);
- for (S32 i = 0; i < 2; i++)
- {
- set_current_modelview(saved_view);
- set_current_projection(saved_proj);
+ if (mShadowSpotLight[i].isNull())
+ {
+ continue;
+ }
- if (mShadowSpotLight[i].isNull())
- {
- continue;
- }
+ LLVOVolume* volume = mShadowSpotLight[i]->getVOVolume();
- LLVOVolume* volume = mShadowSpotLight[i]->getVOVolume();
+ if (!volume)
+ {
+ mShadowSpotLight[i] = NULL;
+ continue;
+ }
- if (!volume)
- {
- mShadowSpotLight[i] = NULL;
- continue;
- }
+ LLDrawable* drawable = mShadowSpotLight[i];
- LLDrawable* drawable = mShadowSpotLight[i];
+ LLVector3 params = volume->getSpotLightParams();
+ F32 fov = params.mV[0];
- LLVector3 params = volume->getSpotLightParams();
- F32 fov = params.mV[0];
+ //get agent->light space matrix (modelview)
+ LLVector3 center = drawable->getPositionAgent();
+ LLQuaternion quat = volume->getRenderRotation();
- //get agent->light space matrix (modelview)
- LLVector3 center = drawable->getPositionAgent();
- LLQuaternion quat = volume->getRenderRotation();
+ //get near clip plane
+ LLVector3 scale = volume->getScale();
+ LLVector3 at_axis(0, 0, -scale.mV[2] * 0.5f);
+ at_axis *= quat;
- //get near clip plane
- LLVector3 scale = volume->getScale();
- LLVector3 at_axis(0,0,-scale.mV[2]*0.5f);
- at_axis *= quat;
+ LLVector3 np = center + at_axis;
+ at_axis.normVec();
- LLVector3 np = center+at_axis;
- at_axis.normVec();
+ //get origin that has given fov for plane np, at_axis, and given scale
+ F32 dist = (scale.mV[1] * 0.5f) / tanf(fov * 0.5f);
- //get origin that has given fov for plane np, at_axis, and given scale
- F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f);
+ LLVector3 origin = np - at_axis * dist;
- LLVector3 origin = np - at_axis*dist;
+ LLMatrix4 mat(quat, LLVector4(origin, 1.f));
- LLMatrix4 mat(quat, LLVector4(origin, 1.f));
+ view[i + 4] = glh::matrix4f((F32*)mat.mMatrix);
- view[i+4] = glh::matrix4f((F32*) mat.mMatrix);
+ view[i + 4] = view[i + 4].inverse();
- view[i+4] = view[i+4].inverse();
+ //get perspective matrix
+ F32 near_clip = dist + 0.01f;
+ F32 width = scale.mV[VX];
+ F32 height = scale.mV[VY];
+ F32 far_clip = dist + volume->getLightRadius() * 1.5f;
- //get perspective matrix
- F32 near_clip = dist+0.01f;
- F32 width = scale.mV[VX];
- F32 height = scale.mV[VY];
- F32 far_clip = dist+volume->getLightRadius()*1.5f;
+ F32 fovy = fov * RAD_TO_DEG;
+ F32 aspect = width / height;
- F32 fovy = fov * RAD_TO_DEG;
- F32 aspect = width/height;
-
- proj[i+4] = gl_perspective(fovy, aspect, near_clip, far_clip);
+ proj[i + 4] = gl_perspective(fovy, aspect, near_clip, far_clip);
- //translate and scale to from [-1, 1] to [0, 1]
- glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
- 0.f, 0.5f, 0.f, 0.5f,
- 0.f, 0.f, 0.5f, 0.5f,
- 0.f, 0.f, 0.f, 1.f);
+ //translate and scale to from [-1, 1] to [0, 1]
+ glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
+ 0.f, 0.5f, 0.f, 0.5f,
+ 0.f, 0.f, 0.5f, 0.5f,
+ 0.f, 0.f, 0.f, 1.f);
- set_current_modelview(view[i+4]);
- set_current_projection(proj[i+4]);
+ set_current_modelview(view[i + 4]);
+ set_current_projection(proj[i + 4]);
- mSunShadowMatrix[i+4] = trans*proj[i+4]*view[i+4]*inv_view;
-
- for (U32 j = 0; j < 16; j++)
- {
- gGLLastModelView[j] = mShadowModelview[i+4].m[j];
- gGLLastProjection[j] = mShadowProjection[i+4].m[j];
- }
+ mSunShadowMatrix[i + 4] = trans * proj[i + 4] * view[i + 4] * inv_view;
- mShadowModelview[i+4] = view[i+4];
- mShadowProjection[i+4] = proj[i+4];
+ for (U32 j = 0; j < 16; j++)
+ {
+ gGLLastModelView[j] = mShadowModelview[i + 4].m[j];
+ gGLLastProjection[j] = mShadowProjection[i + 4].m[j];
+ }
- LLCamera shadow_cam = camera;
- shadow_cam.setFar(far_clip);
- shadow_cam.setOrigin(origin);
+ mShadowModelview[i + 4] = view[i + 4];
+ mShadowProjection[i + 4] = proj[i + 4];
- LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
+ LLCamera shadow_cam = camera;
+ shadow_cam.setFar(far_clip);
+ shadow_cam.setOrigin(origin);
- stop_glerror();
+ LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
- mShadow[i+4].bindTarget();
- mShadow[i+4].getViewport(gGLViewport);
- mShadow[i+4].clear();
+ stop_glerror();
+
+ mShadow[i + 4].bindTarget();
+ mShadow[i + 4].getViewport(gGLViewport);
+ mShadow[i + 4].clear();
- U32 target_width = mShadow[i+4].getWidth();
+ U32 target_width = mShadow[i + 4].getWidth();
- static LLCullResult result[2];
+ static LLCullResult result[2];
- LLViewerCamera::sCurCameraID = (LLViewerCamera::eCameraID)(LLViewerCamera::CAMERA_SHADOW0 + i + 4);
+ LLViewerCamera::sCurCameraID = (LLViewerCamera::eCameraID)(LLViewerCamera::CAMERA_SHADOW0 + i + 4);
- RenderSpotLight = drawable;
+ RenderSpotLight = drawable;
- renderShadow(view[i+4], proj[i+4], shadow_cam, result[i], FALSE, FALSE, target_width);
+ renderShadow(view[i + 4], proj[i + 4], shadow_cam, result[i], FALSE, FALSE, target_width);
- RenderSpotLight = nullptr;
+ RenderSpotLight = nullptr;
- mShadow[i+4].flush();
- }
+ mShadow[i + 4].flush();
+ }
+ }
}
else
{ //no spotlight shadows
@@ -11526,7 +11559,7 @@ void LLPipeline::restoreHiddenObject( const LLUUID& id )
void LLPipeline::overrideEnvironmentMap()
{
- mReflectionMapManager.mProbes.clear();
- mReflectionMapManager.addProbe(LLViewerCamera::instance().getOrigin());
+ //mReflectionMapManager.mProbes.clear();
+ //mReflectionMapManager.addProbe(LLViewerCamera::instance().getOrigin());
}
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 975380929d..88eaca558a 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -578,7 +578,8 @@ public:
RENDER_DEBUG_ATTACHMENT_BYTES = 0x20000000, // not used
RENDER_DEBUG_TEXEL_DENSITY = 0x40000000,
RENDER_DEBUG_TRIANGLE_COUNT = 0x80000000,
- RENDER_DEBUG_IMPOSTORS = 0x100000000
+ RENDER_DEBUG_IMPOSTORS = 0x100000000,
+ RENDER_DEBUG_REFLECTION_PROBES = 0x200000000
};
public:
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index db4e794ed4..0b0f8e17bc 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2912,6 +2912,16 @@ function="World.EnvPreset"
parameter="lights" />
</menu_item_check>
<menu_item_check
+ label="Reflection Probes"
+ name="Reflection Probes">
+ <menu_item_check.on_check
+ function="Advanced.CheckInfoDisplay"
+ parameter="reflection probes" />
+ <menu_item_check.on_click
+ function="Advanced.ToggleInfoDisplay"
+ parameter="reflection probes" />
+ </menu_item_check>
+ <menu_item_check
label="Particles"
name="Particles">
<menu_item_check.on_check
@@ -3252,10 +3262,10 @@ function="World.EnvPreset"
</menu_item_check>
<menu_item_call
enabled="true"
- label="Override Environment Map"
- name="Override Environment Map">
+ label="Rebuild Reflection Probes"
+ name="Rebuild Reflection Probes">
<menu_item_call.on_click
- function="Develop.OverrideEnvironmentMap" />
+ function="Develop.RebuildReflectionProbes" />
</menu_item_call>
<menu_item_separator />