Merge branch 'develop' of https://github.com/secondlife/viewer
# Conflicts: # indra/llcommon/llprofilercategories.hmaster
commit
364a14a8aa
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -2557,6 +2557,7 @@ void LLPipeline::doOcclusion(LLCamera& camera)
|
|||
mCubeVB->setBuffer();
|
||||
|
||||
mReflectionMapManager.doOcclusion();
|
||||
mHeroProbeManager.doOcclusion();
|
||||
gOcclusionCubeProgram.unbind();
|
||||
|
||||
gGL.setColorMask(true, true);
|
||||
|
|
|
|||
|
|
@ -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"/>
|
||||
|
|
|
|||
|
|
@ -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 -->
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 -->
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue