secondlife/viewer-issues#43: Fix debug normals not rendering for terrain

meow-7.2.2
Cosmic Linden 2023-09-15 14:27:15 -07:00
parent c8547ad8a5
commit 00c65b6270
9 changed files with 375 additions and 63 deletions

View File

@ -588,11 +588,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");
@ -1453,6 +1464,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

@ -316,6 +316,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

@ -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

@ -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"
@ -2000,7 +2001,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())
@ -2008,11 +2013,13 @@ void renderNormals(LLDrawable *drawablep)
LLVertexBuffer::unbind();
LLViewerObject* obj = drawablep->getVObj();
LLVOVolume *vol = drawablep->getVOVolume();
if (vol)
if (obj)
{
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.
//
@ -2021,68 +2028,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

@ -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;
@ -2692,6 +2694,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

@ -8241,6 +8241,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);