# Conflicts:
#	indra/llcommon/llprofilercategories.h
master
Ansariel 2024-06-21 22:45:12 +02:00
commit 364a14a8aa
36 changed files with 1034 additions and 531 deletions

View File

@ -68,6 +68,7 @@
#define LL_PROFILER_CATEGORY_ENABLE_VERTEX 1
#define LL_PROFILER_CATEGORY_ENABLE_VOLUME 1
#define LL_PROFILER_CATEGORY_ENABLE_WIN32 0 // <FS:Beq/> Rationalise this silliness
#define LL_PROFILER_CATEGORY_ENABLE_GLTF 1
#define LL_PROFILER_CATEGORY_ENABLE_VOICE 1
#if LL_PROFILER_CATEGORY_ENABLE_APP
@ -288,12 +289,19 @@
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32
#endif
#if LL_PROFILER_CATEGORY_ENABLE_VOICE
#define LL_PROFILE_ZONE_NAMED_CATEGORY_VOICE LL_PROFILE_ZONE_NAMED
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE LL_PROFILE_ZONE_SCOPED
#if LL_PROFILER_CATEGORY_ENABLE_GLTF
#define LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF LL_PROFILE_ZONE_NAMED
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF LL_PROFILE_ZONE_SCOPED
#else
#define LL_PROFILE_ZONE_NAMED_CATEGORY_VOICE(name)
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE
#define LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF(name)
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF
#endif
#if LL_PROFILER_CATEGORY_ENABLE_VOICE
#define LL_PROFILE_ZONE_NAMED_CATEGORY_VOICE LL_PROFILE_ZONE_NAMED
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE LL_PROFILE_ZONE_SCOPED
#else
#define LL_PROFILE_ZONE_NAMED_CATEGORY_VOICE(name)
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE
#endif
#endif // LL_PROFILER_CATEGORIES_H

View File

@ -97,6 +97,9 @@ LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
U32 decode_id = ++mDecodeCount;
if (decode_id == 0)
decode_id = ++mDecodeCount;
// Instantiate the ImageRequest right in the lambda, why not?
bool posted = mThreadPool->getQueue().post(
[req = ImageRequest(image, discard, needs_aux, responder, decode_id)]

View File

@ -54,6 +54,8 @@ using std::string;
GLuint LLGLSLShader::sCurBoundShader = 0;
LLGLSLShader* LLGLSLShader::sCurBoundShaderPtr = NULL;
S32 LLGLSLShader::sIndexedTextureChannels = 0;
U32 LLGLSLShader::sMaxGLTFMaterials = 0;
U32 LLGLSLShader::sMaxGLTFNodes = 0;
bool LLGLSLShader::sProfileEnabled = false;
std::set<LLGLSLShader*> LLGLSLShader::sInstances;
LLGLSLShader::defines_map_t LLGLSLShader::sGlobalDefines;
@ -978,7 +980,9 @@ bool LLGLSLShader::mapUniforms()
const char* ubo_names[] =
{
"ReflectionProbes", // UB_REFLECTION_PROBES
"GLTFJoints", // UB_GLTF_JOINTS
"GLTFJoints", // UB_GLTF_JOINTS
"GLTFNodes", // UB_GLTF_NODES
"GLTFMaterials", // UB_GLTF_MATERIALS
};
llassert(LL_ARRAY_SIZE(ubo_names) == NUM_UNIFORM_BLOCKS);

View File

@ -147,8 +147,10 @@ public:
enum UniformBlock : GLuint
{
UB_REFLECTION_PROBES,
UB_GLTF_JOINTS,
UB_REFLECTION_PROBES, // "ReflectionProbes"
UB_GLTF_JOINTS, // "GLTFJoints"
UB_GLTF_NODES, // "GLTFNodes"
UB_GLTF_MATERIALS, // "GLTFMaterials"
NUM_UNIFORM_BLOCKS
};
@ -163,6 +165,9 @@ public:
static LLGLSLShader* sCurBoundShaderPtr;
static S32 sIndexedTextureChannels;
static U32 sMaxGLTFMaterials;
static U32 sMaxGLTFNodes;
static void initProfile();
static void finishProfile(bool emit_report = true);

View File

@ -1013,6 +1013,8 @@ void LLRender::syncLightState()
void LLRender::syncMatrices()
{
STOP_GLERROR;
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
static const U32 name[] =
{
LLShaderMgr::MODELVIEW_MATRIX,

View File

@ -1191,6 +1191,8 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("normal_texcoord"); // (GLTF)
mReservedUniforms.push_back("metallic_roughness_texcoord"); // (GLTF)
mReservedUniforms.push_back("occlusion_texcoord"); // (GLTF)
mReservedUniforms.push_back("gltf_node_id"); // (GLTF)
mReservedUniforms.push_back("gltf_material_id"); // (GLTF)
mReservedUniforms.push_back("terrain_texture_transforms"); // (GLTF)

View File

@ -63,6 +63,8 @@ public:
NORMAL_TEXCOORD, // "normal_texcoord" (GLTF)
METALLIC_ROUGHNESS_TEXCOORD, // "metallic_roughness_texcoord" (GLTF)
OCCLUSION_TEXCOORD, // "occlusion_texcoord" (GLTF)
GLTF_NODE_ID, // "gltf_node_id" (GLTF)
GLTF_MATERIAL_ID, // "gltf_material_id" (GLTF)
TERRAIN_TEXTURE_TRANSFORMS, // "terrain_texture_transforms" (GLTF)

View File

@ -823,6 +823,13 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
STOP_GLERROR;
}
void LLVertexBuffer::drawRangeFast(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const
{
glDrawRangeElements(sGLMode[mode], start, end, count, mIndicesType,
(GLvoid*)(indices_offset * (size_t)mIndicesStride));
}
void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
{
drawRange(mode, 0, mNumVerts-1, count, indices_offset);
@ -1079,12 +1086,6 @@ bool LLVertexBuffer::updateNumVerts(U32 nverts)
bool success = true;
if (nverts > 65536)
{
LL_WARNS() << "Vertex buffer overflow!" << LL_ENDL;
nverts = 65536;
}
U32 needed_size = calcOffsets(mTypeMask, mOffsets, nverts);
if (needed_size != mSize)
@ -1227,7 +1228,7 @@ U8* LLVertexBuffer::mapIndexBuffer(U32 index, S32 count)
// end -- last byte to copy (NOT last byte + 1)
// data -- data to be flushed
// dst -- mMappedData or mMappedIndexData
static void flush_vbo(GLenum target, U32 start, U32 end, void* data, U8* dst)
void LLVertexBuffer::flush_vbo(GLenum target, U32 start, U32 end, void* data, U8* dst)
{
#if LL_DARWIN
LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb memcpy");
@ -1235,6 +1236,8 @@ static void flush_vbo(GLenum target, U32 start, U32 end, void* data, U8* dst)
// copy into mapped buffer
memcpy(dst+start, data, end-start+1);
#else
llassert(target == GL_ARRAY_BUFFER ? sGLRenderBuffer == mGLBuffer : sGLRenderIndices == mGLIndices);
// skip mapped data and stream to GPU via glBufferSubData
if (end != 0)
{
@ -1655,81 +1658,51 @@ void LLVertexBuffer::setupVertexBuffer()
void LLVertexBuffer::setPositionData(const LLVector4a* data)
{
#if !LL_DARWIN
llassert(sGLRenderBuffer == mGLBuffer);
#endif
flush_vbo(GL_ARRAY_BUFFER, 0, sizeof(LLVector4a) * getNumVerts()-1, (U8*) data, mMappedData);
}
void LLVertexBuffer::setTexCoord0Data(const LLVector2* data)
{
#if !LL_DARWIN
llassert(sGLRenderBuffer == mGLBuffer);
#endif
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD0], mOffsets[TYPE_TEXCOORD0] + sTypeSize[TYPE_TEXCOORD0] * getNumVerts() - 1, (U8*)data, mMappedData);
}
void LLVertexBuffer::setTexCoord1Data(const LLVector2* data)
{
#if !LL_DARWIN
llassert(sGLRenderBuffer == mGLBuffer);
#endif
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD1], mOffsets[TYPE_TEXCOORD1] + sTypeSize[TYPE_TEXCOORD1] * getNumVerts() - 1, (U8*)data, mMappedData);
}
void LLVertexBuffer::setColorData(const LLColor4U* data)
{
#if !LL_DARWIN
llassert(sGLRenderBuffer == mGLBuffer);
#endif
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_COLOR], mOffsets[TYPE_COLOR] + sTypeSize[TYPE_COLOR] * getNumVerts() - 1, (U8*) data, mMappedData);
}
void LLVertexBuffer::setNormalData(const LLVector4a* data)
{
#if !LL_DARWIN
llassert(sGLRenderBuffer == mGLBuffer);
#endif
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_NORMAL], mOffsets[TYPE_NORMAL] + sTypeSize[TYPE_NORMAL] * getNumVerts() - 1, (U8*) data, mMappedData);
}
void LLVertexBuffer::setTangentData(const LLVector4a* data)
{
#if !LL_DARWIN
llassert(sGLRenderBuffer == mGLBuffer);
#endif
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TANGENT], mOffsets[TYPE_TANGENT] + sTypeSize[TYPE_TANGENT] * getNumVerts() - 1, (U8*) data, mMappedData);
}
void LLVertexBuffer::setWeight4Data(const LLVector4a* data)
{
#if !LL_DARWIN
llassert(sGLRenderBuffer == mGLBuffer);
#endif
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_WEIGHT4], mOffsets[TYPE_WEIGHT4] + sTypeSize[TYPE_WEIGHT4] * getNumVerts() - 1, (U8*) data, mMappedData);
}
void LLVertexBuffer::setJointData(const U64* data)
{
#if !LL_DARWIN
llassert(sGLRenderBuffer == mGLBuffer);
#endif
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_JOINT], mOffsets[TYPE_JOINT] + sTypeSize[TYPE_JOINT] * getNumVerts() - 1, (U8*) data, mMappedData);
}
void LLVertexBuffer::setIndexData(const U16* data)
{
#if !LL_DARWIN
llassert(sGLRenderIndices == mGLIndices);
#endif
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(U16) * getNumIndices() - 1, (U8*) data, mMappedIndexData);
}
void LLVertexBuffer::setIndexData(const U32* data)
{
#if !LL_DARWIN
llassert(sGLRenderIndices == mGLIndices);
#endif
if (mIndicesType != GL_UNSIGNED_INT)
{ // HACK -- vertex buffers are initialized as 16-bit indices, but can be switched to 32-bit indices
mIndicesType = GL_UNSIGNED_INT;
@ -1739,3 +1712,62 @@ void LLVertexBuffer::setIndexData(const U32* data)
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(U32) * getNumIndices() - 1, (U8*)data, mMappedIndexData);
}
void LLVertexBuffer::setPositionData(const LLVector4a* data, U32 offset, U32 count)
{
flush_vbo(GL_ARRAY_BUFFER, offset * sizeof(LLVector4a), (offset + count) * sizeof(LLVector4a) - 1, (U8*)data, mMappedData);
}
void LLVertexBuffer::setNormalData(const LLVector4a* data, U32 offset, U32 count)
{
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_NORMAL] + offset * sTypeSize[TYPE_NORMAL], mOffsets[TYPE_NORMAL] + (offset + count) * sTypeSize[TYPE_NORMAL] - 1, (U8*)data, mMappedData);
}
void LLVertexBuffer::setTexCoord0Data(const LLVector2* data, U32 offset, U32 count)
{
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD0] + offset * sTypeSize[TYPE_TEXCOORD0], mOffsets[TYPE_TEXCOORD0] + (offset + count) * sTypeSize[TYPE_TEXCOORD0] - 1, (U8*)data, mMappedData);
}
void LLVertexBuffer::setTexCoord1Data(const LLVector2* data, U32 offset, U32 count)
{
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD1] + offset * sTypeSize[TYPE_TEXCOORD1], mOffsets[TYPE_TEXCOORD1] + (offset + count) * sTypeSize[TYPE_TEXCOORD1] - 1, (U8*)data, mMappedData);
}
void LLVertexBuffer::setColorData(const LLColor4U* data, U32 offset, U32 count)
{
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_COLOR] + offset * sTypeSize[TYPE_COLOR], mOffsets[TYPE_COLOR] + (offset + count) * sTypeSize[TYPE_COLOR] - 1, (U8*)data, mMappedData);
}
void LLVertexBuffer::setTangentData(const LLVector4a* data, U32 offset, U32 count)
{
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TANGENT] + offset * sTypeSize[TYPE_TANGENT], mOffsets[TYPE_TANGENT] + (offset + count) * sTypeSize[TYPE_TANGENT] - 1, (U8*)data, mMappedData);
}
void LLVertexBuffer::setWeight4Data(const LLVector4a* data, U32 offset, U32 count)
{
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_WEIGHT4] + offset * sTypeSize[TYPE_WEIGHT4], mOffsets[TYPE_WEIGHT4] + (offset + count) * sTypeSize[TYPE_WEIGHT4] - 1, (U8*)data, mMappedData);
}
void LLVertexBuffer::setJointData(const U64* data, U32 offset, U32 count)
{
flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_JOINT] + offset * sTypeSize[TYPE_JOINT], mOffsets[TYPE_JOINT] + (offset + count) * sTypeSize[TYPE_JOINT] - 1, (U8*)data, mMappedData);
}
void LLVertexBuffer::setIndexData(const U16* data, U32 offset, U32 count)
{
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, offset * sizeof(U16), (offset + count) * sizeof(U16) - 1, (U8*)data, mMappedIndexData);
}
void LLVertexBuffer::setIndexData(const U32* data, U32 offset, U32 count)
{
if (mIndicesType != GL_UNSIGNED_INT)
{ // HACK -- vertex buffers are initialized as 16-bit indices, but can be switched to 32-bit indices
mIndicesType = GL_UNSIGNED_INT;
mIndicesStride = 4;
mNumIndices /= 2;
}
flush_vbo(GL_ELEMENT_ARRAY_BUFFER, offset * sizeof(U32), (offset + count) * sizeof(U32) - 1, (U8*)data, mMappedIndexData);
}

View File

@ -206,6 +206,18 @@ public:
void setIndexData(const U16* data);
void setIndexData(const U32* data);
void setPositionData(const LLVector4a* data, U32 offset, U32 count);
void setNormalData(const LLVector4a* data, U32 offset, U32 count);
void setTangentData(const LLVector4a* data, U32 offset, U32 count);
void setWeight4Data(const LLVector4a* data, U32 offset, U32 count);
void setJointData(const U64* data, U32 offset, U32 count);
void setTexCoord0Data(const LLVector2* data, U32 offset, U32 count);
void setTexCoord1Data(const LLVector2* data, U32 offset, U32 count);
void setColorData(const LLColor4U* data, U32 offset, U32 count);
void setIndexData(const U16* data, U32 offset, U32 count);
void setIndexData(const U32* data, U32 offset, U32 count);
U32 getNumVerts() const { return mNumVerts; }
U32 getNumIndices() const { return mNumIndices; }
@ -223,6 +235,10 @@ public:
void drawArrays(U32 mode, U32 offset, U32 count) const;
void drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const;
// draw without syncing matrices. If you're positive there have been no matrix
// since the last call to syncMatrices, this is much faster than drawRange
void drawRangeFast(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const;
//for debugging, validate data in given range is valid
bool validateRange(U32 start, U32 end, U32 count, U32 offset) const;
@ -260,6 +276,8 @@ private:
friend class LLNavShapeVBOManager;
friend class LLNavMeshVBOManager;
void flush_vbo(GLenum target, U32 start, U32 end, void* data, U8* dst);
LLVertexBuffer(U32 typemask, U32 usage)
: LLVertexBuffer(typemask)
{}

View File

@ -28,18 +28,40 @@
// GLTF pbrMetallicRoughness implementation
uniform int gltf_material_id;
vec3 emissiveColor = vec3(0,0,0);
float metallicFactor = 1.0;
float roughnessFactor = 1.0;
float minimum_alpha = -1.0;
layout (std140) uniform GLTFMaterials
{
// see pbrmetallicroughnessV.glsl for packing
vec4 gltf_material_data[MAX_UBO_VEC4S];
};
void unpackMaterial()
{
if (gltf_material_id > -1)
{
int idx = gltf_material_id*12;
emissiveColor = gltf_material_data[idx+10].rgb;
roughnessFactor = gltf_material_data[idx+11].g;
metallicFactor = gltf_material_data[idx+11].b;
minimum_alpha -= gltf_material_data[idx+11].a;
}
}
// ==================================
// needed by all variants
// ==================================
uniform sampler2D diffuseMap; //always in sRGB space
uniform sampler2D emissiveMap;
uniform vec3 emissiveColor;
in vec3 vary_position;
in vec4 vertex_color;
in vec2 base_color_uv;
in vec2 emissive_uv;
uniform float minimum_alpha;
void mirrorClip(vec3 pos);
vec3 linear_to_srgb(vec3 c);
@ -54,8 +76,6 @@ vec3 srgb_to_linear(vec3 c);
uniform sampler2D normalMap;
uniform sampler2D metallicRoughnessMap;
uniform sampler2D occlusionMap;
uniform float metallicFactor;
uniform float roughnessFactor;
in vec3 vary_normal;
in vec3 vary_tangent;
flat in float vary_sign;
@ -154,7 +174,7 @@ out vec4 frag_data[4];
void main()
{
unpackMaterial();
// ==================================
// all variants
// mirror clip
@ -165,6 +185,10 @@ void main()
vec3 pos = vary_position;
mirrorClip(pos);
#ifdef ALPHA_BLEND
//waterClip(pos);
#endif
vec4 basecolor = texture(diffuseMap, base_color_uv.xy).rgba;
basecolor.rgb = srgb_to_linear(basecolor.rgb);
basecolor *= vertex_color;

View File

@ -26,19 +26,95 @@
// GLTF pbrMetallicRoughness implementation
uniform mat4 modelview_matrix;
#ifdef HAS_SKIN
uniform mat4 projection_matrix;
#else
uniform mat3 normal_matrix;
uniform mat4 modelview_projection_matrix;
#ifdef MULTI_UV
in vec2 texcoord1;
int base_color_texcoord = 0;
int emissive_texcoord = 0;
#ifndef UNLIT
int normal_texcoord = 0;
int metallic_roughness_texcoord = 0;
int occlusion_texcoord = 0;
#endif
#endif
uniform vec4[2] texture_base_color_transform;
uniform vec4[2] texture_normal_transform;
uniform vec4[2] texture_metallic_roughness_transform;
uniform vec4[2] texture_emissive_transform;
uniform vec4[2] texture_occlusion_transform;
uniform int gltf_material_id;
layout (std140) uniform GLTFMaterials
{
// index by gltf_material_id*12
// [gltf_material_id + [0-1]] - base color transform
// [gltf_material_id + [2-3]] - normal transform
// [gltf_material_id + [4-5]] - metallic roughness transform
// [gltf_material_id + [6-7]] - emissive transform
// [gltf_material_id + [8-9]] - occlusion transform
// [gltf_material_id + 10] - emissive factor
// [gltf_material_id + 11] - .r unused, .g roughness, .b metalness, .a minimum alpha
// Transforms are packed as follows
// packed[0] = vec4(scale.x, scale.y, rotation, offset.x)
// packed[1] = vec4(mScale.y, texcoord, 0, 0)
vec4 gltf_material_data[MAX_UBO_VEC4S];
};
vec4[2] texture_base_color_transform;
vec4[2] texture_normal_transform;
vec4[2] texture_metallic_roughness_transform;
vec4[2] texture_emissive_transform;
vec4[2] texture_occlusion_transform;
void unpackTextureTransforms()
{
if (gltf_material_id != -1)
{
int idx = gltf_material_id*12;
texture_base_color_transform[0] = gltf_material_data[idx+0];
texture_base_color_transform[1] = gltf_material_data[idx+1];
texture_normal_transform[0] = gltf_material_data[idx+2];
texture_normal_transform[1] = gltf_material_data[idx+3];
texture_metallic_roughness_transform[0] = gltf_material_data[idx+4];
texture_metallic_roughness_transform[1] = gltf_material_data[idx+5];
texture_emissive_transform[0] = gltf_material_data[idx+6];
texture_emissive_transform[1] = gltf_material_data[idx+7];
texture_occlusion_transform[0] = gltf_material_data[idx+8];
texture_occlusion_transform[1] = gltf_material_data[idx+9];
#ifdef MULTI_UV
base_color_texcoord = int(gltf_material_data[idx+1].g);
emissive_texcoord = int(gltf_material_data[idx+7].g);
#ifndef UNLIT
normal_texcoord = int(gltf_material_data[idx+3].g);
metallic_roughness_texcoord = int(gltf_material_data[idx+5].g);
occlusion_texcoord = int(gltf_material_data[idx+9].g);
#endif
#endif
}
else
{
texture_base_color_transform[0] = vec4(1.0, 1.0, 0.0, 0.0);
texture_base_color_transform[1] = vec4(0.0, 0.0, 0.0, 0.0);
texture_normal_transform[0] = vec4(1.0, 1.0, 0.0, 0.0);
texture_normal_transform[1] = vec4(0.0, 0.0, 0.0, 0.0);
texture_metallic_roughness_transform[0] = vec4(1.0, 1.0, 0.0, 0.0);
texture_metallic_roughness_transform[1] = vec4(0.0, 0.0, 0.0, 0.0);
texture_emissive_transform[0] = vec4(1.0, 1.0, 0.0, 0.0);
texture_emissive_transform[1] = vec4(0.0, 0.0, 0.0, 0.0);
texture_occlusion_transform[0] = vec4(1.0, 1.0, 0.0, 0.0);
texture_occlusion_transform[1] = vec4(0.0, 0.0, 0.0, 0.0);
}
}
in vec3 position;
in vec4 diffuse_color;
@ -59,17 +135,6 @@ flat out float vary_sign;
out vec3 vary_normal;
#endif
#ifdef MULTI_UV
in vec2 texcoord1;
uniform int base_color_texcoord;
uniform int emissive_texcoord;
#ifndef UNLIT
uniform int normal_texcoord;
uniform int metallic_roughness_texcoord;
uniform int occlusion_texcoord;
#endif
#endif
vec2 gltf_texture_transform(vec2 texcoord, vec4[2] p)
{
texcoord.y = 1.0 - texcoord.y;
@ -124,23 +189,22 @@ vec3 gltf_tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[
}
#endif
#ifdef ALPHA_BLEND
out vec3 vary_fragcoord;
#endif
#ifdef HAS_SKIN
in uvec4 joint;
in vec4 weight4;
layout (std140) uniform GLTFJoints
{
// list of OBBs for user override probes
mat3x4 gltf_joints[MAX_JOINTS_PER_GLTF_OBJECT];
mat3x4 gltf_joints[MAX_NODES_PER_GLTF_OBJECT];
};
mat4 getGLTFSkinTransform()
in uvec4 joint;
in vec4 weight4;
mat4 getGLTFTransform()
{
int i;
@ -169,21 +233,37 @@ mat4 getGLTFSkinTransform()
ret[3] = vec4(trans, 1.0);
return ret;
}
#ifdef IS_AMD_CARD
// If it's AMD make sure the GLSL compiler sees the arrays referenced once by static index. Otherwise it seems to optimise the storage awawy which leads to unfun crashes and artifacts.
mat3x4 dummy1 = gltf_joints[0];
mat3x4 dummy2 = gltf_joints[MAX_JOINTS_PER_GLTF_OBJECT-1];
#endif
#else
layout (std140) uniform GLTFNodes
{
mat3x4 gltf_nodes[MAX_NODES_PER_GLTF_OBJECT];
};
uniform int gltf_node_id = 0;
mat4 getGLTFTransform()
{
mat4 ret;
mat3x4 src = gltf_nodes[gltf_node_id];
ret[0] = vec4(src[0].xyz, 0);
ret[1] = vec4(src[1].xyz, 0);
ret[2] = vec4(src[2].xyz, 0);
ret[3] = vec4(src[0].w, src[1].w, src[2].w, 1);
return ret;
}
#endif
void main()
{
#ifdef HAS_SKIN
mat4 mat = getGLTFSkinTransform();
unpackTextureTransforms();
mat4 mat = getGLTFTransform();
mat = modelview_matrix * mat;
@ -193,13 +273,6 @@ void main()
vec4 vert = projection_matrix * vec4(pos, 1.0);
gl_Position = vert;
#else
vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz;
//transform vertex
vec4 vert = modelview_projection_matrix * vec4(position.xyz, 1.0);
gl_Position = vert;
#endif
vec2 bcuv;
vec2 emuv;
@ -237,13 +310,8 @@ void main()
#endif
#ifndef UNLIT
#ifdef HAS_SKIN
vec3 n = (mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz;
vec3 t = (mat*vec4(tangent.xyz+position.xyz,1.0)).xyz-pos.xyz;
#else //HAS_SKIN
vec3 n = normal_matrix * normal;
vec3 t = normal_matrix * tangent.xyz;
#endif
n = normalize(n);
vary_tangent = normalize(gltf_tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform));

View File

@ -111,7 +111,7 @@ RenderReflectionProbeLevel 1 0
RenderMirrors 1 0
RenderHeroProbeResolution 1 256
RenderHeroProbeDistance 1 4
RenderHeroProbeUpdateRate 1 4
RenderHeroProbeUpdateRate 1 6
RenderHeroProbeConservativeUpdateMultiplier 1 16
//

View File

@ -109,7 +109,7 @@ RenderReflectionProbeLevel 1 0
RenderMirrors 1 0
RenderHeroProbeResolution 1 256
RenderHeroProbeDistance 1 4
RenderHeroProbeUpdateRate 1 4
RenderHeroProbeUpdateRate 1 6
RenderHeroProbeConservativeUpdateMultiplier 1 16
//

View File

@ -70,6 +70,14 @@ bool Animation::prep(Asset& asset)
}
}
for (auto& channel : mScaleChannels)
{
if (!channel.prep(asset, mSamplers[channel.mSampler]))
{
return false;
}
}
return true;
}
@ -82,18 +90,37 @@ void Animation::update(Asset& asset, F32 dt)
void Animation::apply(Asset& asset, float time)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF;
// convert time to animation loop time
time = fmod(time, mMaxTime - mMinTime) + mMinTime;
// apply each channel
for (auto& channel : mRotationChannels)
{
channel.apply(asset, mSamplers[channel.mSampler], time);
LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("gltfanim - rotation");
for (auto& channel : mRotationChannels)
{
channel.apply(asset, mSamplers[channel.mSampler], time);
}
}
for (auto& channel : mTranslationChannels)
{
channel.apply(asset, mSamplers[channel.mSampler], time);
LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("gltfanim - translation");
for (auto& channel : mTranslationChannels)
{
channel.apply(asset, mSamplers[channel.mSampler], time);
}
}
{
LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("gltfanim - scale");
for (auto& channel : mScaleChannels)
{
channel.apply(asset, mSamplers[channel.mSampler], time);
}
}
};
@ -178,7 +205,8 @@ const Animation::Channel& Animation::Channel::operator=(const Value& src)
void Animation::Sampler::getFrameInfo(Asset& asset, F32 time, U32& frameIndex, F32& t)
{
LL_PROFILE_ZONE_SCOPED;
LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF;
llassert(mFrameTimes.size() > 1); // if there is only one frame, there is no need to interpolate
if (time < mMinTime)
{
@ -187,31 +215,32 @@ void Animation::Sampler::getFrameInfo(Asset& asset, F32 time, U32& frameIndex, F
return;
}
if (mFrameTimes.size() > 1)
{
llassert(mFrameTimes.size() <= size_t(U32_MAX));
frameIndex = U32(mFrameTimes.size()) - 2;
t = 1.f;
frameIndex = U32(mFrameTimes.size()) - 2;
t = 1.f;
if (time > mMaxTime)
if (time > mMaxTime)
{
return;
}
if (time < mLastFrameTime)
{
mLastFrameIndex = 0;
}
mLastFrameTime = time;
U32 idx = mLastFrameIndex;
for (U32 i = idx; i < (U32)mFrameTimes.size() - 1; i++)
{
if (time >= mFrameTimes[i] && time < mFrameTimes[i + 1])
{
frameIndex = i;
t = (time - mFrameTimes[i]) / (mFrameTimes[i + 1] - mFrameTimes[i]);
mLastFrameIndex = frameIndex;
return;
}
for (U32 i = 0; i < (U32)mFrameTimes.size() - 1; i++)
{
if (time >= mFrameTimes[i] && time < mFrameTimes[i + 1])
{
frameIndex = i;
t = (time - mFrameTimes[i]) / (mFrameTimes[i + 1] - mFrameTimes[i]);
return;
}
}
}
else
{
frameIndex = 0;
t = 0.0f;
}
}
@ -231,14 +260,14 @@ void Animation::RotationChannel::apply(Asset& asset, Sampler& sampler, F32 time)
Node& node = asset.mNodes[mTarget.mNode];
sampler.getFrameInfo(asset, time, frameIndex, t);
if (sampler.mFrameTimes.size() == 1)
if (sampler.mFrameTimes.size() < 2)
{
node.setRotation(mRotations[0]);
}
else
{
sampler.getFrameInfo(asset, time, frameIndex, t);
// interpolate
quat qf = glm::slerp(mRotations[frameIndex], mRotations[frameIndex + 1], t);
@ -264,14 +293,14 @@ void Animation::TranslationChannel::apply(Asset& asset, Sampler& sampler, F32 ti
Node& node = asset.mNodes[mTarget.mNode];
sampler.getFrameInfo(asset, time, frameIndex, t);
if (sampler.mFrameTimes.size() == 1)
if (sampler.mFrameTimes.size() < 2)
{
node.setTranslation(mTranslations[0]);
}
else
{
sampler.getFrameInfo(asset, time, frameIndex, t);
// interpolate
const vec3& v0 = mTranslations[frameIndex];
const vec3& v1 = mTranslations[frameIndex + 1];
@ -298,14 +327,14 @@ void Animation::ScaleChannel::apply(Asset& asset, Sampler& sampler, F32 time)
Node& node = asset.mNodes[mTarget.mNode];
sampler.getFrameInfo(asset, time, frameIndex, t);
if (sampler.mFrameTimes.size() == 1)
if (sampler.mFrameTimes.size() < 2)
{
node.setScale(mScales[0]);
}
else
{
sampler.getFrameInfo(asset, time, frameIndex, t);
// interpolate
const vec3& v0 = mScales[frameIndex];
const vec3& v1 = mScales[frameIndex + 1];
@ -373,6 +402,7 @@ Skin::~Skin()
void Skin::uploadMatrixPalette(Asset& asset)
{
// prepare matrix palette
LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF;
U32 max_joints = LLSkinningUtil::getMaxGLTFJointCount();

View File

@ -49,6 +49,9 @@ namespace LL
S32 mOutput = INVALID_INDEX;
std::string mInterpolation;
F32 mLastFrameTime = 0.f;
U32 mLastFrameIndex = 0;
bool prep(Asset& asset);
void serialize(boost::json::object& dst) const;

View File

@ -35,6 +35,7 @@
#include "buffer_util.h"
#include <boost/url.hpp>
#include "llimagejpeg.h"
#include "../llskinningutil.h"
using namespace LL::GLTF;
using namespace boost::json;
@ -86,7 +87,6 @@ namespace LL
}
}
void Scene::updateTransforms(Asset& asset)
{
mat4 identity = glm::identity<mat4>();
@ -98,26 +98,6 @@ void Scene::updateTransforms(Asset& asset)
}
}
void Scene::updateRenderTransforms(Asset& asset, const mat4& modelview)
{
for (auto& nodeIndex : mNodes)
{
Node& node = asset.mNodes[nodeIndex];
node.updateRenderTransforms(asset, modelview);
}
}
void Node::updateRenderTransforms(Asset& asset, const mat4& modelview)
{
mRenderMatrix = modelview * mMatrix;
for (auto& childIndex : mChildren)
{
Node& child = asset.mNodes[childIndex];
child.updateRenderTransforms(asset, mRenderMatrix);
}
}
void Node::updateTransforms(Asset& asset, const mat4& parentMatrix)
{
makeMatrixValid();
@ -137,19 +117,119 @@ void Node::updateTransforms(Asset& asset, const mat4& parentMatrix)
void Asset::updateTransforms()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF;
for (auto& scene : mScenes)
{
scene.updateTransforms(*this);
}
uploadTransforms();
}
void Asset::updateRenderTransforms(const mat4& modelview)
void Asset::uploadTransforms()
{
// use mAssetMatrix to update render transforms from node list
for (auto& node : mNodes)
LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF;
// prepare matrix palette
U32 max_nodes = LLSkinningUtil::getMaxGLTFJointCount();
size_t node_count = llmin<size_t>(max_nodes, mNodes.size());
std::vector<mat4> t_mp;
t_mp.resize(node_count);
for (U32 i = 0; i < node_count; ++i)
{
node.mRenderMatrix = modelview * node.mAssetMatrix;
Node& node = mNodes[i];
// build matrix palette in asset space
t_mp[i] = node.mAssetMatrix;
}
std::vector<F32> glmp;
glmp.resize(node_count * 12);
F32* mp = glmp.data();
for (U32 i = 0; i < node_count; ++i)
{
F32* m = glm::value_ptr(t_mp[i]);
U32 idx = i * 12;
mp[idx + 0] = m[0];
mp[idx + 1] = m[1];
mp[idx + 2] = m[2];
mp[idx + 3] = m[12];
mp[idx + 4] = m[4];
mp[idx + 5] = m[5];
mp[idx + 6] = m[6];
mp[idx + 7] = m[13];
mp[idx + 8] = m[8];
mp[idx + 9] = m[9];
mp[idx + 10] = m[10];
mp[idx + 11] = m[14];
}
if (mNodesUBO == 0)
{
glGenBuffers(1, &mNodesUBO);
}
glBindBuffer(GL_UNIFORM_BUFFER, mNodesUBO);
glBufferData(GL_UNIFORM_BUFFER, glmp.size() * sizeof(F32), glmp.data(), GL_STREAM_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
void Asset::uploadMaterials()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF;
// see pbrmetallicroughnessV.glsl for the layout of the material UBO
std::vector<vec4> md;
U32 material_size = sizeof(vec4) * 12;
U32 max_materials = gGLManager.mMaxUniformBlockSize / material_size;
U32 mat_count = (U32)mMaterials.size();
mat_count = llmin(mat_count, max_materials);
md.resize(mat_count * 12);
for (U32 i = 0; i < mat_count*12; i += 12)
{
Material& material = mMaterials[i/12];
// add texture transforms and UV indices
material.mPbrMetallicRoughness.mBaseColorTexture.mTextureTransform.getPacked(&md[i+0]);
md[i + 1].g = (F32)material.mPbrMetallicRoughness.mBaseColorTexture.getTexCoord();
material.mNormalTexture.mTextureTransform.getPacked(&md[i + 2]);
md[i + 3].g = (F32)material.mNormalTexture.getTexCoord();
material.mPbrMetallicRoughness.mMetallicRoughnessTexture.mTextureTransform.getPacked(&md[i+4]);
md[i + 5].g = (F32)material.mPbrMetallicRoughness.mMetallicRoughnessTexture.getTexCoord();
material.mEmissiveTexture.mTextureTransform.getPacked(&md[i + 6]);
md[i + 7].g = (F32)material.mEmissiveTexture.getTexCoord();
material.mOcclusionTexture.mTextureTransform.getPacked(&md[i + 8]);
md[i + 9].g = (F32)material.mOcclusionTexture.getTexCoord();
// add material properties
F32 min_alpha = material.mAlphaMode == Material::AlphaMode::MASK ? material.mAlphaCutoff : -1.0f;
md[i + 10] = vec4(material.mEmissiveFactor, 1.f);
md[i + 11] = vec4(0.f,
material.mPbrMetallicRoughness.mRoughnessFactor,
material.mPbrMetallicRoughness.mMetallicFactor,
min_alpha);
}
if (mMaterialsUBO == 0)
{
glGenBuffers(1, &mMaterialsUBO);
}
glBindBuffer(GL_UNIFORM_BUFFER, mMaterialsUBO);
glBufferData(GL_UNIFORM_BUFFER, md.size() * sizeof(vec4), md.data(), GL_STREAM_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
S32 Asset::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
@ -363,6 +443,7 @@ const Image& Image::operator=(const Value& src)
void Asset::update()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF;
F32 dt = gFrameTimeSeconds - mLastUpdateTime;
if (dt > 0.f)
@ -383,11 +464,27 @@ void Asset::update()
{
skin.uploadMatrixPalette(*this);
}
uploadMaterials();
{
LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("gltf - addTextureStats");
for (auto& image : mImages)
{
if (image.mTexture.notNull())
{ // HACK - force texture to be loaded full rez
// TODO: calculate actual vsize
image.mTexture->addTextureStats(2048.f * 2048.f);
}
}
}
}
}
bool Asset::prep()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF;
// check required extensions and fail if not supported
bool unsupported = false;
for (auto& extension : mExtensionsRequired)
@ -445,6 +542,127 @@ bool Asset::prep()
}
}
// prepare vertex buffers
// material count is number of materials + 1 for default material
U32 mat_count = (U32) mMaterials.size() + 1;
if (LLGLSLShader::sCurBoundShaderPtr == nullptr)
{ // make sure a shader is bound to satisfy mVertexBuffer->setBuffer
gDebugProgram.bind();
}
for (S32 double_sided = 0; double_sided < 2; ++double_sided)
{
RenderData& rd = mRenderData[double_sided];
for (U32 i = 0; i < LLGLSLShader::NUM_GLTF_VARIANTS; ++i)
{
rd.mBatches[i].resize(mat_count);
}
// for each material
for (S32 mat_id = -1; mat_id < (S32)mMaterials.size(); ++mat_id)
{
// for each shader variant
U32 vertex_count[LLGLSLShader::NUM_GLTF_VARIANTS] = { 0 };
U32 index_count[LLGLSLShader::NUM_GLTF_VARIANTS] = { 0 };
S32 ds_mat = mat_id == -1 ? 0 : mMaterials[mat_id].mDoubleSided;
if (ds_mat != double_sided)
{
continue;
}
for (U32 variant = 0; variant < LLGLSLShader::NUM_GLTF_VARIANTS; ++variant)
{
U32 attribute_mask = 0;
// for each mesh
for (auto& mesh : mMeshes)
{
// for each primitive
for (auto& primitive : mesh.mPrimitives)
{
if (primitive.mMaterial == mat_id && primitive.mShaderVariant == variant)
{
// accumulate vertex and index counts
primitive.mVertexOffset = vertex_count[variant];
primitive.mIndexOffset = index_count[variant];
vertex_count[variant] += primitive.getVertexCount();
index_count[variant] += primitive.getIndexCount();
// all primitives of a given variant and material should all have the same attribute mask
llassert(attribute_mask == 0 || primitive.mAttributeMask == attribute_mask);
attribute_mask |= primitive.mAttributeMask;
}
}
}
// allocate vertex buffer and pack it
if (vertex_count[variant] > 0)
{
U32 mat_idx = mat_id + 1;
LLVertexBuffer* vb = new LLVertexBuffer(attribute_mask);
rd.mBatches[variant][mat_idx].mVertexBuffer = vb;
vb->allocateBuffer(vertex_count[variant],
index_count[variant] * 2); // hack double index count... TODO: find a better way to indicate 32-bit indices will be used
vb->setBuffer();
for (auto& mesh : mMeshes)
{
for (auto& primitive : mesh.mPrimitives)
{
if (primitive.mMaterial == mat_id && primitive.mShaderVariant == variant)
{
primitive.upload(vb);
}
}
}
vb->unmapBuffer();
vb->unbind();
}
}
}
}
// sanity check that all primitives have a vertex buffer
for (auto& mesh : mMeshes)
{
for (auto& primitive : mesh.mPrimitives)
{
llassert(primitive.mVertexBuffer.notNull());
}
}
// build render batches
for (S32 node_id = 0; node_id < mNodes.size(); ++node_id)
{
Node& node = mNodes[node_id];
if (node.mMesh != INVALID_INDEX)
{
auto& mesh = mMeshes[node.mMesh];
S32 mat_idx = mesh.mPrimitives[0].mMaterial + 1;
S32 double_sided = mat_idx == 0 ? 0 : mMaterials[mat_idx - 1].mDoubleSided;
for (S32 j = 0; j < mesh.mPrimitives.size(); ++j)
{
auto& primitive = mesh.mPrimitives[j];
S32 variant = primitive.mShaderVariant;
RenderData& rd = mRenderData[double_sided];
RenderBatch& rb = rd.mBatches[variant][mat_idx];
rb.mPrimitives.push_back({ j, node_id });
}
}
}
return true;
}
@ -455,6 +673,7 @@ Asset::Asset(const Value& src)
bool Asset::load(std::string_view filename)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF;
mFilename = filename;
std::string ext = gDirUtilp->getExtension(mFilename);
@ -903,14 +1122,14 @@ bool Image::save(Asset& asset, const std::string& folder)
return true;
}
void Material::TextureInfo::serialize(object& dst) const
void TextureInfo::serialize(object& dst) const
{
write(mIndex, "index", dst, INVALID_INDEX);
write(mTexCoord, "texCoord", dst, 0);
write_extensions(dst, &mTextureTransform, "KHR_texture_transform");
}
S32 Material::TextureInfo::getTexCoord() const
S32 TextureInfo::getTexCoord() const
{
if (mTextureTransform.mPresent && mTextureTransform.mTexCoord != INVALID_INDEX)
{
@ -928,7 +1147,7 @@ bool Material::isMultiUV() const
mEmissiveTexture.getTexCoord() != 0;
}
const Material::TextureInfo& Material::TextureInfo::operator=(const Value& src)
const TextureInfo& TextureInfo::operator=(const Value& src)
{
if (src.is_object())
{
@ -940,23 +1159,23 @@ const Material::TextureInfo& Material::TextureInfo::operator=(const Value& src)
return *this;
}
bool Material::TextureInfo::operator==(const Material::TextureInfo& rhs) const
bool TextureInfo::operator==(const TextureInfo& rhs) const
{
return mIndex == rhs.mIndex && mTexCoord == rhs.mTexCoord;
}
bool Material::TextureInfo::operator!=(const Material::TextureInfo& rhs) const
bool TextureInfo::operator!=(const TextureInfo& rhs) const
{
return !(*this == rhs);
}
void Material::OcclusionTextureInfo::serialize(object& dst) const
void OcclusionTextureInfo::serialize(object& dst) const
{
TextureInfo::serialize(dst);
write(mStrength, "strength", dst, 1.f);
}
const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=(const Value& src)
const OcclusionTextureInfo& OcclusionTextureInfo::operator=(const Value& src)
{
TextureInfo::operator=(src);
@ -968,13 +1187,13 @@ const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=(
return *this;
}
void Material::NormalTextureInfo::serialize(object& dst) const
void NormalTextureInfo::serialize(object& dst) const
{
TextureInfo::serialize(dst);
write(mScale, "scale", dst, 1.f);
}
const Material::NormalTextureInfo& Material::NormalTextureInfo::operator=(const Value& src)
const NormalTextureInfo& NormalTextureInfo::operator=(const Value& src)
{
TextureInfo::operator=(src);
if (src.is_object())
@ -1035,18 +1254,12 @@ void Material::Unlit::serialize(object& dst) const
// no members and object has already been created, nothing to do
}
void TextureTransform::getPacked(F32* packed) const
void TextureTransform::getPacked(vec4* packed) const
{
packed[0] = mScale.x;
packed[1] = mScale.y;
packed[2] = mRotation;
packed[3] = mOffset.x;
packed[4] = mOffset.y;
packed[5] = packed[6] = packed[7] = 0.f;
packed[0] = vec4(mScale.x, mScale.y, mRotation, mOffset.x);
packed[1] = vec4(mOffset.y, 0.f, 0.f, 0.f);
}
const TextureTransform& TextureTransform::operator=(const Value& src)
{
mPresent = true;

View File

@ -34,6 +34,7 @@
#include "boost/json.hpp"
#include "common.h"
#include "../llviewertexture.h"
#include "llglslshader.h"
extern F32SecondsImplicit gFrameTimeSeconds;
@ -65,14 +66,51 @@ namespace LL
vec2 mScale = vec2(1.f, 1.f);
S32 mTexCoord = INVALID_INDEX;
// get the texture transform as a packed array of floats
// dst MUST point to at least 8 floats
void getPacked(F32* dst) const;
// get the texture transform as a packed array of vec4's
// dst MUST point to at least 2 vec4's
void getPacked(vec4* dst) const;
const TextureTransform& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
};
class TextureInfo
{
public:
S32 mIndex = INVALID_INDEX;
S32 mTexCoord = 0;
TextureTransform mTextureTransform;
bool operator==(const TextureInfo& rhs) const;
bool operator!=(const TextureInfo& rhs) const;
// get the UV channel that should be used for sampling this texture
// returns mTextureTransform.mTexCoord if present and valid, otherwise mTexCoord
S32 getTexCoord() const;
const TextureInfo& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
};
class NormalTextureInfo : public TextureInfo
{
public:
F32 mScale = 1.0f;
const NormalTextureInfo& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
};
class OcclusionTextureInfo : public TextureInfo
{
public:
F32 mStrength = 1.0f;
const OcclusionTextureInfo& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
};
class Material
{
public:
@ -91,42 +129,6 @@ namespace LL
BLEND
};
class TextureInfo
{
public:
S32 mIndex = INVALID_INDEX;
S32 mTexCoord = 0;
TextureTransform mTextureTransform;
bool operator==(const TextureInfo& rhs) const;
bool operator!=(const TextureInfo& rhs) const;
// get the UV channel that should be used for sampling this texture
// returns mTextureTransform.mTexCoord if present and valid, otherwise mTexCoord
S32 getTexCoord() const;
const TextureInfo& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
};
class NormalTextureInfo : public TextureInfo
{
public:
F32 mScale = 1.0f;
const NormalTextureInfo& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
};
class OcclusionTextureInfo : public TextureInfo
{
public:
F32 mStrength = 1.0f;
const OcclusionTextureInfo& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
};
class PbrMetallicRoughness
{
@ -179,7 +181,6 @@ namespace LL
{
public:
mat4 mMatrix = glm::identity<mat4>(); //local transform
mat4 mRenderMatrix; //transform for rendering
mat4 mAssetMatrix; //transform from local to asset space
mat4 mAssetMatrixInv; //transform from asset to local space
@ -206,10 +207,6 @@ namespace LL
const Node& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
// Set mRenderMatrix to a transform that can be used for the current render pass
// modelview -- parent's render matrix
void updateRenderTransforms(Asset& asset, const mat4& modelview);
// update mAssetMatrix and mAssetMatrixInv
void updateTransforms(Asset& asset, const mat4& parentMatrix);
@ -322,6 +319,31 @@ namespace LL
bool prep(Asset& asset);
};
// Render Batch -- vertex buffer and list of primitives to render using
// said vertex buffer
class RenderBatch
{
public:
struct PrimitiveData
{
S32 mPrimitiveIndex = INVALID_INDEX;
S32 mNodeIndex = INVALID_INDEX;
};
LLPointer<LLVertexBuffer> mVertexBuffer;
std::vector<PrimitiveData> mPrimitives;
};
class RenderData
{
public:
// list of render batches
// indexed by [material index + 1](0 is reserved for default material)
// there should be exactly one render batch per material per variant
std::vector<RenderBatch> mBatches[LLGLSLShader::NUM_GLTF_VARIANTS];
};
// C++ representation of a GLTF Asset
class Asset
{
@ -359,6 +381,16 @@ namespace LL
// the last time update() was called according to gFrameTimeSeconds
F32 mLastUpdateTime = gFrameTimeSeconds;
// data used for rendering
// 0 - single sided
// 1 - double sided
RenderData mRenderData[2];
// UBO for storing node transforms
U32 mNodesUBO = 0;
// UBO for storing material data
U32 mMaterialsUBO = 0;
// prepare for first time use
bool prep();
@ -373,8 +405,11 @@ namespace LL
// update asset-to-node and node-to-asset transforms
void updateTransforms();
// update node render transforms
void updateRenderTransforms(const mat4& modelview);
// upload matrices to UBO
void uploadTransforms();
// upload materils to UBO
void uploadMaterials();
// return the index of the node that the line segment intersects with, or -1 if no hit
// input and output values must be in this asset's local coordinate frame

View File

@ -64,6 +64,9 @@ namespace LL
class Asset;
class Material;
class TextureInfo;
class NormalTextureInfo;
class OcclusionTextureInfo;
class Mesh;
class Node;
class Scene;
@ -78,6 +81,17 @@ namespace LL
class Accessor;
class BufferView;
class Buffer;
enum class TextureType : U8
{
BASE_COLOR = 0,
NORMAL,
METALLIC_ROUGHNESS,
OCCLUSION,
EMISSIVE
};
constexpr U32 TEXTURE_TYPE_COUNT = 5;
}
}

View File

@ -380,11 +380,22 @@ bool Primitive::prep(Asset& asset)
}
}
}
else
{ //everything must be indexed at runtime
mIndexArray.resize(mPositions.size());
for (U32 i = 0; i < mPositions.size(); ++i)
{
mIndexArray[i] = i;
}
}
U32 mask = LLVertexBuffer::MAP_VERTEX;
mShaderVariant = 0;
if (!mWeights.empty())
{
mShaderVariant |= LLGLSLShader::GLTFVariant::RIGGED;
mask |= LLVertexBuffer::MAP_WEIGHT4;
mask |= LLVertexBuffer::MAP_JOINT;
}
@ -406,9 +417,6 @@ bool Primitive::prep(Asset& asset)
mColors.resize(mPositions.size(), LLColor4U::white);
}
mShaderVariant = 0;
// TODO: support colorless vertex buffers
mask |= LLVertexBuffer::MAP_COLOR;
bool unlit = false;
@ -506,58 +514,7 @@ bool Primitive::prep(Asset& asset)
mask |= LLVertexBuffer::MAP_TANGENT;
}
if (LLGLSLShader::sCurBoundShaderPtr == nullptr)
{ // make sure a shader is bound to satisfy mVertexBuffer->setBuffer
gDebugProgram.bind();
}
mVertexBuffer = new LLVertexBuffer(mask);
// we store these buffer sizes as S32 elsewhere
llassert(mPositions.size() <= size_t(S32_MAX));
llassert(mIndexArray.size() <= size_t(S32_MAX / 2));
mVertexBuffer->allocateBuffer(U32(mPositions.size()), U32(mIndexArray.size() * 2)); // double the size of the index buffer for 32-bit indices
mVertexBuffer->setBuffer();
mVertexBuffer->setPositionData(mPositions.data());
mVertexBuffer->setColorData(mColors.data());
if (!mNormals.empty())
{
mVertexBuffer->setNormalData(mNormals.data());
}
if (!mTangents.empty())
{
mVertexBuffer->setTangentData(mTangents.data());
}
if (!mWeights.empty())
{
mShaderVariant |= LLGLSLShader::GLTFVariant::RIGGED;
mVertexBuffer->setWeight4Data(mWeights.data());
mVertexBuffer->setJointData(mJoints.data());
}
// flip texcoord y, upload, then flip back (keep the off-spec data in vram only)
vertical_flip(mTexCoords0);
mVertexBuffer->setTexCoord0Data(mTexCoords0.data());
vertical_flip(mTexCoords0);
if (!mTexCoords1.empty())
{
vertical_flip(mTexCoords1);
mVertexBuffer->setTexCoord1Data(mTexCoords1.data());
vertical_flip(mTexCoords1);
}
if (!mIndexArray.empty())
{
mVertexBuffer->setIndexData(mIndexArray.data());
}
createOctree();
mVertexBuffer->unbind();
mAttributeMask = mask;
if (mMaterial != INVALID_INDEX)
{
@ -568,9 +525,70 @@ bool Primitive::prep(Asset& asset)
}
}
createOctree();
return true;
}
void Primitive::upload(LLVertexBuffer* buffer)
{
mVertexBuffer = buffer;
// we store these buffer sizes as S32 elsewhere
llassert(mPositions.size() <= size_t(S32_MAX));
llassert(mIndexArray.size() <= size_t(S32_MAX / 2));
llassert(mVertexBuffer != nullptr);
// assert that buffer can hold this primitive
llassert(mVertexBuffer->getNumVerts() >= mPositions.size() + mVertexOffset);
llassert(mVertexBuffer->getNumIndices() >= mIndexArray.size() + mIndexOffset);
llassert(mVertexBuffer->getTypeMask() == mAttributeMask);
U32 offset = mVertexOffset;
U32 count = getVertexCount();
mVertexBuffer->setPositionData(mPositions.data(), offset, count);
mVertexBuffer->setColorData(mColors.data(), offset, count);
if (!mNormals.empty())
{
mVertexBuffer->setNormalData(mNormals.data(), offset, count);
}
if (!mTangents.empty())
{
mVertexBuffer->setTangentData(mTangents.data(), offset, count);
}
if (!mWeights.empty())
{
mVertexBuffer->setWeight4Data(mWeights.data(), offset, count);
mVertexBuffer->setJointData(mJoints.data(), offset, count);
}
// flip texcoord y, upload, then flip back (keep the off-spec data in vram only)
vertical_flip(mTexCoords0);
mVertexBuffer->setTexCoord0Data(mTexCoords0.data(), offset, count);
vertical_flip(mTexCoords0);
if (!mTexCoords1.empty())
{
vertical_flip(mTexCoords1);
mVertexBuffer->setTexCoord1Data(mTexCoords1.data(), offset, count);
vertical_flip(mTexCoords1);
}
if (!mIndexArray.empty())
{
std::vector<U32> index_array;
index_array.resize(mIndexArray.size());
for (U32 i = 0; i < mIndexArray.size(); ++i)
{
index_array[i] = mIndexArray[i] + mVertexOffset;
}
mVertexBuffer->setIndexData(index_array.data(), mIndexOffset, getIndexCount());
}
}
void initOctreeTriangle(LLVolumeTriangle* tri, F32 scaler, S32 i0, S32 i1, S32 i2, const LLVector4a& v0, const LLVector4a& v1, const LLVector4a& v2)
{
//store pointers to vertex data
@ -616,7 +634,7 @@ void Primitive::createOctree()
if (mMode == Mode::TRIANGLES)
{
const U32 num_triangles = mVertexBuffer->getNumIndices() / 3;
const U32 num_triangles = getIndexCount() / 3;
// Initialize all the triangles we need
mOctreeTriangles.resize(num_triangles);
@ -640,7 +658,7 @@ void Primitive::createOctree()
}
else if (mMode == Mode::TRIANGLE_STRIP)
{
const U32 num_triangles = mVertexBuffer->getNumIndices() - 2;
const U32 num_triangles = getIndexCount() - 2;
// Initialize all the triangles we need
mOctreeTriangles.resize(num_triangles);
@ -664,7 +682,7 @@ void Primitive::createOctree()
}
else if (mMode == Mode::TRIANGLE_FAN)
{
const U32 num_triangles = mVertexBuffer->getNumIndices() - 2;
const U32 num_triangles = getIndexCount() - 2;
// Initialize all the triangles we need
mOctreeTriangles.resize(num_triangles);

View File

@ -54,10 +54,7 @@ namespace LL
~Primitive();
// GPU copy of mesh data
LLPointer<LLVertexBuffer> mVertexBuffer;
// CPU copy of mesh data, keep these as LLVector types for compatibility with raycasting code
// CPU copy of mesh data
std::vector<LLVector2> mTexCoords0;
std::vector<LLVector2> mTexCoords1;
std::vector<LLVector4a> mNormals;
@ -80,6 +77,17 @@ namespace LL
// shader variant according to LLGLSLShader::GLTFVariant flags
U8 mShaderVariant = 0;
// vertex attribute mask
U32 mAttributeMask = 0;
// backpointer to vertex buffer (owned by Asset)
LLPointer<LLVertexBuffer> mVertexBuffer;
U32 mVertexOffset = 0;
U32 mIndexOffset = 0;
U32 getVertexCount() const { return (U32) mPositions.size(); }
U32 getIndexCount() const { return (U32) mIndexArray.size(); }
std::unordered_map<std::string, S32> mAttributes;
// create octree based on vertex buffer
@ -100,6 +108,11 @@ namespace LL
const Primitive& operator=(const Value& src);
bool prep(Asset& asset);
// upload geometry to given vertex buffer
// asserts that buffer is bound
// asserts that buffer is valid for this primitive
void upload(LLVertexBuffer* buffer);
};
}
}

View File

@ -437,6 +437,8 @@ void GLTFSceneManager::onGLTFLoadComplete(const LLUUID& id, LLAssetType::EType a
void GLTFSceneManager::update()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF;
for (U32 i = 0; i < mObjects.size(); ++i)
{
if (mObjects[i]->isDead() || mObjects[i]->mGLTFAsset == nullptr)
@ -552,6 +554,7 @@ void GLTFSceneManager::render(bool opaque, bool rigged, bool unlit)
void GLTFSceneManager::render(U8 variant)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF;
// just render the whole scene by traversing the whole scenegraph
// Assumes camera transform is already set and appropriate shader is already bound.
// Eventually we'll want a smarter render pipe that has pre-sorted the scene graph
@ -563,8 +566,6 @@ void GLTFSceneManager::render(U8 variant)
render((U8) (variant | LLGLSLShader::GLTFVariant::MULTI_UV));
}
gGL.matrixMode(LLRender::MM_MODELVIEW);
bool rigged = variant & LLGLSLShader::GLTFVariant::RIGGED;
for (U32 i = 0; i < mObjects.size(); ++i)
@ -581,19 +582,11 @@ void GLTFSceneManager::render(U8 variant)
LLMatrix4a mat = mObjects[i]->getGLTFAssetToAgentTransform();
LLMatrix4a modelview;
modelview.loadu(gGLModelView);
// provide a modelview matrix that goes from asset to camera space
// (matrix palettes are in asset space)
gGL.loadMatrix(gGLModelView);
gGL.multMatrix(mat.getF32ptr());
matMul(mat, modelview, modelview);
mat4 mdv = glm::make_mat4(modelview.getF32ptr());
asset->updateRenderTransforms(mdv);
if (rigged)
{ // provide a modelview matrix that goes from asset to camera space for rigged render passes
// (matrix palettes are in asset space)
gGL.loadMatrix(glm::value_ptr(mdv));
}
render(*asset, variant);
gGL.popMatrix();
@ -602,176 +595,185 @@ void GLTFSceneManager::render(U8 variant)
void GLTFSceneManager::render(Asset& asset, U8 variant)
{
bool opaque = !(variant & LLGLSLShader::GLTFVariant::ALPHA_BLEND);
bool rigged = variant & LLGLSLShader::GLTFVariant::RIGGED;
LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF;
if (opaque)
for (U32 ds = 0; ds < 2; ++ds)
{
gGLTFPBRMetallicRoughnessProgram.bind(variant);
}
else
{ // alpha shaders need all the shadow map setup etc
gPipeline.bindDeferredShader(gGLTFPBRMetallicRoughnessProgram.mGLTFVariants[variant]);
}
RenderData& rd = asset.mRenderData[ds];
auto& batches = rd.mBatches[variant];
for (auto& node : asset.mNodes)
{
if (node.mSkin != INVALID_INDEX)
if (batches.empty())
{
if (rigged)
{
Skin& skin = asset.mSkins[node.mSkin];
glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_JOINTS, skin.mUBO);
}
return;
}
if (node.mMesh != INVALID_INDEX)
LLGLDisable cull_face(ds == 1 ? GL_CULL_FACE : 0);
bool opaque = !(variant & LLGLSLShader::GLTFVariant::ALPHA_BLEND);
bool rigged = variant & LLGLSLShader::GLTFVariant::RIGGED;
bool shader_bound = false;
for (U32 i = 0; i < batches.size(); ++i)
{
Mesh& mesh = asset.mMeshes[node.mMesh];
for (auto& primitive : mesh.mPrimitives)
if (batches[i].mPrimitives.empty() || batches[i].mVertexBuffer.isNull())
{
if (primitive.mShaderVariant != variant)
continue;
}
if (!shader_bound)
{ // don't bind the shader until we know we have somthing to render
if (opaque)
{
continue;
gGLTFPBRMetallicRoughnessProgram.bind(variant);
}
else
{ // alpha shaders need all the shadow map setup etc
gPipeline.bindDeferredShader(gGLTFPBRMetallicRoughnessProgram.mGLTFVariants[variant]);
}
if (!rigged)
{
gGL.loadMatrix((F32*)glm::value_ptr(node.mRenderMatrix));
glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_NODES, asset.mNodesUBO);
}
bool cull = true;
if (primitive.mMaterial != INVALID_INDEX)
{
Material& material = asset.mMaterials[primitive.mMaterial];
bind(asset, material);
cull = !material.mDoubleSided;
glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_MATERIALS, asset.mMaterialsUBO);
for (U32 i = 0; i < TEXTURE_TYPE_COUNT; ++i)
{
mLastTexture[i] = -2;
}
gGL.syncMatrices();
shader_bound = true;
}
{
LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("gltfdc - set vb");
batches[i].mVertexBuffer->setBuffer();
}
S32 mat_idx = i - 1;
if (mat_idx != INVALID_INDEX)
{
Material& material = asset.mMaterials[mat_idx];
bind(asset, material);
}
else
{
LLFetchedGLTFMaterial::sDefault.bind();
LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::GLTF_MATERIAL_ID, -1);
}
for (auto& pdata : batches[i].mPrimitives)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("GLTF draw call");
Node& node = asset.mNodes[pdata.mNodeIndex];
Mesh& mesh = asset.mMeshes[node.mMesh];
Primitive& primitive = mesh.mPrimitives[pdata.mPrimitiveIndex];
if (rigged)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("gltfdc - bind skin");
llassert(node.mSkin != INVALID_INDEX);
Skin& skin = asset.mSkins[node.mSkin];
glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_JOINTS, skin.mUBO);
}
else
{
LLFetchedGLTFMaterial::sDefault.bind();
LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::GLTF_NODE_ID, pdata.mNodeIndex);
}
LLGLDisable cull_face(!cull ? GL_CULL_FACE : 0);
{
LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("gltfdc - push vb");
primitive.mVertexBuffer->setBuffer();
if (primitive.mVertexBuffer->getNumIndices() > 0)
{
primitive.mVertexBuffer->draw(primitive.mGLMode, primitive.mVertexBuffer->getNumIndices(), 0);
}
else
{
primitive.mVertexBuffer->drawArrays(primitive.mGLMode, 0, primitive.mVertexBuffer->getNumVerts());
primitive.mVertexBuffer->drawRangeFast(primitive.mGLMode, primitive.mVertexOffset, primitive.mVertexOffset + primitive.getVertexCount() - 1, primitive.getIndexCount(), primitive.mIndexOffset);
}
}
}
}
}
static void bindTexture(Asset& asset, S32 uniform, Material::TextureInfo& info, LLViewerTexture* fallback)
void GLTFSceneManager::bindTexture(Asset& asset, TextureType texture_type, TextureInfo& info, LLViewerTexture* fallback)
{
if (info.mIndex != INVALID_INDEX)
U8 type_idx = (U8)texture_type;
if (info.mIndex == mLastTexture[type_idx])
{ //already bound
return;
}
S32 uniform[] =
{
Texture& texture = asset.mTextures[info.mIndex];
LLShaderMgr::DIFFUSE_MAP,
LLShaderMgr::NORMAL_MAP,
LLShaderMgr::METALLIC_ROUGHNESS_MAP,
LLShaderMgr::OCCLUSION_MAP,
LLShaderMgr::EMISSIVE_MAP
};
LLViewerTexture* tex = asset.mImages[texture.mSource].mTexture;
if (tex)
S32 channel = LLGLSLShader::sCurBoundShaderPtr->getTextureChannel(uniform[(U8)type_idx]);
if (channel > -1)
{
glActiveTexture(GL_TEXTURE0 + channel);
if (info.mIndex != INVALID_INDEX)
{
tex->addTextureStats(2048.f * 2048.f);
S32 channel = LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, tex);
Texture& texture = asset.mTextures[info.mIndex];
if (channel != -1 && texture.mSampler != -1)
{ // set sampler state
Sampler& sampler = asset.mSamplers[texture.mSampler];
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, sampler.mWrapS);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, sampler.mWrapT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, sampler.mMagFilter);
LLViewerTexture* tex = asset.mImages[texture.mSource].mTexture;
if (tex)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("gl bind texture");
glBindTexture(GL_TEXTURE_2D, tex->getTexName());
// NOTE: do not set min filter. Always respect client preference for min filter
if (channel != -1 && texture.mSampler != -1)
{ // set sampler state
Sampler& sampler = asset.mSamplers[texture.mSampler];
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, sampler.mWrapS);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, sampler.mWrapT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, sampler.mMagFilter);
// NOTE: do not set min filter. Always respect client preference for min filter
}
else
{
// set default sampler state
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
}
else
{
// set default sampler state
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, fallback->getTexName());
}
}
else
{
LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, fallback);
glBindTexture(GL_TEXTURE_2D, fallback->getTexName());
}
}
else
{
LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, fallback);
}
}
void GLTFSceneManager::bind(Asset& asset, Material& material)
{
// bind for rendering (derived from LLFetchedGLTFMaterial::bind)
// glTF 2.0 Specification 3.9.4. Alpha Coverage
// mAlphaCutoff is only valid for LLGLTFMaterial::ALPHA_MODE_MASK
F32 min_alpha = -1.0;
LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF;
LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
if (!LLPipeline::sShadowRender || (material.mAlphaMode == Material::AlphaMode::BLEND))
{
if (material.mAlphaMode == Material::AlphaMode::MASK)
{
// dividing the alpha cutoff by transparency here allows the shader to compare against
// the alpha value of the texture without needing the transparency value
if (material.mPbrMetallicRoughness.mBaseColorFactor.a > 0.f)
{
min_alpha = material.mAlphaCutoff / material.mPbrMetallicRoughness.mBaseColorFactor.a;
}
else
{
min_alpha = 1024.f;
}
}
shader->uniform1f(LLShaderMgr::MINIMUM_ALPHA, min_alpha);
}
bindTexture(asset, LLShaderMgr::DIFFUSE_MAP, material.mPbrMetallicRoughness.mBaseColorTexture, LLViewerFetchedTexture::sWhiteImagep);
F32 tf[8];
material.mPbrMetallicRoughness.mBaseColorTexture.mTextureTransform.getPacked(tf);
shader->uniform4fv(LLShaderMgr::TEXTURE_BASE_COLOR_TRANSFORM, 2, tf);
shader->uniform1i(LLShaderMgr::BASE_COLOR_TEXCOORD, material.mPbrMetallicRoughness.mBaseColorTexture.getTexCoord());
bindTexture(asset, TextureType::BASE_COLOR, material.mPbrMetallicRoughness.mBaseColorTexture, LLViewerFetchedTexture::sWhiteImagep);
if (!LLPipeline::sShadowRender)
{
bindTexture(asset, LLShaderMgr::NORMAL_MAP, material.mNormalTexture, LLViewerFetchedTexture::sFlatNormalImagep);
bindTexture(asset, LLShaderMgr::METALLIC_ROUGHNESS_MAP, material.mPbrMetallicRoughness.mMetallicRoughnessTexture, LLViewerFetchedTexture::sWhiteImagep);
bindTexture(asset, LLShaderMgr::OCCLUSION_MAP, material.mOcclusionTexture, LLViewerFetchedTexture::sWhiteImagep);
bindTexture(asset, LLShaderMgr::EMISSIVE_MAP, material.mEmissiveTexture, LLViewerFetchedTexture::sWhiteImagep);
// NOTE: base color factor is baked into vertex stream
shader->uniform1f(LLShaderMgr::ROUGHNESS_FACTOR, material.mPbrMetallicRoughness.mRoughnessFactor);
shader->uniform1f(LLShaderMgr::METALLIC_FACTOR, material.mPbrMetallicRoughness.mMetallicFactor);
shader->uniform3fv(LLShaderMgr::EMISSIVE_COLOR, 1, glm::value_ptr(material.mEmissiveFactor));
material.mNormalTexture.mTextureTransform.getPacked(tf);
shader->uniform4fv(LLShaderMgr::TEXTURE_NORMAL_TRANSFORM, 2, tf);
shader->uniform1i(LLShaderMgr::NORMAL_TEXCOORD, material.mNormalTexture.getTexCoord());
material.mPbrMetallicRoughness.mMetallicRoughnessTexture.mTextureTransform.getPacked(tf);
shader->uniform4fv(LLShaderMgr::TEXTURE_METALLIC_ROUGHNESS_TRANSFORM, 2, tf);
shader->uniform1i(LLShaderMgr::METALLIC_ROUGHNESS_TEXCOORD, material.mPbrMetallicRoughness.mMetallicRoughnessTexture.getTexCoord());
material.mOcclusionTexture.mTextureTransform.getPacked(tf);
shader->uniform4fv(LLShaderMgr::TEXTURE_OCCLUSION_TRANSFORM, 2, tf);
shader->uniform1i(LLShaderMgr::OCCLUSION_TEXCOORD, material.mOcclusionTexture.getTexCoord());
material.mEmissiveTexture.mTextureTransform.getPacked(tf);
shader->uniform4fv(LLShaderMgr::TEXTURE_EMISSIVE_TRANSFORM, 2, tf);
shader->uniform1i(LLShaderMgr::EMISSIVE_TEXCOORD, material.mEmissiveTexture.getTexCoord());
bindTexture(asset, TextureType::NORMAL, material.mNormalTexture, LLViewerFetchedTexture::sFlatNormalImagep);
bindTexture(asset, TextureType::METALLIC_ROUGHNESS, material.mPbrMetallicRoughness.mMetallicRoughnessTexture, LLViewerFetchedTexture::sWhiteImagep);
bindTexture(asset, TextureType::OCCLUSION, material.mOcclusionTexture, LLViewerFetchedTexture::sWhiteImagep);
bindTexture(asset, TextureType::EMISSIVE, material.mEmissiveTexture, LLViewerFetchedTexture::sWhiteImagep);
}
shader->uniform1i(LLShaderMgr::GLTF_MATERIAL_ID, &material - &asset.mMaterials[0]);
}
LLMatrix4a inverse(const LLMatrix4a& mat)
@ -930,10 +932,11 @@ void renderAssetDebug(LLViewerObject* obj, Asset* asset)
// assumes modelview matrix is already set
gGL.pushMatrix();
// get raycast in asset space
LLMatrix4a agent_to_asset = obj->getAgentToGLTFAssetTransform();
gGL.multMatrix(agent_to_asset.getF32ptr());
vec4 start;
vec4 end;
@ -951,7 +954,8 @@ void renderAssetDebug(LLViewerObject* obj, Asset* asset)
if (node.mMesh != INVALID_INDEX)
{
gGL.loadMatrix((F32*)glm::value_ptr(node.mRenderMatrix));
gGL.pushMatrix();
gGL.multMatrix((F32*)glm::value_ptr(node.mAssetMatrix));
// draw bounding box of mesh primitives
if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BBOXES))
@ -994,6 +998,7 @@ void renderAssetDebug(LLViewerObject* obj, Asset* asset)
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
#endif
gGL.popMatrix();
}
}
@ -1012,35 +1017,15 @@ void GLTFSceneManager::renderDebug()
gDebugProgram.bind();
gGL.pushMatrix();
gGL.loadMatrix(gGLModelView);
LLGLDisable cullface(GL_CULL_FACE);
LLGLEnable blend(GL_BLEND);
gGL.setSceneBlendType(LLRender::BT_ALPHA);
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
gPipeline.disableLights();
// force update all mRenderMatrix, not just nodes with meshes
for (auto& obj : mObjects)
{
if (obj->isDead() || obj->mGLTFAsset == nullptr)
{
continue;
}
mat4 mat = glm::make_mat4(obj->getGLTFAssetToAgentTransform().getF32ptr());
mat4 modelview = glm::make_mat4(gGLModelView);
modelview = modelview * mat;
Asset* asset = obj->mGLTFAsset.get();
for (auto& node : asset->mNodes)
{
node.mRenderMatrix = modelview * node.mAssetMatrix;
}
}
for (auto& obj : mObjects)
{
if (obj->isDead() || obj->mGLTFAsset == nullptr)
@ -1061,9 +1046,6 @@ void GLTFSceneManager::renderDebug()
LLGLDepthTest depth(GL_TRUE, i == 0 ? GL_FALSE : GL_TRUE, i == 0 ? GL_GREATER : GL_LEQUAL);
LLGLState blend(GL_BLEND, i == 0 ? GL_TRUE : GL_FALSE);
gGL.pushMatrix();
for (auto& obj : mObjects)
{
if (obj->isDead() || obj->mGLTFAsset == nullptr)
@ -1071,20 +1053,16 @@ void GLTFSceneManager::renderDebug()
continue;
}
mat4 mat = glm::make_mat4(obj->getGLTFAssetToAgentTransform().getF32ptr());
gGL.pushMatrix();
mat4 modelview = glm::make_mat4(gGLModelView);
modelview = modelview * mat;
gGL.multMatrix(obj->getGLTFAssetToAgentTransform().getF32ptr());
Asset* asset = obj->mGLTFAsset.get();
for (auto& node : asset->mNodes)
{
// force update all mRenderMatrix, not just nodes with meshes
node.mRenderMatrix = modelview * node.mAssetMatrix;
gGL.loadMatrix(glm::value_ptr(node.mRenderMatrix));
gGL.pushMatrix();
gGL.multMatrix(glm::value_ptr(node.mAssetMatrix));
// render x-axis red, y-axis green, z-axis blue
gGL.color4f(1.f, 0.f, 0.f, 0.5f);
gGL.begin(LLRender::LINES);
@ -1120,12 +1098,12 @@ void GLTFSceneManager::renderDebug()
}
gGL.end();
gGL.flush();
gGL.popMatrix();
}
gGL.popMatrix();
}
gGL.popMatrix();
}
}
@ -1139,28 +1117,36 @@ void GLTFSceneManager::renderDebug()
if (drawable)
{
gGL.pushMatrix();
Asset* asset = drawable->getVObj()->mGLTFAsset.get();
Node* node = &asset->mNodes[node_hit];
Primitive* primitive = &asset->mMeshes[node->mMesh].mPrimitives[primitive_hit];
gGL.flush();
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
gGL.color3f(1, 0, 1);
drawBoxOutline(intersection, LLVector4a(0.1f, 0.1f, 0.1f, 0.f));
LLViewerObject* obj = drawable->getVObj();
if (obj)
{
gGL.pushMatrix();
gGL.multMatrix(obj->getGLTFAssetToAgentTransform().getF32ptr());
Asset* asset = obj->mGLTFAsset.get();
Node* node = &asset->mNodes[node_hit];
Primitive* primitive = &asset->mMeshes[node->mMesh].mPrimitives[primitive_hit];
gGL.loadMatrix(glm::value_ptr(node->mRenderMatrix));
gGL.flush();
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
gGL.color3f(1, 0, 1);
drawBoxOutline(intersection, LLVector4a(0.1f, 0.1f, 0.1f, 0.f));
gGL.multMatrix(glm::value_ptr(node->mAssetMatrix));
auto* listener = (LLVolumeOctreeListener*) primitive->mOctree->getListener(0);
drawBoxOutline(listener->mBounds[0], listener->mBounds[1]);
auto* listener = (LLVolumeOctreeListener*)primitive->mOctree->getListener(0);
drawBoxOutline(listener->mBounds[0], listener->mBounds[1]);
gGL.flush();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
gGL.popMatrix();
gGL.flush();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
gGL.popMatrix();
}
}
}
gGL.popMatrix();
gDebugProgram.unbind();
}

View File

@ -59,7 +59,7 @@ namespace LL
// bind the given material for rendering
void bind(LL::GLTF::Asset& asset, LL::GLTF::Material& material);
void bindTexture(LL::GLTF::Asset& asset, LL::GLTF::TextureType texture_type, LL::GLTF::TextureInfo& info, LLViewerTexture* fallback);
void renderOpaque();
void renderAlpha();
@ -94,6 +94,11 @@ namespace LL
U32 mPendingGLTFUploads = 0;
U32 mJointUBO = 0;
// render loop state
S32 mLastTexture[GLTF::TEXTURE_TYPE_COUNT] = { -2, -2, -2, -2, -2 };
};
}

View File

@ -258,7 +258,7 @@ void LLDrawPoolAlpha::forwardRender(bool rigged)
mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // }
gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
if (rigged)
if (rigged && mType == LLDrawPool::POOL_ALPHA_POST_WATER)
{ // draw GLTF scene to depth buffer before rigged alpha
LL::GLTFSceneManager::instance().render(false, false);
LL::GLTFSceneManager::instance().render(false, true);

View File

@ -54,7 +54,10 @@ void LLDrawPoolGLTFPBR::renderDeferred(S32 pass)
{
llassert(!LLPipeline::sRenderingHUDs);
LL::GLTFSceneManager::instance().renderOpaque();
if (mRenderType == LLPipeline::RENDER_TYPE_PASS_GLTF_PBR_ALPHA_MASK)
{
LL::GLTFSceneManager::instance().renderOpaque();
}
gDeferredPBROpaqueProgram.bind();
pushGLTFBatches(mRenderType);

View File

@ -205,18 +205,8 @@ void LLHeroProbeManager::update()
LLVector3(0, 0, -1)
};
// Iterate through each face of the cube
for (int i = 0; i < 6; i++)
{
float cube_facing = fmax(-1, fmin(1.0f, cameraDirection * cubeFaces[i]));
cube_facing = 1 - cube_facing;
mFaceUpdateList[i] = ceilf(cube_facing * gPipeline.RenderHeroProbeConservativeUpdateMultiplier);
}
mProbes[0]->mOrigin = probe_pos;
mProbes[0]->mRadius = mNearestHero->getScale().magVec() * 0.5f;
}
else
{
@ -243,9 +233,10 @@ void LLHeroProbeManager::renderProbes()
static LLCachedControl<S32> sDetail(gSavedSettings, "RenderHeroReflectionProbeDetail", -1);
static LLCachedControl<S32> sLevel(gSavedSettings, "RenderHeroReflectionProbeLevel", 3);
static LLCachedControl<S32> sUpdateRate(gSavedSettings, "RenderHeroProbeUpdateRate", 0);
F32 near_clip = 0.01f;
if (mNearestHero != nullptr && (gPipeline.RenderHeroProbeUpdateRate == 0 || (gFrameCount % gPipeline.RenderHeroProbeUpdateRate) == 0) &&
if (mNearestHero != nullptr &&
!gTeleportDisplay && !gDisconnected && !LLAppViewer::instance()->logoutRequestSent())
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("hpmu - realtime");
@ -255,20 +246,36 @@ void LLHeroProbeManager::renderProbes()
gPipeline.mReflectionMapManager.mRadiancePass = true;
mRenderingMirror = true;
doOcclusion();
S32 rate = sUpdateRate;
for (U32 j = 0; j < mProbes.size(); j++)
// rate must be divisor of 6 (1, 2, 3, or 6)
if (rate < 1)
{
rate = 1;
}
else if (rate > 3)
{
rate = 6;
}
S32 face = gFrameCount % 6;
if (!mProbes.empty() && !mProbes[0].isNull() && !mProbes[0]->mOccluded)
{
LL_PROFILE_ZONE_NUM(gFrameCount % rate);
LL_PROFILE_ZONE_NUM(rate);
for (U32 i = 0; i < 6; ++i)
{
if (mFaceUpdateList[i] > 0 && mCurrentProbeUpdateFrame % mFaceUpdateList[i] == 0)
{
updateProbeFace(mProbes[j], i, mNearestHero->getReflectionProbeIsDynamic() && sDetail > 0, near_clip);
mCurrentProbeUpdateFrame = 0;
if ((gFrameCount % rate) == (i % rate))
{ // update 6/rate faces per frame
LL_PROFILE_ZONE_NUM(i);
updateProbeFace(mProbes[0], i, mNearestHero->getReflectionProbeIsDynamic() && sDetail > 0, near_clip);
}
}
generateRadiance(mProbes[j]);
generateRadiance(mProbes[0]);
}
mRenderingMirror = false;
gPipeline.mReflectionMapManager.mRadiancePass = radiance_pass;
@ -276,8 +283,6 @@ void LLHeroProbeManager::renderProbes()
mProbes[0]->mViewerObject = mNearestHero;
mProbes[0]->autoAdjustOrigin();
}
mCurrentProbeUpdateFrame++;
}
// Do the reflection map update render passes.
@ -411,6 +416,7 @@ void LLHeroProbeManager::updateProbeFace(LLReflectionMap* probe, U32 face, bool
// Useful when we may not always be rendering a full set of faces of the probe.
void LLHeroProbeManager::generateRadiance(LLReflectionMap* probe)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
S32 sourceIdx = mReflectionProbeCount;
// Unlike the reflectionmap manager, all probes are considered "realtime" for hero probes.
@ -617,7 +623,7 @@ void LLHeroProbeManager::doOcclusion()
for (auto& probe : mProbes)
{
if (probe != nullptr && probe != mDefaultProbe)
if (probe != nullptr)
{
probe->doOcclusion(eye);
}

View File

@ -147,9 +147,6 @@ private:
bool mReset = false;
bool mRenderingMirror = false;
std::map<int, int> mFaceUpdateList;
U32 mCurrentProbeUpdateFrame = 0;
std::vector<LLPointer<LLVOVolume>> mHeroVOList;
LLPointer<LLVOVolume> mNearestHero;

View File

@ -5068,7 +5068,7 @@ public:
return;
}
BOOL session_type_p2p = input["body"]["voice"].get("invitation_type").asInteger() == EMultiAgentChatSessionType::P2P_CHAT_SESSION;
bool session_type_p2p = input["body"]["voice"].get("invitation_type").asInteger() == EMultiAgentChatSessionType::P2P_CHAT_SESSION;
LL_DEBUGS("Voice") << "Received voice information from the server: " << input["body"]<< LL_ENDL;
gIMMgr->inviteToSession(
input["body"]["session_id"].asUUID(),

View File

@ -263,7 +263,18 @@ static bool make_gltf_variant(LLGLSLShader& shader, LLGLSLShader& variant, bool
variant.mDefines = shader.mDefines; // NOTE: Must come before addPermutation
variant.addPermutation("MAX_JOINTS_PER_GLTF_OBJECT", std::to_string(LLSkinningUtil::getMaxGLTFJointCount()));
U32 node_size = 16 * 3;
U32 max_nodes = gGLManager.mMaxUniformBlockSize / node_size;
variant.addPermutation("MAX_NODES_PER_GLTF_OBJECT", std::to_string(max_nodes));
U32 material_size = 16 * 12;
U32 max_materials = gGLManager.mMaxUniformBlockSize / material_size;
LLGLSLShader::sMaxGLTFMaterials = max_materials;
variant.addPermutation("MAX_MATERIALS_PER_GLTF_OBJECT", std::to_string(max_materials));
U32 max_vec4s = gGLManager.mMaxUniformBlockSize / 16;
variant.addPermutation("MAX_UBO_VEC4S", std::to_string(max_vec4s));
if (rigged)
{

View File

@ -906,7 +906,7 @@ void LLVoiceChannelP2P::setChannelInfo(const LLSD& channel_info)
}
}
mReceivedCall = TRUE;
mReceivedCall = true;
if (!channel_info.isUndefined())
{
mIncomingCallInterface = LLVoiceClient::getInstance()->getIncomingCallInterface(channel_info);

View File

@ -5327,7 +5327,7 @@ std::string LLVivoxVoiceClient::nameFromID(const LLUUID &uuid)
LLStringUtil::replaceChar(result, '+', '-');
LLStringUtil::replaceChar(result, '/', '_');
// If you need to transform a GUID to this form on the Mac OS X command line, this will do so:
// If you need to transform a GUID to this form on the macOS command line, this will do so:
// echo -n x && (echo e669132a-6c43-4ee1-a78d-6c82fff59f32 |xxd -r -p |openssl base64|tr '/+' '_-')
// The reverse transform can be done with:
@ -7063,7 +7063,7 @@ void LLVivoxVoiceClient::updateVoiceMorphingMenu()
const voice_effect_list_t& effect_list = effect_interfacep->getVoiceEffectList();
if (!effect_list.empty())
{
LLMenuGL * voice_morphing_menup = gMenuBarView->findChildMenuByName("VoiceMorphing", TRUE);
LLMenuGL * voice_morphing_menup = gMenuBarView->findChildMenuByName("VoiceMorphing", true);
if (NULL != voice_morphing_menup)
{

View File

@ -1294,7 +1294,7 @@ bool LLWebRTCVoiceClient::isVoiceWorking() const
bool LLWebRTCVoiceClient::isSessionCallBackPossible(const LLUUID &session_id)
{
sessionStatePtr_t session(findP2PSession(session_id));
return session && session->isCallbackPossible() ? true : false;
return session && session->isCallbackPossible();
}
// Channel Management

View File

@ -2557,6 +2557,7 @@ void LLPipeline::doOcclusion(LLCamera& camera)
mCubeVB->setBuffer();
mReflectionMapManager.doOcclusion();
mHeroProbeManager.doOcclusion();
gOcclusionCubeProgram.unbind();
gGL.setColorMask(true, true);

View File

@ -91,10 +91,10 @@
Aktualisierung Spiegelung:
</text>
<combo_box name="HeroProbeUpdateRate">
<combo_box.item label="Jeden Frame" name="0"/>
<combo_box.item label="Jeden 2. Frame" name="1"/>
<combo_box.item label="Jeden 3. Frame" name="2"/>
<combo_box.item label="Jeden 4. Frame" name="3"/>
<combo_box.item label="Niedrig" name="6"/>
<combo_box.item label="Mittel" name="3"/>
<combo_box.item label="Hoch" name="1"/>
<combo_box.item label="Ultra" name="0"/>
</combo_box>
<check_box label="Vollbildmodus" name="Fullscreen Mode" tool_tip="Firestorm im Vollbildmodus ausführen. (Erfordert Neustart)"/>
<slider label="Sichtweite:" name="DrawDistance"/>

View File

@ -864,21 +864,21 @@
name="HeroProbeUpdateRate"
width="150">
<combo_box.item
label="Every Frame"
name="0"
value="1"/>
label="Low"
name="6"
value="6"/>
<combo_box.item
label="Every 2nd Frame"
label="Medium"
name="3"
value="3"/>
<combo_box.item
label="High"
name="1"
value="2"/>
<combo_box.item
label="Every 3rd Frame"
name="2"
value="3"/>
<combo_box.item
label="Every 4th Frame"
name="3"
value="4"/>
label="Ultra"
name="0"
value="1"/>
</combo_box>
<!-- End of mirror settings -->

View File

@ -4136,8 +4136,8 @@
<menu_item_call
label="Open..."
name="Open...">
<menu_item_call.on_enable
function="EnableGLTF"/>
<!--<menu_item_call.on_enable
function="EnableGLTF"/>-->
<menu_item_call.on_click
function="Advanced.ClickGLTFOpen" />
</menu_item_call>

View File

@ -509,21 +509,21 @@
name="HeroProbeUpdateRate"
width="150">
<combo_box.item
label="Every Frame"
name="0"
value="1"/>
label="Low"
name="6"
value="6"/>
<combo_box.item
label="Every 2nd Frame"
label="Medium"
name="3"
value="3"/>
<combo_box.item
label="High"
name="1"
value="2"/>
<combo_box.item
label="Every 3rd Frame"
name="2"
value="3"/>
<combo_box.item
label="Every 4th Frame"
name="3"
value="4"/>
label="Ultra"
name="0"
value="1"/>
</combo_box>
<!-- End of mirror settings -->