summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl34
-rw-r--r--indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl162
-rw-r--r--indra/newview/featuretable.txt2
-rw-r--r--indra/newview/featuretable_mac.txt2
-rw-r--r--indra/newview/gltf/animation.cpp98
-rw-r--r--indra/newview/gltf/animation.h3
-rw-r--r--indra/newview/gltf/asset.cpp299
-rw-r--r--indra/newview/gltf/asset.h127
-rw-r--r--indra/newview/gltf/common.h14
-rw-r--r--indra/newview/gltf/primitive.cpp90
-rw-r--r--indra/newview/gltf/primitive.h21
-rw-r--r--indra/newview/gltfscenemanager.cpp350
-rw-r--r--indra/newview/gltfscenemanager.h7
-rw-r--r--indra/newview/lldrawpoolalpha.cpp2
-rw-r--r--indra/newview/lldrawpoolpbropaque.cpp5
-rw-r--r--indra/newview/llheroprobemanager.cpp50
-rw-r--r--indra/newview/llheroprobemanager.h3
-rw-r--r--indra/newview/llviewershadermgr.cpp13
-rw-r--r--indra/newview/pipeline.cpp1
-rw-r--r--indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml22
-rw-r--r--indra/newview/skins/default/xui/en/menu_viewer.xml4
21 files changed, 868 insertions, 441 deletions
diff --git a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl
index 789c00259b..ac4ff50552 100644
--- a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl
+++ b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl
@@ -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;
diff --git a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl
index aac3dc917f..6a628bc852 100644
--- a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl
+++ b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl
@@ -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 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);
+ }
+}
-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;
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));
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index 8950770172..03849a0326 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -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
//
diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt
index 8c71235f37..7aa8504eaa 100644
--- a/indra/newview/featuretable_mac.txt
+++ b/indra/newview/featuretable_mac.txt
@@ -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
//
diff --git a/indra/newview/gltf/animation.cpp b/indra/newview/gltf/animation.cpp
index 8b85eba3e5..3dff67d746 100644
--- a/indra/newview/gltf/animation.cpp
+++ b/indra/newview/gltf/animation.cpp
@@ -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);
+ }
+ }
+
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("gltfanim - translation");
+
+ for (auto& channel : mTranslationChannels)
+ {
+ 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 - 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,32 +215,33 @@ void Animation::Sampler::getFrameInfo(Asset& asset, F32 time, U32& frameIndex, F
return;
}
- if (mFrameTimes.size() > 1)
+ frameIndex = U32(mFrameTimes.size()) - 2;
+ t = 1.f;
+
+ if (time > mMaxTime)
{
- llassert(mFrameTimes.size() <= size_t(U32_MAX));
- frameIndex = U32(mFrameTimes.size()) - 2;
- t = 1.f;
+ return;
+ }
- if (time > mMaxTime)
- {
- return;
- }
+ if (time < mLastFrameTime)
+ {
+ mLastFrameIndex = 0;
+ }
- for (U32 i = 0; i < (U32)mFrameTimes.size() - 1; i++)
+ mLastFrameTime = time;
+
+ U32 idx = mLastFrameIndex;
+
+ for (U32 i = idx; i < (U32)mFrameTimes.size() - 1; i++)
+ {
+ if (time >= mFrameTimes[i] && time < mFrameTimes[i + 1])
{
- if (time >= mFrameTimes[i] && time < mFrameTimes[i + 1])
- {
- frameIndex = i;
- t = (time - mFrameTimes[i]) / (mFrameTimes[i + 1] - mFrameTimes[i]);
- return;
- }
+ frameIndex = i;
+ t = (time - mFrameTimes[i]) / (mFrameTimes[i + 1] - mFrameTimes[i]);
+ mLastFrameIndex = frameIndex;
+ return;
}
}
- else
- {
- frameIndex = 0;
- t = 0.0f;
- }
}
bool Animation::RotationChannel::prep(Asset& asset, Animation::Sampler& sampler)
@@ -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();
diff --git a/indra/newview/gltf/animation.h b/indra/newview/gltf/animation.h
index d5426fd4ce..ab8839470a 100644
--- a/indra/newview/gltf/animation.h
+++ b/indra/newview/gltf/animation.h
@@ -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;
diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp
index 21be69aae2..a454e68a92 100644
--- a/indra/newview/gltf/asset.cpp
+++ b/indra/newview/gltf/asset.cpp
@@ -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;
diff --git a/indra/newview/gltf/asset.h b/indra/newview/gltf/asset.h
index ea3f7d480a..27821659db 100644
--- a/indra/newview/gltf/asset.h
+++ b/indra/newview/gltf/asset.h
@@ -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
diff --git a/indra/newview/gltf/common.h b/indra/newview/gltf/common.h
index 4f660d7cfc..b9698d4017 100644
--- a/indra/newview/gltf/common.h
+++ b/indra/newview/gltf/common.h
@@ -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;
}
}
diff --git a/indra/newview/gltf/primitive.cpp b/indra/newview/gltf/primitive.cpp
index 2280c7004e..e1579374d4 100644
--- a/indra/newview/gltf/primitive.cpp
+++ b/indra/newview/gltf/primitive.cpp
@@ -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,69 +514,79 @@ 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();
+ mAttributeMask = mask;
+
+ if (mMaterial != INVALID_INDEX)
+ {
+ Material& material = asset.mMaterials[mMaterial];
+ if (material.mAlphaMode == Material::AlphaMode::BLEND)
+ {
+ mShaderVariant |= LLGLSLShader::GLTFVariant::ALPHA_BLEND;
+ }
}
- mVertexBuffer = new LLVertexBuffer(mask);
+ 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));
- 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());
+ 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());
+ mVertexBuffer->setNormalData(mNormals.data(), offset, count);
}
if (!mTangents.empty())
{
- mVertexBuffer->setTangentData(mTangents.data());
+ mVertexBuffer->setTangentData(mTangents.data(), offset, count);
}
if (!mWeights.empty())
{
- mShaderVariant |= LLGLSLShader::GLTFVariant::RIGGED;
- mVertexBuffer->setWeight4Data(mWeights.data());
- mVertexBuffer->setJointData(mJoints.data());
+ 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());
+ mVertexBuffer->setTexCoord0Data(mTexCoords0.data(), offset, count);
vertical_flip(mTexCoords0);
if (!mTexCoords1.empty())
{
vertical_flip(mTexCoords1);
- mVertexBuffer->setTexCoord1Data(mTexCoords1.data());
+ mVertexBuffer->setTexCoord1Data(mTexCoords1.data(), offset, count);
vertical_flip(mTexCoords1);
}
-
if (!mIndexArray.empty())
{
- mVertexBuffer->setIndexData(mIndexArray.data());
- }
-
- createOctree();
-
- mVertexBuffer->unbind();
-
- if (mMaterial != INVALID_INDEX)
- {
- Material& material = asset.mMaterials[mMaterial];
- if (material.mAlphaMode == Material::AlphaMode::BLEND)
+ std::vector<U32> index_array;
+ index_array.resize(mIndexArray.size());
+ for (U32 i = 0; i < mIndexArray.size(); ++i)
{
- mShaderVariant |= LLGLSLShader::GLTFVariant::ALPHA_BLEND;
+ index_array[i] = mIndexArray[i] + mVertexOffset;
}
+ mVertexBuffer->setIndexData(index_array.data(), mIndexOffset, getIndexCount());
}
-
- return true;
}
void initOctreeTriangle(LLVolumeTriangle* tri, F32 scaler, S32 i0, S32 i1, S32 i2, const LLVector4a& v0, const LLVector4a& v1, const LLVector4a& v2)
@@ -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);
diff --git a/indra/newview/gltf/primitive.h b/indra/newview/gltf/primitive.h
index 7cc05cf831..304eb26432 100644
--- a/indra/newview/gltf/primitive.h
+++ b/indra/newview/gltf/primitive.h
@@ -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);
};
}
}
diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp
index e01aec0497..7b2de4d6de 100644
--- a/indra/newview/gltfscenemanager.cpp
+++ b/indra/newview/gltfscenemanager.cpp
@@ -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);
-
- matMul(mat, modelview, modelview);
-
- mat4 mdv = glm::make_mat4(modelview.getF32ptr());
- asset->updateRenderTransforms(mdv);
+ // provide a modelview matrix that goes from asset to camera space
+ // (matrix palettes are in asset space)
+ gGL.loadMatrix(gGLModelView);
+ gGL.multMatrix(mat.getF32ptr());
- 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;
- }
- else
+ glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_MATERIALS, asset.mMaterialsUBO);
+
+ for (U32 i = 0; i < TEXTURE_TYPE_COUNT; ++i)
{
- LLFetchedGLTFMaterial::sDefault.bind();
+ mLastTexture[i] = -2;
}
- LLGLDisable cull_face(!cull ? GL_CULL_FACE : 0);
+ 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];
- primitive.mVertexBuffer->setBuffer();
- if (primitive.mVertexBuffer->getNumIndices() > 0)
+ if (rigged)
{
- primitive.mVertexBuffer->draw(primitive.mGLMode, primitive.mVertexBuffer->getNumIndices(), 0);
+ 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
{
- primitive.mVertexBuffer->drawArrays(primitive.mGLMode, 0, primitive.mVertexBuffer->getNumVerts());
+ LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::GLTF_NODE_ID, pdata.mNodeIndex);
+ }
+
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("gltfdc - push vb");
+
+ 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];
+
+ LLViewerTexture* tex = asset.mImages[texture.mSource].mTexture;
+ if (tex)
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("gl bind texture");
+ glBindTexture(GL_TEXTURE_2D, tex->getTexName());
- 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);
+ 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
+ // 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)
@@ -931,10 +933,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;
@@ -952,7 +955,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))
@@ -995,6 +999,7 @@ void renderAssetDebug(LLViewerObject* obj, Asset* asset)
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
#endif
+ gGL.popMatrix();
}
}
@@ -1013,35 +1018,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)
@@ -1062,9 +1047,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)
@@ -1072,20 +1054,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);
@@ -1121,12 +1099,12 @@ void GLTFSceneManager::renderDebug()
}
gGL.end();
gGL.flush();
+ gGL.popMatrix();
}
- }
- gGL.popMatrix();
+ gGL.popMatrix();
+ }
}
-
}
@@ -1140,28 +1118,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();
+
}
diff --git a/indra/newview/gltfscenemanager.h b/indra/newview/gltfscenemanager.h
index 7da413e8b2..853bca59d0 100644
--- a/indra/newview/gltfscenemanager.h
+++ b/indra/newview/gltfscenemanager.h
@@ -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 };
+
};
}
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 93fea899f3..34da5b29d4 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -257,7 +257,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);
diff --git a/indra/newview/lldrawpoolpbropaque.cpp b/indra/newview/lldrawpoolpbropaque.cpp
index 5eb10fe335..4ea23412e6 100644
--- a/indra/newview/lldrawpoolpbropaque.cpp
+++ b/indra/newview/lldrawpoolpbropaque.cpp
@@ -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);
diff --git a/indra/newview/llheroprobemanager.cpp b/indra/newview/llheroprobemanager.cpp
index f544b70329..66ccdd2b32 100644
--- a/indra/newview/llheroprobemanager.cpp
+++ b/indra/newview/llheroprobemanager.cpp
@@ -188,18 +188,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
{
@@ -220,9 +210,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");
@@ -232,20 +223,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;
@@ -253,8 +260,6 @@ void LLHeroProbeManager::renderProbes()
mProbes[0]->mViewerObject = mNearestHero;
mProbes[0]->autoAdjustOrigin();
}
-
- mCurrentProbeUpdateFrame++;
}
// Do the reflection map update render passes.
@@ -388,6 +393,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.
@@ -594,7 +600,7 @@ void LLHeroProbeManager::doOcclusion()
for (auto& probe : mProbes)
{
- if (probe != nullptr && probe != mDefaultProbe)
+ if (probe != nullptr)
{
probe->doOcclusion(eye);
}
diff --git a/indra/newview/llheroprobemanager.h b/indra/newview/llheroprobemanager.h
index c8d505f4c3..28852770c3 100644
--- a/indra/newview/llheroprobemanager.h
+++ b/indra/newview/llheroprobemanager.h
@@ -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;
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 37fbfccbbb..12d0aa4f8e 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -259,7 +259,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)
{
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index f9ff8217af..6c9c4751d7 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -2436,6 +2436,7 @@ void LLPipeline::doOcclusion(LLCamera& camera)
mCubeVB->setBuffer();
mReflectionMapManager.doOcclusion();
+ mHeroProbeManager.doOcclusion();
gOcclusionCubeProgram.unbind();
gGL.setColorMask(true, true);
diff --git a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
index a80b1e1c13..7bc81a1f79 100644
--- a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
+++ b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml
@@ -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="Medium"
+ name="3"
+ value="3"/>
<combo_box.item
- label="Every 2nd Frame"
+ 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 -->
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 0e7c522f74..4a043bbbc9 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2866,8 +2866,8 @@ function="World.EnvPreset"
<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>