Merge branch 'release/materials_featurette' of https://github.com/secondlife/viewer

# Conflicts:
#	indra/newview/app_settings/settings.xml
#	indra/newview/llspatialpartition.cpp
#	indra/newview/llviewermenu.cpp
#	indra/newview/pipeline.cpp
#	indra/newview/skins/default/xui/en/menu_viewer.xml
meow-7.2.2
Ansariel 2024-02-05 12:18:37 +01:00
commit c73b3b2a1b
25 changed files with 687 additions and 102 deletions

View File

@ -594,11 +594,22 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev
}
else
{
//set version to 1.40
shader_code_text[shader_code_count++] = strdup("#version 140\n");
//some implementations of GLSL 1.30 require integer precision be explicitly declared
extra_code_text[extra_code_count++] = strdup("precision mediump int;\n");
extra_code_text[extra_code_count++] = strdup("precision highp float;\n");
if (type == GL_GEOMETRY_SHADER)
{
//set version to 1.50
shader_code_text[shader_code_count++] = strdup("#version 150\n");
//some implementations of GLSL 1.30 require integer precision be explicitly declared
extra_code_text[extra_code_count++] = strdup("precision mediump int;\n");
extra_code_text[extra_code_count++] = strdup("precision highp float;\n");
}
else
{
//set version to 1.40
shader_code_text[shader_code_count++] = strdup("#version 140\n");
//some implementations of GLSL 1.30 require integer precision be explicitly declared
extra_code_text[extra_code_count++] = strdup("precision mediump int;\n");
extra_code_text[extra_code_count++] = strdup("precision highp float;\n");
}
}
extra_code_text[extra_code_count++] = strdup("#define FXAA_GLSL_130 1\n");
@ -1471,6 +1482,8 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("sun_up_factor");
mReservedUniforms.push_back("moonlight_color");
mReservedUniforms.push_back("debug_normal_draw_length");
llassert(mReservedUniforms.size() == END_RESERVED_UNIFORMS);
std::set<std::string> dupe_check;

View File

@ -329,6 +329,9 @@ public:
WATER_EDGE_FACTOR, // "water_edge"
SUN_UP_FACTOR, // "sun_up_factor"
MOONLIGHT_COLOR, // "moonlight_color"
DEBUG_NORMAL_DRAW_LENGTH, // "debug_normal_draw_length"
END_RESERVED_UNIFORMS
} eGLSLReservedUniforms;
// clang-format on

View File

@ -14005,6 +14005,17 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<real>8.0</real>
</map>
<key>RenderTerrainPBRNormalsEnabled</key>
<map>
<key>Comment</key>
<string>EXPERIMENTAL: Change normal gen for PBR Terrain.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>RenderTrackerBeacon</key>
<map>
<key>Comment</key>

View File

@ -0,0 +1,33 @@
/**
* @file normaldebugF.glsl
*
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2023, 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$
*/
out vec4 frag_color;
in vec4 vertex_color;
void main()
{
frag_color = max(vertex_color, vec4(0));
}

View File

@ -0,0 +1,76 @@
/**
* @file normaldebugG.glsl
*
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2023, 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$
*/
// *NOTE: Geometry shaders have a reputation for being slow. Consider using
// compute shaders instead, which have a reputation for being fast. This
// geometry shader in particular seems to run fine on my machine, but I won't
// vouch for this in performance-critical areas.
// -Cosmic,2023-09-28
out vec4 vertex_color;
in vec4 normal_g[];
#if HAS_ATTRIBUTE_TANGENT == 1
in vec4 tangent_g[];
#endif
layout(TRIANGLES) in;
#if HAS_ATTRIBUTE_TANGENT == 1
layout(LINE_STRIP, max_vertices = 12) out;
#else
layout(LINE_STRIP, max_vertices = 6) out;
#endif
void triangle_normal_debug(int i)
{
// Normal
vec4 normal_color = vec4(1.0, 1.0, 0.0, 1.0);
gl_Position = gl_in[i].gl_Position;
vertex_color = normal_color;
EmitVertex();
gl_Position = normal_g[i];
vertex_color = normal_color;
EmitVertex();
EndPrimitive();
#if HAS_ATTRIBUTE_TANGENT == 1
// Tangent
vec4 tangent_color = vec4(0.0, 1.0, 1.0, 1.0);
gl_Position = gl_in[i].gl_Position;
vertex_color = tangent_color;
EmitVertex();
gl_Position = tangent_g[i];
vertex_color = tangent_color;
EmitVertex();
EndPrimitive();
#endif
}
void main()
{
triangle_normal_debug(0);
triangle_normal_debug(1);
triangle_normal_debug(2);
}

View File

@ -0,0 +1,74 @@
/**
* @file normaldebugV.glsl
*
* $LicenseInfo:firstyear=2023&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2023, 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$
*/
in vec3 position;
in vec3 normal;
out vec4 normal_g;
#if HAS_ATTRIBUTE_TANGENT == 1
in vec4 tangent;
out vec4 tangent_g;
#endif
uniform float debug_normal_draw_length;
#ifdef HAS_SKIN
mat4 getObjectSkinnedTransform();
#else
uniform mat3 normal_matrix;
#endif
uniform mat4 projection_matrix;
uniform mat4 modelview_matrix;
// *NOTE: Should use the modelview_projection_matrix here in the non-skinned
// case for efficiency, but opting for the simplier implementation for now as
// this is debug code. Also, the skinned version hasn't beeen tested yet.
// world_pos = mat * vec4(position.xyz, 1.0)
vec4 get_screen_normal(vec3 position, vec4 world_pos, vec3 normal, mat4 mat)
{
vec4 world_norm = mat * vec4((position + normal), 1.0);
world_norm.xyz -= world_pos.xyz;
world_norm.xyz = debug_normal_draw_length * normalize(world_norm.xyz);
world_norm.xyz += world_pos.xyz;
return projection_matrix * world_norm;
}
void main()
{
#ifdef HAS_SKIN
mat4 mat = getObjectSkinnedTransform();
mat = modelview_matrix * mat;
#else
#define mat modelview_matrix
#endif
vec4 world_pos = mat * vec4(position.xyz,1.0);
gl_Position = projection_matrix * world_pos;
normal_g = get_screen_normal(position.xyz, world_pos, normal.xyz, mat);
#if HAS_ATTRIBUTE_TANGENT == 1
tangent_g = get_screen_normal(position.xyz, world_pos, tangent.xyz, mat);
#endif
}

View File

@ -40,6 +40,8 @@ public:
virtual ~LLFetchedGLTFMaterial();
LLFetchedGLTFMaterial& operator=(const LLFetchedGLTFMaterial& rhs);
// LLGLTFMaterial::operator== is defined, but LLFetchedGLTFMaterial::operator== is not.
bool operator==(const LLGLTFMaterial& rhs) const = delete;
// If this material is loaded, fire the given function
void onMaterialComplete(std::function<void()> material_complete);

View File

@ -34,6 +34,7 @@
#include "llenvironment.h"
#include "llselectmgr.h"
#include "llviewercamera.h"
#include "llviewercontrol.h"
#include "llviewerobject.h"
#include "llviewershadermgr.h"
#include "llviewertexturelist.h"
@ -95,7 +96,7 @@ namespace
{
void fetch_texture_for_ui(LLPointer<LLViewerFetchedTexture>& img, const LLUUID& id)
{
if (id.notNull())
if (!img && id.notNull())
{
if (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::isBakedImageId(id))
{
@ -129,6 +130,8 @@ namespace
LLGLTFPreviewTexture::MaterialLoadLevels get_material_load_levels(LLFetchedGLTFMaterial& material)
{
llassert(!material.isFetching());
using MaterialTextures = LLPointer<LLViewerFetchedTexture>*[LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT];
MaterialTextures textures;
@ -334,7 +337,7 @@ void set_preview_sphere_material(PreviewSphere& preview_sphere, LLPointer<LLFetc
info->mGLTFMaterial = material;
LLVertexBuffer* buf = info->mVertexBuffer.get();
LLStrider<LLColor4U> colors;
const S32 count = info->mEnd - info->mStart;
const S32 count = info->mEnd - info->mStart + 1;
buf->getColorStrider(colors, info->mStart, count);
for (S32 i = 0; i < count; ++i)
{
@ -419,7 +422,8 @@ BOOL LLGLTFPreviewTexture::render()
LLVector3 light_dir3(1.0f, 1.0f, 1.0f);
light_dir3.normalize();
const LLVector4 light_dir = LLVector4(light_dir3, 0);
SetTemporarily<S32> sun_light_only(&LLPipeline::RenderLocalLightCount, 0);
const S32 old_local_light_count = gSavedSettings.get<S32>("RenderLocalLightCount");
gSavedSettings.set<S32>("RenderLocalLightCount", 0);
gPipeline.mReflectionMapManager.forceDefaultProbeAndUpdateUniforms();
@ -524,6 +528,7 @@ BOOL LLGLTFPreviewTexture::render()
// Clean up
gPipeline.setupHWLights();
gPipeline.mReflectionMapManager.forceDefaultProbeAndUpdateUniforms(false);
gSavedSettings.set<S32>("RenderLocalLightCount", old_local_light_count);
return TRUE;
}

View File

@ -47,6 +47,7 @@
#include "pipeline.h"
#include "llmeshrepository.h"
#include "llrender.h"
#include "lldrawpool.h"
#include "lloctree.h"
#include "llphysicsshapebuilderutil.h"
#include "llvoavatar.h"
@ -2024,7 +2025,11 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
drawBoxOutline(pos,size);
}
}
// *TODO: LLDrawables which are not part of LLVOVolumes fall into a different
// code path which uses a shader - it was tested to be faster than mapping a
// vertex buffer in the terrain case. Consider using it for LLVOVolumes as well
// to simplify and speed up this debug code. Alternatively, a compute shader is
// likely faster. -Cosmic,2023-09-28
void renderNormals(LLDrawable *drawablep)
{
if (!drawablep->isVisible())
@ -2032,20 +2037,22 @@ void renderNormals(LLDrawable *drawablep)
LLVertexBuffer::unbind();
LLViewerObject* obj = drawablep->getVObj();
LLVOVolume *vol = drawablep->getVOVolume();
if (vol)
if (obj)
{
// <FS:Beq> FIX and improve renderNormals debug
static LLCachedControl<bool> showSelectedOnly(gSavedSettings, "OnlyShowSelectedNormals");
if(showSelectedOnly && !drawablep->getVObj()->isSelected())
if (showSelectedOnly && !obj->isSelected())
{
drawablep->getVObj()->setDebugText("");
obj->setDebugText("");
return;
}
// </FS:Beq>
LLVolume *volume = vol->getVolume();
LLGLEnable blend(GL_BLEND);
LLGLDepthTest gl_depth(GL_TRUE, GL_FALSE);
// Drawable's normals & tangents are stored in model space, i.e. before any scaling is applied.
//
@ -2054,68 +2061,136 @@ void renderNormals(LLDrawable *drawablep)
// transform. We get that effect here by pre-applying the inverse scale (twice, because
// one forward scale will be re-applied via the MVP in the vertex shader)
LLVector3 scale_v3 = vol->getScale();
float scale_len = scale_v3.length();
LLVector4a obj_scale(scale_v3.mV[VX], scale_v3.mV[VY], scale_v3.mV[VZ]);
obj_scale.normalize3();
LLVector4a inv_scale;
float scale_len;
if (vol)
{
LLVector3 scale_v3 = vol->getScale();
LLVector4a obj_scale(scale_v3.mV[VX], scale_v3.mV[VY], scale_v3.mV[VZ]);
obj_scale.normalize3();
// Create inverse-scale vector for normals
inv_scale.set(1.0 / scale_v3.mV[VX], 1.0 / scale_v3.mV[VY], 1.0 / scale_v3.mV[VZ], 0.0);
inv_scale.mul(inv_scale); // Squared, to apply inverse scale twice
inv_scale.normalize3fast();
scale_len = scale_v3.length();
}
else
{
inv_scale.set(1.0, 1.0, 1.0, 0.0);
scale_len = 1.0;
}
gGL.pushMatrix();
if (vol)
{
gGL.multMatrix((F32 *) vol->getRelativeXform().mMatrix);
}
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
// Normals &tangent line segments get scaled along with the object. Divide by scale length
// to keep the as-viewed lengths (relatively) constant with the debug setting length
float draw_length = gSavedSettings.getF32("RenderDebugNormalScale") / scale_len;
// Create inverse-scale vector for normals
LLVector4a inv_scale(1.0 / scale_v3.mV[VX], 1.0 / scale_v3.mV[VY], 1.0 / scale_v3.mV[VZ]);
inv_scale.mul(inv_scale); // Squared, to apply inverse scale twice
inv_scale.normalize3fast();
gGL.pushMatrix();
gGL.multMatrix((F32 *) vol->getRelativeXform().mMatrix);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
std::vector<LLVolumeFace>* faces = nullptr;
std::vector<LLFace*>* drawable_faces = nullptr;
if (vol)
{
const LLVolumeFace &face = volume->getVolumeFace(i);
gGL.flush();
gGL.diffuseColor4f(1, 1, 0, 1);
gGL.begin(LLRender::LINES);
for (S32 j = 0; j < face.mNumVertices; ++j)
{
LLVector4a n, p;
n.setMul(face.mNormals[j], 1.0);
n.mul(inv_scale); // Pre-scale normal, so it's left with an inverse-transpose xform after MVP
n.normalize3fast();
n.mul(draw_length);
p.setAdd(face.mPositions[j], n);
gGL.vertex3fv(face.mPositions[j].getF32ptr());
gGL.vertex3fv(p.getF32ptr());
}
gGL.end();
// Tangents are simple vectors and do not require reorientation via pre-scaling
if (face.mTangents)
{
gGL.flush();
gGL.diffuseColor4f(0, 1, 1, 1);
gGL.begin(LLRender::LINES);
for (S32 j = 0; j < face.mNumVertices; ++j)
{
LLVector4a t, p;
t.setMul(face.mTangents[j], 1.0f);
t.normalize3fast();
t.mul(draw_length);
p.setAdd(face.mPositions[j], t);
gGL.vertex3fv(face.mPositions[j].getF32ptr());
gGL.vertex3fv(p.getF32ptr());
}
gGL.end();
}
LLVolume* volume = vol->getVolume();
faces = &volume->getVolumeFaces();
}
else
{
drawable_faces = &drawablep->getFaces();
}
if (faces)
{
for (auto it = faces->begin(); it != faces->end(); ++it)
{
const LLVolumeFace& face = *it;
gGL.flush();
gGL.diffuseColor4f(1, 1, 0, 1);
gGL.begin(LLRender::LINES);
for (S32 j = 0; j < face.mNumVertices; ++j)
{
LLVector4a n, p;
n.setMul(face.mNormals[j], 1.0);
n.mul(inv_scale); // Pre-scale normal, so it's left with an inverse-transpose xform after MVP
n.normalize3fast();
n.mul(draw_length);
p.setAdd(face.mPositions[j], n);
gGL.vertex3fv(face.mPositions[j].getF32ptr());
gGL.vertex3fv(p.getF32ptr());
}
gGL.end();
// Tangents are simple vectors and do not require reorientation via pre-scaling
if (face.mTangents)
{
gGL.flush();
gGL.diffuseColor4f(0, 1, 1, 1);
gGL.begin(LLRender::LINES);
for (S32 j = 0; j < face.mNumVertices; ++j)
{
LLVector4a t, p;
t.setMul(face.mTangents[j], 1.0f);
t.normalize3fast();
t.mul(draw_length);
p.setAdd(face.mPositions[j], t);
gGL.vertex3fv(face.mPositions[j].getF32ptr());
gGL.vertex3fv(p.getF32ptr());
}
gGL.end();
}
}
}
else if (drawable_faces)
{
// *HACK: Prepare to restore previous shader as other debug code depends on a simpler shader being present
llassert(LLGLSLShader::sCurBoundShaderPtr == &gDebugProgram);
LLGLSLShader* prev_shader = LLGLSLShader::sCurBoundShaderPtr;
for (auto it = drawable_faces->begin(); it != drawable_faces->end(); ++it)
{
LLFace* facep = *it;
LLFace& face = **it;
LLVertexBuffer* buf = face.getVertexBuffer();
if (!buf) { continue; }
U32 mask_vn = LLVertexBuffer::TYPE_VERTEX | LLVertexBuffer::TYPE_NORMAL;
if ((buf->getTypeMask() & mask_vn) != mask_vn) { continue; }
LLGLSLShader* shader;
if ((buf->getTypeMask() & LLVertexBuffer::TYPE_TANGENT) != LLVertexBuffer::TYPE_TANGENT)
{
shader = &gNormalDebugProgram[NORMAL_DEBUG_SHADER_DEFAULT];
}
else
{
shader = &gNormalDebugProgram[NORMAL_DEBUG_SHADER_WITH_TANGENTS];
}
shader->bind();
shader->uniform1f(LLShaderMgr::DEBUG_NORMAL_DRAW_LENGTH, draw_length);
LLRenderPass::applyModelMatrix(&facep->getDrawable()->getRegion()->mRenderMatrix);
buf->setBuffer();
// *NOTE: The render type in the vertex shader is TRIANGLES, but gets converted to LINES in the geometry shader
// *NOTE: For terrain normal debug, this seems to also include vertices for water, which is technically not part of the terrain. Should fix that at some point.
buf->drawRange(LLRender::TRIANGLES, face.getGeomIndex(), face.getGeomIndex() + face.getGeomCount()-1, face.getIndicesCount(), face.getIndicesStart());
}
if (prev_shader)
{
prev_shader->bind();
}
}
gGL.popMatrix();
}

View File

@ -827,17 +827,18 @@ void LLSurface::updatePatchVisibilities(LLAgent &agent)
}
}
BOOL LLSurface::idleUpdate(F32 max_update_time)
template<bool PBR>
bool LLSurface::idleUpdate(F32 max_update_time)
{
if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_TERRAIN))
{
return FALSE;
return false;
}
// Perform idle time update of non-critical stuff.
// In this case, texture and normal updates.
LLTimer update_timer;
BOOL did_update = FALSE;
bool did_update = false;
// If the Z height data has changed, we need to rebuild our
// property line vertex arrays.
@ -853,13 +854,13 @@ BOOL LLSurface::idleUpdate(F32 max_update_time)
{
std::set<LLSurfacePatch *>::iterator curiter = iter++;
LLSurfacePatch *patchp = *curiter;
patchp->updateNormals();
patchp->updateNormals<PBR>();
patchp->updateVerticalStats();
if (max_update_time == 0.f || update_timer.getElapsedTimeF32() < max_update_time)
{
if (patchp->updateTexture())
{
did_update = TRUE;
did_update = true;
patchp->clearDirty();
mDirtyPatchList.erase(curiter);
}
@ -875,6 +876,9 @@ BOOL LLSurface::idleUpdate(F32 max_update_time)
return did_update;
}
template bool LLSurface::idleUpdate</*PBR=*/false>(F32 max_update_time);
template bool LLSurface::idleUpdate</*PBR=*/true>(F32 max_update_time);
void LLSurface::decompressDCTPatch(LLBitPack &bitpack, LLGroupHeader *gopp, BOOL b_large_patch)
{

View File

@ -115,7 +115,8 @@ public:
LLSurfacePatch *resolvePatchGlobal(const LLVector3d &position_global) const;
// Update methods (called during idle, normally)
BOOL idleUpdate(F32 max_update_time);
template<bool PBR>
bool idleUpdate(F32 max_update_time);
BOOL containsPosition(const LLVector3 &position);
@ -227,6 +228,9 @@ private:
static S32 sTextureSize; // Size of the surface texture
};
extern template bool LLSurface::idleUpdate</*PBR=*/false>(F32 max_update_time);
extern template bool LLSurface::idleUpdate</*PBR=*/true>(F32 max_update_time);
// . __.

View File

@ -268,7 +268,8 @@ void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3
}
void LLSurfacePatch::calcNormal(const U32 x, const U32 y, const U32 stride)
template<>
void LLSurfacePatch::calcNormal</*PBR=*/false>(const U32 x, const U32 y, const U32 stride)
{
U32 patch_width = mSurfacep->mPVArray.mPatchWidth;
U32 surface_stride = mSurfacep->getGridsPerEdge();
@ -420,6 +421,166 @@ void LLSurfacePatch::calcNormal(const U32 x, const U32 y, const U32 stride)
*(mDataNorm + surface_stride * y + x) = normal;
}
template<>
void LLSurfacePatch::calcNormal</*PBR=*/true>(const U32 x, const U32 y, const U32 stride)
{
llassert(mDataNorm);
constexpr U32 index = 0;
const U32 surface_stride = mSurfacep->getGridsPerEdge();
LLVector3& normal_out = *(mDataNorm + surface_stride * y + x);
calcNormalFlat(normal_out, x, y, index);
}
// Calculate the flat normal of a triangle whose least coordinate is specified by the given x,y values.
// If index = 0, calculate the normal of the first triangle, otherwise calculate the normal of the second.
void LLSurfacePatch::calcNormalFlat(LLVector3& normal_out, const U32 x, const U32 y, const U32 index)
{
llassert(index == 0 || index == 1);
U32 patch_width = mSurfacep->mPVArray.mPatchWidth;
U32 surface_stride = mSurfacep->getGridsPerEdge();
// Vertex stride is always 1 because we want the flat surface of the current triangle face
constexpr U32 stride = 1;
const F32 mpg = mSurfacep->getMetersPerGrid() * stride;
S32 poffsets[2][2][2];
poffsets[0][0][0] = x;
poffsets[0][0][1] = y;
poffsets[0][1][0] = x;
poffsets[0][1][1] = y + stride;
poffsets[1][0][0] = x + stride;
poffsets[1][0][1] = y;
poffsets[1][1][0] = x + stride;
poffsets[1][1][1] = y + stride;
const LLSurfacePatch *ppatches[2][2];
// LLVector3 p1, p2, p3, p4;
ppatches[0][0] = this;
ppatches[0][1] = this;
ppatches[1][0] = this;
ppatches[1][1] = this;
U32 i, j;
for (i = 0; i < 2; i++)
{
for (j = 0; j < 2; j++)
{
if (poffsets[i][j][0] < 0)
{
if (!ppatches[i][j]->getNeighborPatch(WEST))
{
poffsets[i][j][0] = 0;
}
else
{
poffsets[i][j][0] += patch_width;
ppatches[i][j] = ppatches[i][j]->getNeighborPatch(WEST);
}
}
if (poffsets[i][j][1] < 0)
{
if (!ppatches[i][j]->getNeighborPatch(SOUTH))
{
poffsets[i][j][1] = 0;
}
else
{
poffsets[i][j][1] += patch_width;
ppatches[i][j] = ppatches[i][j]->getNeighborPatch(SOUTH);
}
}
if (poffsets[i][j][0] >= (S32)patch_width)
{
if (!ppatches[i][j]->getNeighborPatch(EAST))
{
poffsets[i][j][0] = patch_width - 1;
}
else
{
poffsets[i][j][0] -= patch_width;
ppatches[i][j] = ppatches[i][j]->getNeighborPatch(EAST);
}
}
if (poffsets[i][j][1] >= (S32)patch_width)
{
if (!ppatches[i][j]->getNeighborPatch(NORTH))
{
poffsets[i][j][1] = patch_width - 1;
}
else
{
poffsets[i][j][1] -= patch_width;
ppatches[i][j] = ppatches[i][j]->getNeighborPatch(NORTH);
}
}
}
}
LLVector3 p00(-mpg,-mpg,
*(ppatches[0][0]->mDataZ
+ poffsets[0][0][0]
+ poffsets[0][0][1]*surface_stride));
LLVector3 p01(-mpg,+mpg,
*(ppatches[0][1]->mDataZ
+ poffsets[0][1][0]
+ poffsets[0][1][1]*surface_stride));
LLVector3 p10(+mpg,-mpg,
*(ppatches[1][0]->mDataZ
+ poffsets[1][0][0]
+ poffsets[1][0][1]*surface_stride));
LLVector3 p11(+mpg,+mpg,
*(ppatches[1][1]->mDataZ
+ poffsets[1][1][0]
+ poffsets[1][1][1]*surface_stride));
// Triangle index / coordinate convention
// for a single surface patch
//
// p01 p11
//
// ^ ._____.
// | |\ |
// | | \ 1 |
// | | \ |
// | 0 \ |
// y |____\|
//
// p00 x ---> p10
//
// (z up / out of the screen due to right-handed coordinate system)
LLVector3 normal;
if (index == 0)
{
LLVector3 c1 = p10 - p00;
LLVector3 c2 = p01 - p00;
normal = c1;
normal %= c2;
normal.normVec();
}
else // index == 1
{
LLVector3 c1 = p11 - p01;
LLVector3 c2 = p11 - p10;
normal = c1;
normal %= c2;
normal.normVec();
}
llassert(&normal_out);
normal_out = normal;
}
const LLVector3 &LLSurfacePatch::getNormal(const U32 x, const U32 y) const
{
U32 surface_stride = mSurfacep->getGridsPerEdge();
@ -517,6 +678,7 @@ void LLSurfacePatch::updateVerticalStats()
}
template<bool PBR>
void LLSurfacePatch::updateNormals()
{
if (mSurfacep->mType == 'w')
@ -534,9 +696,9 @@ void LLSurfacePatch::updateNormals()
{
for (j = 0; j <= grids_per_patch_edge; j++)
{
calcNormal(grids_per_patch_edge, j, 2);
calcNormal(grids_per_patch_edge - 1, j, 2);
calcNormal(grids_per_patch_edge - 2, j, 2);
calcNormal<PBR>(grids_per_patch_edge, j, 2);
calcNormal<PBR>(grids_per_patch_edge - 1, j, 2);
calcNormal<PBR>(grids_per_patch_edge - 2, j, 2);
}
dirty_patch = TRUE;
@ -559,9 +721,9 @@ void LLSurfacePatch::updateNormals()
for (i = 0; i <= grids_per_patch_edge; i++)
{
calcNormal(i, grids_per_patch_edge, 2);
calcNormal(i, grids_per_patch_edge - 1, 2);
calcNormal(i, grids_per_patch_edge - 2, 2);
calcNormal<PBR>(i, grids_per_patch_edge, 2);
calcNormal<PBR>(i, grids_per_patch_edge - 1, 2);
calcNormal<PBR>(i, grids_per_patch_edge - 2, 2);
}
dirty_patch = TRUE;
@ -582,8 +744,8 @@ void LLSurfacePatch::updateNormals()
for (j = 0; j < grids_per_patch_edge; j++)
{
calcNormal(0, j, 2);
calcNormal(1, j, 2);
calcNormal<PBR>(0, j, 2);
calcNormal<PBR>(1, j, 2);
}
dirty_patch = TRUE;
}
@ -604,8 +766,8 @@ void LLSurfacePatch::updateNormals()
for (i = 0; i < grids_per_patch_edge; i++)
{
calcNormal(i, 0, 2);
calcNormal(i, 1, 2);
calcNormal<PBR>(i, 0, 2);
calcNormal<PBR>(i, 1, 2);
}
dirty_patch = TRUE;
}
@ -704,10 +866,10 @@ void LLSurfacePatch::updateNormals()
// We've got a northeast patch in the same surface.
// The z and normals will be handled by that patch.
}
calcNormal(grids_per_patch_edge, grids_per_patch_edge, 2);
calcNormal(grids_per_patch_edge, grids_per_patch_edge - 1, 2);
calcNormal(grids_per_patch_edge - 1, grids_per_patch_edge, 2);
calcNormal(grids_per_patch_edge - 1, grids_per_patch_edge - 1, 2);
calcNormal<PBR>(grids_per_patch_edge, grids_per_patch_edge, 2);
calcNormal<PBR>(grids_per_patch_edge, grids_per_patch_edge - 1, 2);
calcNormal<PBR>(grids_per_patch_edge - 1, grids_per_patch_edge, 2);
calcNormal<PBR>(grids_per_patch_edge - 1, grids_per_patch_edge - 1, 2);
dirty_patch = TRUE;
}
@ -718,7 +880,7 @@ void LLSurfacePatch::updateNormals()
{
for (i=2; i < grids_per_patch_edge - 2; i++)
{
calcNormal(i, j, 2);
calcNormal<PBR>(i, j, 2);
}
}
dirty_patch = TRUE;
@ -735,6 +897,9 @@ void LLSurfacePatch::updateNormals()
}
}
template void LLSurfacePatch::updateNormals</*PBR=*/false>();
template void LLSurfacePatch::updateNormals</*PBR=*/true>();
void LLSurfacePatch::updateEastEdge()
{
U32 grids_per_patch_edge = mSurfacep->getGridsPerPatchEdge();

View File

@ -77,6 +77,7 @@ public:
void updateVerticalStats();
void updateCompositionStats();
template<bool PBR>
void updateNormals();
void updateEastEdge();
@ -102,9 +103,18 @@ public:
LLVector3 getPointAgent(const U32 x, const U32 y) const; // get the point at the offset.
LLVector2 getTexCoords(const U32 x, const U32 y) const;
// Per-vertex normals
// *TODO: PBR=true is a test implementation solely for proof-of-concept.
// Final implementation would likely be very different and may not even use
// this function. If we decide to keep calcNormalFlat, remove index as it
// is a debug parameter for testing.
template<bool PBR>
void calcNormal(const U32 x, const U32 y, const U32 stride);
const LLVector3 &getNormal(const U32 x, const U32 y) const;
// Per-triangle normals for flat edges
void calcNormalFlat(LLVector3& normal_out, const U32 x, const U32 y, const U32 index /* 0 or 1 */);
void eval(const U32 x, const U32 y, const U32 stride,
LLVector3 *vertex, LLVector3 *normal, LLVector2 *tex0, LLVector2 *tex1);
@ -181,5 +191,8 @@ protected:
LLSurface *mSurfacep; // Pointer to "parent" surface
};
extern template void LLSurfacePatch::updateNormals</*PBR=*/false>();
extern template void LLSurfacePatch::updateNormals</*PBR=*/true>();
#endif // LL_LLSURFACEPATCH_H

View File

@ -732,7 +732,7 @@ void LLFloaterTexturePicker::draw()
{
mGLTFMaterial = (LLFetchedGLTFMaterial*) gGLTFMaterialList.getMaterial(mImageAssetID);
llassert(mGLTFMaterial == nullptr || dynamic_cast<LLFetchedGLTFMaterial*>(gGLTFMaterialList.getMaterial(mImageAssetID)) != nullptr);
if (mGLTFPreview.isNull() || mGLTFMaterial.isNull() || (old_material.notNull() && (*old_material.get() != *mGLTFMaterial.get())))
if (mGLTFPreview.isNull() || mGLTFMaterial.isNull() || (old_material.notNull() && (old_material.get() != mGLTFMaterial.get())))
{
// Only update the preview if needed, since gGLTFMaterialPreviewMgr does not cache the preview.
if (mGLTFMaterial.isNull())
@ -2395,7 +2395,7 @@ void LLTextureCtrl::draw()
if (mInventoryPickType == PICK_MATERIAL)
{
mGLTFMaterial = gGLTFMaterialList.getMaterial(mImageAssetID);
if (mGLTFPreview.isNull() || mGLTFMaterial.isNull() || (old_material.notNull() && (*old_material.get() != *mGLTFMaterial.get())))
if (mGLTFPreview.isNull() || mGLTFMaterial.isNull() || (old_material.notNull() && (old_material.get() != mGLTFMaterial.get())))
{
// Only update the preview if needed, since gGLTFMaterialPreviewMgr does not cache the preview.
if (mGLTFMaterial.isNull())

View File

@ -846,8 +846,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 2")
if (gResizeScreenTexture)
{
gResizeScreenTexture = FALSE;
gPipeline.resizeScreenTexture();
gResizeScreenTexture = FALSE;
}
gGL.setColorMask(true, true);

View File

@ -2441,6 +2441,20 @@ class LLAdvancedPurgeShaderCache : public view_listener_t
}
};
/////////////////////
// REBUILD TERRAIN //
/////////////////////
class LLAdvancedRebuildTerrain : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
gPipeline.rebuildTerrain();
return true;
}
};
////////////////////
// EVENT Recorder //
///////////////////
@ -12282,6 +12296,10 @@ void initialize_menus()
view_listener_t::addMenu(new LLAdvancedClickRenderProfile(), "Advanced.ClickRenderProfile");
view_listener_t::addMenu(new LLAdvancedClickRenderBenchmark(), "Advanced.ClickRenderBenchmark");
view_listener_t::addMenu(new LLAdvancedPurgeShaderCache(), "Advanced.ClearShaderCache");
if (gSavedSettings.get<bool>("RenderTerrainPBREnabled"))
{
view_listener_t::addMenu(new LLAdvancedRebuildTerrain(), "Advanced.RebuildTerrain");
}
//[FIX FIRE-1927 - enable DoubleClickTeleport shortcut : SJ]
view_listener_t::addMenu(new FSAdvancedToggleDoubleClickAction, "Advanced.SetDoubleClickAction");
view_listener_t::addMenu(new FSAdvancedCheckEnabledDoubleClickAction, "Advanced.CheckEnabledDoubleClickAction");

View File

@ -1190,6 +1190,11 @@ void LLViewerRegion::dirtyHeights()
}
}
void LLViewerRegion::dirtyAllPatches()
{
getLand().dirtyAllPatches();
}
//physically delete the cache entry
void LLViewerRegion::killCacheEntry(LLVOCacheEntry* entry, bool for_rendering)
{
@ -1690,7 +1695,19 @@ void LLViewerRegion::idleUpdate(F32 max_update_time)
mLastUpdate = LLViewerOctreeEntryData::getCurrentFrame();
mImpl->mLandp->idleUpdate(max_update_time);
static bool pbr_terrain_enabled = gSavedSettings.get<bool>("RenderTerrainPBREnabled");
static LLCachedControl<bool> pbr_terrain_experimental_normals(gSavedSettings, "RenderTerrainPBRNormalsEnabled", FALSE);
bool pbr_material = mImpl->mCompositionp && (mImpl->mCompositionp->getMaterialType() == LLTerrainMaterials::Type::PBR);
bool pbr_land = pbr_material && pbr_terrain_enabled && pbr_terrain_experimental_normals;
if (!pbr_land)
{
mImpl->mLandp->idleUpdate</*PBR=*/false>(max_update_time);
}
else
{
mImpl->mLandp->idleUpdate</*PBR=*/true>(max_update_time);
}
if (mParcelOverlay)
{
@ -1992,7 +2009,21 @@ LLViewerObject* LLViewerRegion::updateCacheEntry(U32 local_id, LLViewerObject* o
// As above, but forcibly do the update.
void LLViewerRegion::forceUpdate()
{
mImpl->mLandp->idleUpdate(0.f);
constexpr F32 max_update_time = 0.f;
static bool pbr_terrain_enabled = gSavedSettings.get<BOOL>("RenderTerrainPBREnabled");
static LLCachedControl<BOOL> pbr_terrain_experimental_normals(gSavedSettings, "RenderTerrainPBRNormalsEnabled", FALSE);
bool pbr_material = mImpl->mCompositionp && (mImpl->mCompositionp->getMaterialType() == LLTerrainMaterials::Type::PBR);
bool pbr_land = pbr_material && pbr_terrain_enabled && pbr_terrain_experimental_normals;
if (!pbr_land)
{
mImpl->mLandp->idleUpdate</*PBR=*/false>(max_update_time);
}
else
{
mImpl->mLandp->idleUpdate</*PBR=*/true>(max_update_time);
}
if (mParcelOverlay)
{

View File

@ -175,6 +175,9 @@ public:
// Call this whenever you change the height data in the region.
// (Automatically called by LLSurfacePatch's update routine)
void dirtyHeights();
// Call this whenever you want to force all terrain to rebuild.
// (For example, if a global terrain config option has changed)
void dirtyAllPatches();
LLViewerParcelOverlay *getParcelOverlay() const
{ return mParcelOverlay; }

View File

@ -91,6 +91,8 @@ LLGLSLShader gTwoTextureCompareProgram;
LLGLSLShader gOneTextureFilterProgram;
LLGLSLShader gDebugProgram;
LLGLSLShader gSkinnedDebugProgram;
LLGLSLShader gNormalDebugProgram[NORMAL_DEBUG_SHADER_COUNT];
LLGLSLShader gSkinnedNormalDebugProgram[NORMAL_DEBUG_SHADER_COUNT];
LLGLSLShader gClipProgram;
LLGLSLShader gAlphaMaskProgram;
LLGLSLShader gBenchmarkProgram;
@ -2727,6 +2729,33 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
success = success && gDebugProgram.createShader(NULL, NULL);
}
if (success)
{
for (S32 variant = 0; variant < NORMAL_DEBUG_SHADER_COUNT; ++variant)
{
LLGLSLShader& shader = gNormalDebugProgram[variant];
LLGLSLShader& skinned_shader = gSkinnedNormalDebugProgram[variant];
shader.mName = "Normal Debug Shader";
shader.mShaderFiles.clear();
shader.mShaderFiles.push_back(make_pair("interface/normaldebugV.glsl", GL_VERTEX_SHADER));
// *NOTE: Geometry shaders have a reputation for being slow.
// Consider using compute shaders instead, which have a reputation
// for being fast. This geometry shader in particular seems to run
// fine on my machine, but I won't vouch for this in
// performance-critical areas. -Cosmic,2023-09-28
shader.mShaderFiles.push_back(make_pair("interface/normaldebugG.glsl", GL_GEOMETRY_SHADER));
shader.mShaderFiles.push_back(make_pair("interface/normaldebugF.glsl", GL_FRAGMENT_SHADER));
shader.mRiggedVariant = &skinned_shader;
shader.mShaderLevel = mShaderLevel[SHADER_INTERFACE];
if (variant == NORMAL_DEBUG_SHADER_WITH_TANGENTS)
{
shader.addPermutation("HAS_ATTRIBUTE_TANGENT", "1");
}
success = make_rigged_variant(shader, skinned_shader);
success = success && shader.createShader(NULL, NULL);
}
}
if (success)
{
gClipProgram.mName = "Clip Shader";

View File

@ -156,6 +156,14 @@ extern LLGLSLShader gRadianceGenProgram;
extern LLGLSLShader gIrradianceGenProgram;
extern LLGLSLShader gGlowCombineFXAAProgram;
extern LLGLSLShader gDebugProgram;
enum NormalDebugShaderVariant : S32
{
NORMAL_DEBUG_SHADER_DEFAULT,
NORMAL_DEBUG_SHADER_WITH_TANGENTS,
NORMAL_DEBUG_SHADER_COUNT
};
extern LLGLSLShader gNormalDebugProgram[NORMAL_DEBUG_SHADER_COUNT];
extern LLGLSLShader gSkinnedNormalDebugProgram[NORMAL_DEBUG_SHADER_COUNT];
extern LLGLSLShader gClipProgram;
extern LLGLSLShader gBenchmarkProgram;
extern LLGLSLShader gReflectionProbeDisplayProgram;

View File

@ -214,6 +214,7 @@ BOOL LLVOSurfacePatch::updateGeometry(LLDrawable *drawable)
void LLVOSurfacePatch::updateFaceSize(S32 idx)
{
LL_PROFILE_ZONE_SCOPED;
if (idx != 0)
{
LL_WARNS() << "Terrain partition requested invalid face!!!" << LL_ENDL;

View File

@ -177,7 +177,6 @@ F32 LLPipeline::CameraFocusTransitionTime;
F32 LLPipeline::CameraFNumber;
F32 LLPipeline::CameraFocalLength;
F32 LLPipeline::CameraFieldOfView;
S32 LLPipeline::RenderLocalLightCount;
F32 LLPipeline::RenderShadowNoise;
F32 LLPipeline::RenderShadowBlurSize;
F32 LLPipeline::RenderSSAOScale;
@ -564,7 +563,6 @@ void LLPipeline::init()
connectRefreshCachedSettingsSafe("CameraFNumber");
connectRefreshCachedSettingsSafe("CameraFocalLength");
connectRefreshCachedSettingsSafe("CameraFieldOfView");
connectRefreshCachedSettingsSafe("RenderLocalLightCount");
connectRefreshCachedSettingsSafe("RenderShadowNoise");
connectRefreshCachedSettingsSafe("RenderShadowBlurSize");
connectRefreshCachedSettingsSafe("RenderSSAOScale");
@ -1125,7 +1123,6 @@ void LLPipeline::refreshCachedSettings()
CameraFNumber = gSavedSettings.getF32("CameraFNumber");
CameraFocalLength = gSavedSettings.getF32("CameraFocalLength");
CameraFieldOfView = gSavedSettings.getF32("CameraFieldOfView");
RenderLocalLightCount = gSavedSettings.getS32("RenderLocalLightCount");
RenderShadowNoise = gSavedSettings.getF32("RenderShadowNoise");
RenderShadowBlurSize = gSavedSettings.getF32("RenderShadowBlurSize");
RenderSSAOScale = gSavedSettings.getF32("RenderSSAOScale");
@ -5401,7 +5398,7 @@ void LLPipeline::calcNearbyLights(LLCamera& camera)
return;
}
const S32 local_light_count = LLPipeline::RenderLocalLightCount;
static LLCachedControl<S32> local_light_count(gSavedSettings, "RenderLocalLightCount", 256);
if (local_light_count >= 1)
{
@ -5670,7 +5667,7 @@ void LLPipeline::setupHWLights()
mLightMovingMask = 0;
const S32 local_light_count = LLPipeline::RenderLocalLightCount;
static LLCachedControl<S32> local_light_count(gSavedSettings, "RenderLocalLightCount", 256);
if (local_light_count >= 1)
{
@ -8177,7 +8174,7 @@ void LLPipeline::renderDeferredLighting()
unbindDeferredShader(gDeferredSoftenProgram);
}
const S32 local_light_count = LLPipeline::RenderLocalLightCount;
static LLCachedControl<S32> local_light_count(gSavedSettings, "RenderLocalLightCount", 256);
if (local_light_count > 0)
{
@ -8456,6 +8453,7 @@ void LLPipeline::renderDeferredLighting()
LLPipeline::RENDER_TYPE_CONTROL_AV,
LLPipeline::RENDER_TYPE_ALPHA_MASK,
LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK,
LLPipeline::RENDER_TYPE_TERRAIN,
LLPipeline::RENDER_TYPE_WATER,
END_RENDER_TYPES);
@ -11139,6 +11137,16 @@ void LLPipeline::rebuildDrawInfo()
}
}
void LLPipeline::rebuildTerrain()
{
for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
{
LLViewerRegion* region = *iter;
region->dirtyAllPatches();
}
}
// <FS:Ansariel> Reset VB during TP
void LLPipeline::initDeferredVB()
{

View File

@ -134,6 +134,8 @@ public:
// rebuild all LLVOVolume render batches
void rebuildDrawInfo();
// Rebuild all terrain
void rebuildTerrain();
// Clear LLFace mVertexBuffer pointers
void resetVertexBuffers(LLDrawable* drawable);
@ -1041,7 +1043,6 @@ public:
static F32 CameraFNumber;
static F32 CameraFocalLength;
static F32 CameraFieldOfView;
static S32 RenderLocalLightCount;
static F32 RenderShadowNoise;
static F32 RenderShadowBlurSize;
static F32 RenderSSAOScale;

View File

@ -528,6 +528,7 @@
<menu_item_check label="Angehängte Partikel rendern" name="Render Attached Particles"/>
<menu_item_check label="Shader-Cache aktivieren" name="Enable Shader Cache"/>
<menu_item_call label="Shader-Cache bereinigen" name="Shader Cache Clear"/>
<menu_item_call label="Terrain neu erstellen" name="Rebuild Terrain"/>
</menu>
<menu label="Netzwerk" name="Network">
<menu_item_check label="Agent pausieren" name="AgentPause"/>

View File

@ -4599,6 +4599,13 @@
<menu_item_call.on_click
function="Advanced.ClearShaderCache" />
</menu_item_call>
<menu_item_call
enabled="true"
label="Rebuild Terrain"
name="Rebuild Terrain">
<menu_item_call.on_click
function="Advanced.RebuildTerrain" />
</menu_item_call>
</menu>
<menu