#1530 Increase joint limit for GLTF Assets (#1582)

* Migrate GLTF scene rendering to its own shaders
* Add support for ambient occlusion map separate from metallic roughness map (or absent)
* Use UBO's for GLTF joints
* Better error handling of downloading GLTF assets
master
Dave Parks 2024-05-29 16:56:39 -05:00 committed by GitHub
parent 2d0fe5ca7b
commit 15fd13f830
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 735 additions and 401 deletions

View File

@ -1238,6 +1238,11 @@ bool LLGLManager::initGL()
glGetIntegerv(GL_MAX_INTEGER_SAMPLES, &mMaxIntegerSamples);
glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &mMaxSampleMaskWords);
glGetIntegerv(GL_MAX_SAMPLES, &mMaxSamples);
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &mMaxUniformBlockSize);
// sanity clamp max uniform block size to 64k just in case
// there's some implementation that reports a crazy value
mMaxUniformBlockSize = llmin(mMaxUniformBlockSize, 65536);
if (mGLVersion >= 4.59f)
{

View File

@ -87,6 +87,7 @@ public:
S32 mGLMaxIndexRange;
S32 mGLMaxTextureSize;
F32 mMaxAnisotropy = 0.f;
S32 mMaxUniformBlockSize = 0;
// GL 4.x capabilities
bool mHasCubeMapArray = false;

View File

@ -983,17 +983,25 @@ bool LLGLSLShader::mapUniforms(const vector<LLStaticHashedString>* uniforms)
}
//........................................................................................................................................
if (mFeatures.hasReflectionProbes) // Set up block binding, in a way supported by Apple (rather than binding = 1 in .glsl).
{ // See slide 35 and more of https://docs.huihoo.com/apple/wwdc/2011/session_420__advances_in_opengl_for_mac_os_x_lion.pdf
static const GLuint BLOCKBINDING = 1; //picked by us
//Get the index, similar to a uniform location
GLuint UBOBlockIndex = glGetUniformBlockIndex(mProgramObject, "ReflectionProbes");
// Set up block binding, in a way supported by Apple (rather than binding = 1 in .glsl).
// See slide 35 and more of https://docs.huihoo.com/apple/wwdc/2011/session_420__advances_in_opengl_for_mac_os_x_lion.pdf
const char* ubo_names[] =
{
"ReflectionProbes", // UB_REFLECTION_PROBES
"GLTFJoints", // UB_GLTF_JOINTS
};
llassert(LL_ARRAY_SIZE(ubo_names) == NUM_UNIFORM_BLOCKS);
for (U32 i = 0; i < NUM_UNIFORM_BLOCKS; ++i)
{
GLuint UBOBlockIndex = glGetUniformBlockIndex(mProgramObject, ubo_names[i]);
if (UBOBlockIndex != GL_INVALID_INDEX)
{
//Set this index to a binding index
glUniformBlockBinding(mProgramObject, UBOBlockIndex, BLOCKBINDING);
glUniformBlockBinding(mProgramObject, UBOBlockIndex, i);
}
}
unbind();
LL_DEBUGS("ShaderUniform") << "Total Uniform Size: " << mTotalUniformSize << LL_ENDL;
@ -1049,9 +1057,10 @@ void LLGLSLShader::bind()
}
}
void LLGLSLShader::bind(LLGLSLShader::GLTFVariant variant)
void LLGLSLShader::bind(U32 variant)
{
llassert(mGLTFVariants.size() == LLGLSLShader::NUM_GLTF_VARIANTS);
llassert(variant < LLGLSLShader::NUM_GLTF_VARIANTS);
mGLTFVariants[variant].bind();
}

View File

@ -146,6 +146,14 @@ public:
SG_COUNT
} eGroup;
enum UniformBlock : GLuint
{
UB_REFLECTION_PROBES,
UB_GLTF_JOINTS,
NUM_UNIFORM_BLOCKS
};
static std::set<LLGLSLShader*> sInstances;
static bool sProfileEnabled;
@ -320,20 +328,24 @@ public:
LLGLSLShader* mRiggedVariant = nullptr;
// variants for use by GLTF renderer
// "this" is considered to be OPAQUE
enum GLTFVariant
// bit 0 = alpha mode blend (1) or opaque (0)
// bit 1 = rigged (1) or static (0)
struct GLTFVariant
{
STATIC_OPAQUE,
STATIC_BLEND,
RIGGED_OPAQUE,
RIGGED_BLEND,
NUM_GLTF_VARIANTS
constexpr static U32 RIGGED = 2;
constexpr static U32 ALPHA = 1;
constexpr static U32 OPAQUE_STATIC = 0;
constexpr static U32 ALPHA_STATIC = 1;
constexpr static U32 OPAQUE_RIGGED = 2;
constexpr static U32 ALPHA_RIGGED = 3;
};
constexpr static U32 NUM_GLTF_VARIANTS = 4;
std::vector<LLGLSLShader> mGLTFVariants;
//helper to bind GLTF variant
void bind(GLTFVariant variant);
void bind(U32 variant);
// hacky flag used for optimization in LLDrawPoolAlpha
bool mCanBindFast = false;

View File

@ -1225,6 +1225,9 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("diffuseMap");
mReservedUniforms.push_back("altDiffuseMap");
mReservedUniforms.push_back("specularMap");
mReservedUniforms.push_back("metallicRoughnessMap");
mReservedUniforms.push_back("normalMap");
mReservedUniforms.push_back("occlusionMap");
mReservedUniforms.push_back("emissiveMap");
mReservedUniforms.push_back("bumpMap");
mReservedUniforms.push_back("bumpMap2");
@ -1348,7 +1351,6 @@ void LLShaderMgr::initAttribsAndUniforms()
llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_SHADOW5+1);
mReservedUniforms.push_back("normalMap");
mReservedUniforms.push_back("positionMap");
mReservedUniforms.push_back("diffuseRect");
mReservedUniforms.push_back("specularRect");

View File

@ -93,6 +93,9 @@ public:
DIFFUSE_MAP, // "diffuseMap"
ALTERNATE_DIFFUSE_MAP, // "altDiffuseMap"
SPECULAR_MAP, // "specularMap"
METALLIC_ROUGHNESS_MAP, // "metallicRoughnessMap"
NORMAL_MAP, // "normalMap"
OCCLUSION_MAP, // "occlusionMap"
EMISSIVE_MAP, // "emissiveMap"
BUMP_MAP, // "bumpMap"
BUMP_MAP2, // "bumpMap2"
@ -202,7 +205,6 @@ public:
DEFERRED_SHADOW3, // "shadowMap3"
DEFERRED_SHADOW4, // "shadowMap4"
DEFERRED_SHADOW5, // "shadowMap5"
DEFERRED_NORMAL, // "normalMap"
DEFERRED_POSITION, // "positionMap"
DEFERRED_DIFFUSE, // "diffuseRect"
DEFERRED_SPECULAR, // "specularRect"

View File

@ -687,6 +687,7 @@ bool LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of
}
{
#if 0 // not a reliable test for VBOs that are not backed by a CPU buffer
U16* idx = (U16*) mMappedIndexData+indices_offset;
for (U32 i = 0; i < count; ++i)
{
@ -724,6 +725,7 @@ bool LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_of
}
}
}
#endif
}
return true;
@ -1036,8 +1038,7 @@ bool LLVertexBuffer::updateNumIndices(U32 nindices)
bool LLVertexBuffer::allocateBuffer(U32 nverts, U32 nindices)
{
if (nverts < 0 || nindices < 0 ||
nverts > 65536)
if (nverts < 0 || nindices < 0)
{
LL_ERRS() << "Bad vertex buffer allocation: " << nverts << " : " << nindices << LL_ENDL;
}

View File

@ -496,6 +496,43 @@ vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor,
return clamp(color, vec3(0), vec3(10));
}
vec3 pbrCalcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor,
float perceptualRoughness,
float metallic,
vec3 n, // normal
vec3 p, // pixel position
vec3 v, // view vector (negative normalized pixel position)
vec3 lp, // light position
vec3 ld, // light direction (for spotlights)
vec3 lightColor,
float lightSize, float falloff, float is_pointlight, float ambiance)
{
vec3 color = vec3(0,0,0);
vec3 lv = lp.xyz - p;
float lightDist = length(lv);
float dist = lightDist / lightSize;
if (dist <= 1.0)
{
lv /= lightDist;
float dist_atten = calcLegacyDistanceAttenuation(dist, falloff);
// spotlight coefficient.
float spot = max(dot(-ld, lv), is_pointlight);
// spot*spot => GL_SPOT_EXPONENT=2
float spot_atten = spot*spot;
vec3 intensity = spot_atten * dist_atten * lightColor * 3.0; //magic number to balance with legacy materials
color = intensity*pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, n.xyz, v, lv);
}
return color;
}
void calcDiffuseSpecular(vec3 baseColor, float metallic, inout vec3 diffuseColor, inout vec3 specularColor)
{
vec3 f0 = vec3(0.04);

View File

@ -51,8 +51,6 @@ uniform vec4[2] texture_emissive_transform;
out vec3 vary_fragcoord;
uniform float near_clip;
in vec3 position;
in vec4 diffuse_color;
in vec3 normal;
@ -88,7 +86,7 @@ void main()
#endif
gl_Position = vert;
vary_fragcoord.xyz = vert.xyz + vec3(0,0,near_clip);
vary_fragcoord.xyz = vert.xyz;
base_color_texcoord = texture_transform(texcoord0, texture_base_color_transform, texture_matrix0);
normal_texcoord = texture_transform(texcoord0, texture_normal_transform, texture_matrix0);

View File

@ -1,24 +1,24 @@
/**
/**
* @file pbrmetallicroughnessF.glsl
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2022, Linden Research, Inc.
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@ -33,11 +33,82 @@ uniform sampler2D diffuseMap; //always in sRGB space
uniform float metallicFactor;
uniform float roughnessFactor;
uniform vec3 emissiveColor;
uniform sampler2D bumpMap;
uniform sampler2D normalMap;
uniform sampler2D emissiveMap;
uniform sampler2D specularMap; // Packed: Occlusion, Metal, Roughness
uniform sampler2D metallicRoughnessMap;
uniform sampler2D occlusionMap;
#ifdef ALPHA_BLEND
out vec4 frag_color;
in vec3 vary_fragcoord;
#ifdef HAS_SUN_SHADOW
uniform sampler2D lightMap;
uniform vec2 screen_res;
#endif
// Lights
// See: LLRender::syncLightState()
uniform vec4 light_position[8];
uniform vec3 light_direction[8]; // spot direction
uniform vec4 light_attenuation[8]; // linear, quadratic, is omni, unused, See: LLPipeline::setupHWLights() and syncLightState()
uniform vec3 light_diffuse[8];
uniform vec2 light_deferred_attenuation[8]; // light size and falloff
uniform int sun_up_factor;
uniform vec3 sun_dir;
uniform vec3 moon_dir;
vec3 srgb_to_linear(vec3 c);
vec3 linear_to_srgb(vec3 c);
void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, out vec3 sunlit, out vec3 amblit, out vec3 atten, out vec3 additive);
vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color);
void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist);
float calcLegacyDistanceAttenuation(float distance, float falloff);
float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen);
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, bool transparent, vec3 amblit_linear);
void mirrorClip(vec3 pos);
void waterClip(vec3 pos);
void calcDiffuseSpecular(vec3 baseColor, float metallic, inout vec3 diffuseColor, inout vec3 specularColor);
vec3 pbrBaseLight(vec3 diffuseColor,
vec3 specularColor,
float metallic,
vec3 pos,
vec3 norm,
float perceptualRoughness,
vec3 light_dir,
vec3 sunlit,
float scol,
vec3 radiance,
vec3 irradiance,
vec3 colorEmissive,
float ao,
vec3 additive,
vec3 atten);
vec3 pbrCalcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor,
float perceptualRoughness,
float metallic,
vec3 n, // normal
vec3 p, // pixel position
vec3 v, // view vector (negative normalized pixel position)
vec3 lp, // light position
vec3 ld, // light direction (for spotlights)
vec3 lightColor,
float lightSize, float falloff, float is_pointlight, float ambiance);
#else
out vec4 frag_data[4];
#endif
in vec3 vary_position;
in vec4 vertex_color;
@ -50,7 +121,7 @@ in vec2 normal_texcoord;
in vec2 metallic_roughness_texcoord;
in vec2 emissive_texcoord;
uniform float minimum_alpha; // PBR alphaMode: MASK, See: mAlphaCutoff, setAlphaCutoff()
uniform float minimum_alpha;
vec3 linear_to_srgb(vec3 c);
vec3 srgb_to_linear(vec3 c);
@ -62,9 +133,11 @@ void mirrorClip(vec3 pos);
uniform mat3 normal_matrix;
void main()
{
mirrorClip(vary_position);
vec3 pos = vary_position;
mirrorClip(pos);
vec4 basecolor = texture(diffuseMap, base_color_texcoord.xy).rgba;
basecolor.rgb = srgb_to_linear(basecolor.rgb);
@ -79,39 +152,97 @@ void main()
vec3 col = basecolor.rgb;
// from mikktspace.com
vec3 vNt = texture(bumpMap, normal_texcoord.xy).xyz*2.0-1.0;
vec3 vNt = texture(normalMap, normal_texcoord.xy).xyz*2.0-1.0;
float sign = vary_sign;
vec3 vN = vary_normal;
vec3 vT = vary_tangent.xyz;
vec3 vB = sign * cross(vN, vT);
vec3 tnorm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN );
vec3 norm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN );
// RGB = Occlusion, Roughness, Metal
// default values, see LLViewerTexture::sDefaultPBRORMImagep
// occlusion 1.0
// roughness 0.0
// metal 0.0
vec3 spec = texture(specularMap, metallic_roughness_texcoord.xy).rgb;
spec.g *= roughnessFactor;
spec.b *= metallicFactor;
vec3 orm = texture(metallicRoughnessMap, metallic_roughness_texcoord.xy).rgb;
orm.r = texture(occlusionMap, metallic_roughness_texcoord.xy).r;
orm.g *= roughnessFactor;
orm.b *= metallicFactor;
vec3 emissive = emissiveColor;
emissive *= srgb_to_linear(texture(emissiveMap, emissive_texcoord.xy).rgb);
tnorm *= gl_FrontFacing ? 1.0 : -1.0;
norm *= gl_FrontFacing ? 1.0 : -1.0;
//spec.rgb = vec3(1,1,0);
//col = vec3(0,0,0);
//emissive = vary_tangent.xyz*0.5+0.5;
//emissive = vec3(sign*0.5+0.5);
//emissive = vNt * 0.5 + 0.5;
//emissive = tnorm*0.5+0.5;
#ifdef ALPHA_BLEND
vec3 color = vec3(0,0,0);
vec3 light_dir = (sun_up_factor == 1) ? sun_dir : moon_dir;
float scol = 1.0;
vec3 sunlit;
vec3 amblit;
vec3 additive;
vec3 atten;
calcAtmosphericVarsLinear(pos.xyz, norm, light_dir, sunlit, amblit, additive, atten);
vec3 sunlit_linear = srgb_to_linear(sunlit);
vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5;
#ifdef HAS_SUN_SHADOW
scol = sampleDirectionalShadow(pos.xyz, norm.xyz, frag);
#endif
float perceptualRoughness = orm.g * roughnessFactor;
float metallic = orm.b * metallicFactor;
// emissiveColor is the emissive color factor from GLTF and is already in linear space
vec3 colorEmissive = emissiveColor;
// emissiveMap here is a vanilla RGB texture encoded as sRGB, manually convert to linear
colorEmissive *= srgb_to_linear(texture(emissiveMap, emissive_texcoord.xy).rgb);
// PBR IBL
float gloss = 1.0 - perceptualRoughness;
vec3 irradiance = vec3(0);
vec3 radiance = vec3(0);
sampleReflectionProbes(irradiance, radiance, vary_position.xy*0.5+0.5, pos.xyz, norm.xyz, gloss, true, amblit);
vec3 diffuseColor;
vec3 specularColor;
calcDiffuseSpecular(col.rgb, metallic, diffuseColor, specularColor);
vec3 v = -normalize(pos.xyz);
color = pbrBaseLight(diffuseColor, specularColor, metallic, v, norm.xyz, perceptualRoughness, light_dir, sunlit_linear, scol, radiance, irradiance, colorEmissive, orm.r, additive, atten);
vec3 light = vec3(0);
// Punctual lights
#define LIGHT_LOOP(i) light += pbrCalcPointLightOrSpotLight(diffuseColor, specularColor, perceptualRoughness, metallic, norm.xyz, pos.xyz, v, light_position[i].xyz, light_direction[i].xyz, light_diffuse[i].rgb, light_deferred_attenuation[i].x, light_deferred_attenuation[i].y, light_attenuation[i].z, light_attenuation[i].w);
LIGHT_LOOP(1)
LIGHT_LOOP(2)
LIGHT_LOOP(3)
LIGHT_LOOP(4)
LIGHT_LOOP(5)
LIGHT_LOOP(6)
LIGHT_LOOP(7)
color.rgb += light.rgb;
color.rgb = applySkyAndWaterFog(pos.xyz, additive, atten, vec4(color, 1.0)).rgb;
float a = basecolor.a*vertex_color.a;
frag_color = max(vec4(color.rgb,a), vec4(0));
#else
// See: C++: addDeferredAttachments(), GLSL: softenLightF
frag_data[0] = max(vec4(col, 0.0), vec4(0)); // Diffuse
frag_data[1] = max(vec4(spec.rgb,0.0), vec4(0)); // PBR linear packed Occlusion, Roughness, Metal.
frag_data[2] = vec4(tnorm, GBUFFER_FLAG_HAS_PBR); // normal, environment intensity, flags
frag_data[3] = max(vec4(emissive,0), vec4(0)); // PBR sRGB Emissive
frag_data[0] = max(vec4(col, 0.0), vec4(0));
frag_data[1] = max(vec4(orm.rgb,0.0), vec4(0));
frag_data[2] = vec4(norm, GBUFFER_FLAG_HAS_PBR);
frag_data[3] = max(vec4(emissive,0), vec4(0));
#endif
}

View File

@ -29,7 +29,6 @@ uniform mat4 modelview_matrix;
#ifdef HAS_SKIN
uniform mat4 projection_matrix;
mat4 getObjectSkinnedTransform();
#else
uniform mat3 normal_matrix;
uniform mat4 modelview_projection_matrix;
@ -62,21 +61,85 @@ out vec3 vary_position;
vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl_animation_transform);
vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform);
#ifdef ALPHA_BLEND
out vec3 vary_fragcoord;
#endif
#ifdef HAS_SKIN
in vec4 weight4;
layout (std140) uniform GLTFJoints
{
// list of OBBs for user override probes
mat3x4 gltf_joints[MAX_JOINTS_PER_GLTF_OBJECT];
};
mat4 getGLTFSkinTransform()
{
int i;
vec4 w = fract(weight4);
vec4 index = floor(weight4);
index = min(index, vec4(MAX_JOINTS_PER_GLTF_OBJECT-1));
index = max(index, vec4( 0.0));
w *= 1.0/(w.x+w.y+w.z+w.w);
int i1 = int(index.x);
int i2 = int(index.y);
int i3 = int(index.z);
int i4 = int(index.w);
mat3 mat = mat3(gltf_joints[i1])*w.x;
mat += mat3(gltf_joints[i2])*w.y;
mat += mat3(gltf_joints[i3])*w.z;
mat += mat3(gltf_joints[i4])*w.w;
vec3 trans = vec3(gltf_joints[i1][0].w,gltf_joints[i1][1].w,gltf_joints[i1][2].w)*w.x;
trans += vec3(gltf_joints[i2][0].w,gltf_joints[i2][1].w,gltf_joints[i2][2].w)*w.y;
trans += vec3(gltf_joints[i3][0].w,gltf_joints[i3][1].w,gltf_joints[i3][2].w)*w.z;
trans += vec3(gltf_joints[i4][0].w,gltf_joints[i4][1].w,gltf_joints[i4][2].w)*w.w;
mat4 ret;
ret[0] = vec4(mat[0], 0);
ret[1] = vec4(mat[1], 0);
ret[2] = vec4(mat[2], 0);
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_MESH_OBJECT-1];
#endif
}
#endif
void main()
{
#ifdef HAS_SKIN
mat4 mat = getObjectSkinnedTransform();
mat4 mat = getGLTFSkinTransform();
mat = modelview_matrix * mat;
vec3 pos = (mat*vec4(position.xyz,1.0)).xyz;
vary_position = pos;
gl_Position = projection_matrix*vec4(pos,1.0);
vec4 vert = projection_matrix * vec4(pos, 1.0);
gl_Position = vert;
#else
vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz;
//transform vertex
gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
vec4 vert = modelview_projection_matrix * vec4(position.xyz, 1.0);
gl_Position = vert;
#endif
base_color_texcoord = texture_transform(texcoord0, texture_base_color_transform, texture_matrix0);
@ -99,6 +162,9 @@ void main()
vary_normal = n;
vertex_color = diffuse_color;
#ifdef ALPHA_BLEND
vary_fragcoord = vert.xyz;
#endif
}

View File

@ -1,24 +1,24 @@
/**
/**
* @file class1\deferred\pbralphaF.glsl
*
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2022, Linden Research, Inc.
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@ -87,7 +87,7 @@ vec4 applySkyAndWaterFog(vec3 pos, vec3 additive, vec3 atten, vec4 color);
void calcHalfVectors(vec3 lv, vec3 n, vec3 v, out vec3 h, out vec3 l, out float nh, out float nl, out float nv, out float vh, out float lightDist);
float calcLegacyDistanceAttenuation(float distance, float falloff);
float sampleDirectionalShadow(vec3 pos, vec3 norm, vec2 pos_screen);
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv,
vec2 tc, vec3 pos, vec3 norm, float glossiness, bool transparent, vec3 amblit_linear);
void mirrorClip(vec3 pos);
@ -111,15 +111,15 @@ vec3 pbrBaseLight(vec3 diffuseColor,
vec3 additive,
vec3 atten);
vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor,
float perceptualRoughness,
vec3 pbrPunctual(vec3 diffuseColor, vec3 specularColor,
float perceptualRoughness,
float metallic,
vec3 n, // normal
vec3 v, // surface point to camera
vec3 l); //surface point to light
vec3 calcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor,
float perceptualRoughness,
vec3 pbrCalcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor,
float perceptualRoughness,
float metallic,
vec3 n, // normal
vec3 p, // pixel position
@ -127,33 +127,7 @@ vec3 calcPointLightOrSpotLight(vec3 diffuseColor, vec3 specularColor,
vec3 lp, // light position
vec3 ld, // light direction (for spotlights)
vec3 lightColor,
float lightSize, float falloff, float is_pointlight, float ambiance)
{
vec3 color = vec3(0,0,0);
vec3 lv = lp.xyz - p;
float lightDist = length(lv);
float dist = lightDist / lightSize;
if (dist <= 1.0)
{
lv /= lightDist;
float dist_atten = calcLegacyDistanceAttenuation(dist, falloff);
// spotlight coefficient.
float spot = max(dot(-ld, lv), is_pointlight);
// spot*spot => GL_SPOT_EXPONENT=2
float spot_atten = spot*spot;
vec3 intensity = spot_atten * dist_atten * lightColor * 3.0; //magic number to balance with legacy materials
color = intensity*pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, n.xyz, v, lv);
}
return color;
}
float lightSize, float falloff, float is_pointlight, float ambiance);
void main()
{
@ -181,7 +155,7 @@ void main()
float sign = vary_sign;
vec3 vN = vary_normal;
vec3 vT = vary_tangent.xyz;
vec3 vB = sign * cross(vN, vT);
vec3 norm = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN );
@ -218,7 +192,7 @@ void main()
vec3 irradiance = vec3(0);
vec3 radiance = vec3(0);
sampleReflectionProbes(irradiance, radiance, vary_position.xy*0.5+0.5, pos.xyz, norm.xyz, gloss, true, amblit);
vec3 diffuseColor;
vec3 specularColor;
calcDiffuseSpecular(col.rgb, metallic, diffuseColor, specularColor);
@ -230,7 +204,7 @@ void main()
vec3 light = vec3(0);
// Punctual lights
#define LIGHT_LOOP(i) light += calcPointLightOrSpotLight(diffuseColor, specularColor, perceptualRoughness, metallic, norm.xyz, pos.xyz, v, light_position[i].xyz, light_direction[i].xyz, light_diffuse[i].rgb, light_deferred_attenuation[i].x, light_deferred_attenuation[i].y, light_attenuation[i].z, light_attenuation[i].w);
#define LIGHT_LOOP(i) light += pbrCalcPointLightOrSpotLight(diffuseColor, specularColor, perceptualRoughness, metallic, norm.xyz, pos.xyz, v, light_position[i].xyz, light_direction[i].xyz, light_diffuse[i].rgb, light_deferred_attenuation[i].x, light_deferred_attenuation[i].y, light_attenuation[i].z, light_attenuation[i].w);
LIGHT_LOOP(1)
LIGHT_LOOP(2)
@ -245,7 +219,7 @@ void main()
color.rgb = applySkyAndWaterFog(pos.xyz, additive, atten, vec4(color, 1.0)).rgb;
float a = basecolor.a*vertex_color.a;
frag_color = max(vec4(color.rgb,a), vec4(0));
}
@ -295,7 +269,7 @@ void main()
// emissiveMap here is a vanilla RGB texture encoded as sRGB, manually convert to linear
colorEmissive *= srgb_to_linear(texture(emissiveMap, emissive_texcoord.xy).rgb);
float a = basecolor.a*vertex_color.a;
color += colorEmissive;

View File

@ -77,7 +77,6 @@ uniform float is_mirror;
uniform vec3 sun_dir;
uniform vec3 moon_dir;
in vec2 vary_fragcoord;
uniform mat4 proj_mat;
uniform mat4 inv_proj;

View File

@ -132,7 +132,13 @@ bool Buffer::prep(Asset& asset)
{ // loaded from an asset, fetch the buffer data from the asset store
LLFileSystem file(id, LLAssetType::AT_GLTF_BIN, LLFileSystem::READ);
mData.resize(file.getSize());
if (mByteLength > file.getSize())
{
LL_WARNS("GLTF") << "Unexpected glbin size: " << id << " is " << file.getSize() << " bytes, expected " << mByteLength << LL_ENDL;
return false;
}
mData.resize(mByteLength);
if (!file.read((U8*)mData.data(), mData.size()))
{
LL_WARNS("GLTF") << "Failed to load buffer data from asset: " << id << LL_ENDL;

View File

@ -28,6 +28,7 @@
#include "asset.h"
#include "buffer_util.h"
#include "../llskinningutil.h"
using namespace LL::GLTF;
using namespace boost::json;
@ -362,6 +363,71 @@ const Animation& Animation::operator=(const Value& src)
return *this;
}
Skin::~Skin()
{
if (mUBO)
{
glDeleteBuffers(1, &mUBO);
}
}
void Skin::uploadMatrixPalette(Asset& asset)
{
// prepare matrix palette
U32 max_joints = LLSkinningUtil::getMaxGLTFJointCount();
if (mUBO == 0)
{
glGenBuffers(1, &mUBO);
}
U32 joint_count = llmin(max_joints, mJoints.size());
std::vector<mat4> t_mp;
t_mp.resize(joint_count);
for (U32 i = 0; i < joint_count; ++i)
{
Node& joint = asset.mNodes[mJoints[i]];
// build matrix palette in asset space
t_mp[i] = joint.mAssetMatrix * mInverseBindMatricesData[i];
}
std::vector<F32> glmp;
glmp.resize(joint_count * 12);
F32* mp = glmp.data();
for (U32 i = 0; i < joint_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];
}
glBindBuffer(GL_UNIFORM_BUFFER, mUBO);
glBufferData(GL_UNIFORM_BUFFER, glmp.size() * sizeof(F32), glmp.data(), GL_STREAM_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
bool Skin::prep(Asset& asset)
{
if (mInverseBindMatrices != INVALID_INDEX)

View File

@ -84,7 +84,7 @@ namespace LL
void Scene::updateTransforms(Asset& asset)
{
mat4 identity = glm::identity<mat4>();
for (auto& nodeIndex : mNodes)
{
Node& node = asset.mNodes[nodeIndex];
@ -116,7 +116,7 @@ void Node::updateTransforms(Asset& asset, const mat4& parentMatrix)
{
makeMatrixValid();
mAssetMatrix = parentMatrix * mMatrix;
mAssetMatrixInv = glm::inverse(mAssetMatrix);
S32 my_index = this - &asset.mNodes[0];
@ -356,94 +356,6 @@ const Image& Image::operator=(const Value& src)
return *this;
}
void Asset::render(bool opaque, bool rigged)
{
if (rigged)
{
gGL.loadIdentity();
}
for (auto& node : mNodes)
{
if (node.mSkin != INVALID_INDEX)
{
if (rigged)
{
Skin& skin = mSkins[node.mSkin];
skin.uploadMatrixPalette(*this, node);
}
else
{
//skip static nodes if we're rendering rigged
continue;
}
}
else if (rigged)
{
// skip rigged nodes if we're not rendering rigged
continue;
}
if (node.mMesh != INVALID_INDEX)
{
Mesh& mesh = mMeshes[node.mMesh];
for (auto& primitive : mesh.mPrimitives)
{
if (!rigged)
{
gGL.loadMatrix((F32*)glm::value_ptr(node.mRenderMatrix));
}
bool cull = true;
if (primitive.mMaterial != INVALID_INDEX)
{
Material& material = mMaterials[primitive.mMaterial];
bool mat_opaque = material.mAlphaMode != Material::AlphaMode::BLEND;
if (mat_opaque != opaque)
{
continue;
}
material.bind(*this);
cull = !material.mDoubleSided;
}
else
{
if (!opaque)
{
continue;
}
LLFetchedGLTFMaterial::sDefault.bind();
}
LLGLDisable cull_face(!cull ? GL_CULL_FACE : 0);
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());
}
}
}
}
}
void Asset::renderOpaque()
{
render(true);
}
void Asset::renderTransparent()
{
render(false);
}
void Asset::update()
{
F32 dt = gFrameTimeSeconds - mLastUpdateTime;
@ -461,6 +373,11 @@ void Asset::update()
}
updateTransforms();
for (auto& skin : mSkins)
{
skin.uploadMatrixPalette(*this);
}
}
}
@ -1063,90 +980,6 @@ bool Material::PbrMetallicRoughness::operator!=(const Material::PbrMetallicRough
return !(*this == rhs);
}
static void bindTexture(Asset& asset, S32 uniform, Material::TextureInfo& info, LLViewerTexture* fallback)
{
if (info.mIndex != INVALID_INDEX)
{
LLViewerTexture* tex = asset.mImages[asset.mTextures[info.mIndex].mSource].mTexture;
if (tex)
{
tex->addTextureStats(2048.f * 2048.f);
LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, tex);
}
else
{
LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, fallback);
}
}
else
{
LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, fallback);
}
}
void Material::bind(Asset& asset)
{
// 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;
LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
if (!LLPipeline::sShadowRender || (mAlphaMode == Material::AlphaMode::BLEND))
{
if (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 (mPbrMetallicRoughness.mBaseColorFactor.a > 0.f)
{
min_alpha = mAlphaCutoff / mPbrMetallicRoughness.mBaseColorFactor.a;
}
else
{
min_alpha = 1024.f;
}
}
shader->uniform1f(LLShaderMgr::MINIMUM_ALPHA, min_alpha);
}
bindTexture(asset, LLShaderMgr::DIFFUSE_MAP, mPbrMetallicRoughness.mBaseColorTexture, LLViewerFetchedTexture::sWhiteImagep);
F32 base_color_packed[8];
//mTextureTransform[GLTF_TEXTURE_INFO_BASE_COLOR].getPacked(base_color_packed);
LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR].getPacked(base_color_packed);
shader->uniform4fv(LLShaderMgr::TEXTURE_BASE_COLOR_TRANSFORM, 2, (F32*)base_color_packed);
if (!LLPipeline::sShadowRender)
{
bindTexture(asset, LLShaderMgr::BUMP_MAP, mNormalTexture, LLViewerFetchedTexture::sFlatNormalImagep);
bindTexture(asset, LLShaderMgr::SPECULAR_MAP, mPbrMetallicRoughness.mMetallicRoughnessTexture, LLViewerFetchedTexture::sWhiteImagep);
bindTexture(asset, LLShaderMgr::EMISSIVE_MAP, mEmissiveTexture, LLViewerFetchedTexture::sWhiteImagep);
// NOTE: base color factor is baked into vertex stream
shader->uniform1f(LLShaderMgr::ROUGHNESS_FACTOR, mPbrMetallicRoughness.mRoughnessFactor);
shader->uniform1f(LLShaderMgr::METALLIC_FACTOR, mPbrMetallicRoughness.mMetallicFactor);
shader->uniform3fv(LLShaderMgr::EMISSIVE_COLOR, 1, glm::value_ptr(mEmissiveFactor));
F32 normal_packed[8];
//mTextureTransform[GLTF_TEXTURE_INFO_NORMAL].getPacked(normal_packed);
LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL].getPacked(normal_packed);
shader->uniform4fv(LLShaderMgr::TEXTURE_NORMAL_TRANSFORM, 2, (F32*)normal_packed);
F32 metallic_roughness_packed[8];
//mTextureTransform[GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].getPacked(metallic_roughness_packed);
LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].getPacked(metallic_roughness_packed);
shader->uniform4fv(LLShaderMgr::TEXTURE_METALLIC_ROUGHNESS_TRANSFORM, 2, (F32*)metallic_roughness_packed);
F32 emissive_packed[8];
//mTextureTransform[GLTF_TEXTURE_INFO_EMISSIVE].getPacked(emissive_packed);
LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE].getPacked(emissive_packed);
shader->uniform4fv(LLShaderMgr::TEXTURE_EMISSIVE_TRANSFORM, 2, (F32*)emissive_packed);
}
}
void Material::serialize(object& dst) const
{
write(mName, "name", dst);
@ -1264,52 +1097,4 @@ const Sampler& Sampler::operator=(const Value& src)
return *this;
}
void Skin::uploadMatrixPalette(Asset& asset, Node& node)
{
// prepare matrix palette
// modelview will be applied by the shader, so assume matrix palette is in asset space
std::vector<mat4> t_mp;
t_mp.resize(mJoints.size());
for (U32 i = 0; i < mJoints.size(); ++i)
{
Node& joint = asset.mNodes[mJoints[i]];
t_mp[i] = joint.mRenderMatrix * mInverseBindMatricesData[i];
}
std::vector<F32> glmp;
glmp.resize(mJoints.size() * 12);
F32* mp = glmp.data();
for (U32 i = 0; i < mJoints.size(); ++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];
}
LLGLSLShader::sCurBoundShaderPtr->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX,
mJoints.size(),
GL_FALSE,
(GLfloat*)glmp.data());
}

View File

@ -118,8 +118,6 @@ namespace LL
F32 mAlphaCutoff = 0.5f;
bool mDoubleSided = false;
// bind for rendering
void bind(Asset& asset);
const Material& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
};
@ -197,14 +195,18 @@ namespace LL
class Skin
{
public:
~Skin();
S32 mInverseBindMatrices = INVALID_INDEX;
S32 mSkeleton = INVALID_INDEX;
U32 mUBO = 0;
std::vector<S32> mJoints;
std::string mName;
std::vector<mat4> mInverseBindMatricesData;
bool prep(Asset& asset);
void uploadMatrixPalette(Asset& asset, Node& node);
void uploadMatrixPalette(Asset& asset);
const Skin& operator=(const Value& src);
void serialize(boost::json::object& dst) const;
@ -332,10 +334,6 @@ namespace LL
// update node render transforms
void updateRenderTransforms(const mat4& modelview);
void render(bool opaque, bool rigged = false);
void renderOpaque();
void renderTransparent();
// 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
S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,

View File

@ -36,6 +36,7 @@
#include "glm/ext/quaternion_float.hpp"
#include "glm/gtx/quaternion.hpp"
#include "glm/gtx/matrix_decompose.hpp"
#include <boost/json.hpp>
// Common types and constants used in the GLTF implementation
namespace LL
@ -62,6 +63,21 @@ namespace LL
class Asset;
class Material;
class Mesh;
class Node;
class Scene;
class Texture;
class Sampler;
class Image;
class Animation;
class Skin;
class Camera;
class Light;
class Primitive;
class Accessor;
class BufferView;
class Buffer;
}
}

View File

@ -351,11 +351,18 @@ void GLTFSceneManager::onGLTFBinLoadComplete(const LLUUID& id, LLAssetType::ETyp
if (obj->mGLTFAsset->mPendingBuffers == 0)
{
obj->mGLTFAsset->prep();
GLTFSceneManager& mgr = GLTFSceneManager::instance();
if (std::find(mgr.mObjects.begin(), mgr.mObjects.end(), obj) == mgr.mObjects.end())
if (obj->mGLTFAsset->prep())
{
GLTFSceneManager::instance().mObjects.push_back(obj);
GLTFSceneManager& mgr = GLTFSceneManager::instance();
if (std::find(mgr.mObjects.begin(), mgr.mObjects.end(), obj) == mgr.mObjects.end())
{
GLTFSceneManager::instance().mObjects.push_back(obj);
}
}
else
{
LL_WARNS("GLTF") << "Failed to prepare GLTF asset: " << id << LL_ENDL;
obj->mGLTFAsset = nullptr;
}
}
}
@ -528,7 +535,6 @@ void GLTFSceneManager::render(bool opaque, bool rigged)
}
Asset* asset = mObjects[i]->mGLTFAsset.get();
gGL.pushMatrix();
LLMatrix4a mat = mObjects[i]->getGLTFAssetToAgentTransform();
@ -540,12 +546,195 @@ void GLTFSceneManager::render(bool opaque, bool rigged)
mat4 mdv = glm::make_mat4(modelview.getF32ptr());
asset->updateRenderTransforms(mdv);
asset->render(opaque, rigged);
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, opaque, rigged);
gGL.popMatrix();
}
}
void GLTFSceneManager::render(Asset& asset, bool opaque, bool rigged)
{
U32 variant = 0;
if (rigged)
{
variant |= LLGLSLShader::GLTFVariant::RIGGED;
}
if (!opaque)
{
variant |= LLGLSLShader::GLTFVariant::ALPHA;
}
if (opaque)
{
gGLTFPBRMetallicRoughnessProgram.bind(variant);
}
else
{ // alpha shaders need all the shadow map setup etc
gPipeline.bindDeferredShader(gGLTFPBRMetallicRoughnessProgram.mGLTFVariants[variant]);
}
for (auto& node : asset.mNodes)
{
if (node.mSkin != INVALID_INDEX)
{
if (rigged)
{
Skin& skin = asset.mSkins[node.mSkin];
glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_GLTF_JOINTS, skin.mUBO);
}
else
{
//skip static nodes if we're rendering rigged
continue;
}
}
else if (rigged)
{
// skip rigged nodes if we're not rendering rigged
continue;
}
if (node.mMesh != INVALID_INDEX)
{
Mesh& mesh = asset.mMeshes[node.mMesh];
for (auto& primitive : mesh.mPrimitives)
{
if (!rigged)
{
gGL.loadMatrix((F32*)glm::value_ptr(node.mRenderMatrix));
}
bool cull = true;
if (primitive.mMaterial != INVALID_INDEX)
{
Material& material = asset.mMaterials[primitive.mMaterial];
bool mat_opaque = material.mAlphaMode != Material::AlphaMode::BLEND;
if (mat_opaque != opaque)
{
continue;
}
bind(asset, material);
cull = !material.mDoubleSided;
}
else
{
if (!opaque)
{
continue;
}
LLFetchedGLTFMaterial::sDefault.bind();
}
LLGLDisable cull_face(!cull ? GL_CULL_FACE : 0);
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());
}
}
}
}
}
static void bindTexture(Asset& asset, S32 uniform, Material::TextureInfo& info, LLViewerTexture* fallback)
{
if (info.mIndex != INVALID_INDEX)
{
LLViewerTexture* tex = asset.mImages[asset.mTextures[info.mIndex].mSource].mTexture;
if (tex)
{
tex->addTextureStats(2048.f * 2048.f);
LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, tex);
}
else
{
LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, fallback);
}
}
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;
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 base_color_packed[8];
//mTextureTransform[GLTF_TEXTURE_INFO_BASE_COLOR].getPacked(base_color_packed);
LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR].getPacked(base_color_packed);
shader->uniform4fv(LLShaderMgr::TEXTURE_BASE_COLOR_TRANSFORM, 2, (F32*)base_color_packed);
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));
F32 normal_packed[8];
//mTextureTransform[GLTF_TEXTURE_INFO_NORMAL].getPacked(normal_packed);
LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL].getPacked(normal_packed);
shader->uniform4fv(LLShaderMgr::TEXTURE_NORMAL_TRANSFORM, 2, (F32*)normal_packed);
F32 metallic_roughness_packed[8];
//mTextureTransform[GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].getPacked(metallic_roughness_packed);
LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].getPacked(metallic_roughness_packed);
shader->uniform4fv(LLShaderMgr::TEXTURE_METALLIC_ROUGHNESS_TRANSFORM, 2, (F32*)metallic_roughness_packed);
F32 emissive_packed[8];
//mTextureTransform[GLTF_TEXTURE_INFO_EMISSIVE].getPacked(emissive_packed);
LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE].getPacked(emissive_packed);
shader->uniform4fv(LLShaderMgr::TEXTURE_EMISSIVE_TRANSFORM, 2, (F32*)emissive_packed);
}
}
LLMatrix4a inverse(const LLMatrix4a& mat)
{
glh::matrix4f m((F32*)mat.mMatrix);

View File

@ -28,17 +28,11 @@
#include "llsingleton.h"
#include "llviewerobject.h"
#include "gltf/common.h"
class LLVOVolume;
class LLDrawable;
namespace LL
{
namespace GLTF
{
class Asset;
}
}
namespace LL
{
class GLTFSceneManager : public LLSimpleton<GLTFSceneManager>
@ -56,6 +50,11 @@ namespace LL
void update();
void render(bool opaque, bool rigged = false);
void render(LL::GLTF::Asset& asset, bool opaque, bool rigged);
// bind the given material for rendering
void bind(LL::GLTF::Asset& asset, LL::GLTF::Material& material);
void renderOpaque();
void renderAlpha();
@ -71,7 +70,7 @@ namespace LL
LLVector4a* normal, // return the surface normal at the intersection point
LLVector4a* tangent); // return the surface tangent at the intersection point
bool lineSegmentIntersect(LLVOVolume* obj, GLTF::Asset* asset, const LLVector4a& start, const LLVector4a& end, S32 face, bool pick_transparent, bool pick_rigged, bool pick_unselectable, S32* face_hitp, S32* primitive_hitp,
bool lineSegmentIntersect(LLVOVolume* obj, LL::GLTF::Asset* asset, const LLVector4a& start, const LLVector4a& end, S32 face, bool pick_transparent, bool pick_rigged, bool pick_unselectable, S32* face_hitp, S32* primitive_hitp,
LLVector4a* intersection, LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent);
void renderDebug();
@ -88,6 +87,8 @@ namespace LL
U32 mPendingImageUploads = 0;
U32 mPendingBinaryUploads = 0;
U32 mPendingGLTFUploads = 0;
U32 mJointUBO = 0;
};
}

View File

@ -263,10 +263,7 @@ void LLDrawPoolAlpha::forwardRender(bool rigged)
if (rigged)
{ // draw GLTF scene to depth buffer before rigged alpha
gPipeline.bindDeferredShader(gDeferredPBRAlphaProgram);
LL::GLTFSceneManager::instance().render(false, false);
gPipeline.bindDeferredShader(*gDeferredPBRAlphaProgram.mRiggedVariant);
LL::GLTFSceneManager::instance().render(false, true);
}

View File

@ -555,7 +555,7 @@ void LLDrawPoolAvatar::beginDeferredImpostor()
sVertexProgram = &gDeferredImpostorProgram;
specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::NORMAL_MAP);
sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
sVertexProgram->bind();
sVertexProgram->setMinimumAlpha(0.01f);
@ -566,7 +566,7 @@ void LLDrawPoolAvatar::endDeferredImpostor()
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR
sShaderLevel = mShaderLevel;
sVertexProgram->disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
sVertexProgram->disableTexture(LLViewerShaderMgr::NORMAL_MAP);
sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP);
sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
gPipeline.unbindDeferredShader(*sVertexProgram);

View File

@ -1,25 +1,25 @@
/**
/**
* @file lldrawpoolpbropaque.cpp
* @brief LLDrawPoolGLTFPBR class implementation
*
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2022, Linden Research, Inc.
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@ -54,11 +54,10 @@ void LLDrawPoolGLTFPBR::renderDeferred(S32 pass)
{
llassert(!LLPipeline::sRenderingHUDs);
gDeferredPBROpaqueProgram.bind();
LL::GLTFSceneManager::instance().renderOpaque();
pushGLTFBatches(mRenderType);
gDeferredPBROpaqueProgram.bind();
pushGLTFBatches(mRenderType);
gDeferredPBROpaqueProgram.bind(true);
LL::GLTFSceneManager::instance().render(true, true);

View File

@ -1680,15 +1680,15 @@ void LLEnvironment::update(const LLViewerCamera * cam)
end_shaders = LLViewerShaderMgr::instance()->endShaders();
for (shaders_iter = LLViewerShaderMgr::instance()->beginShaders(); shaders_iter != end_shaders; ++shaders_iter)
{
if ((shaders_iter->mProgramObject != 0)
&& (gPipeline.canUseWindLightShaders()
|| shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER))
shaders_iter->mUniformsDirty = true;
if (shaders_iter->mRiggedVariant)
{
shaders_iter->mUniformsDirty = true;
if (shaders_iter->mRiggedVariant)
{
shaders_iter->mRiggedVariant->mUniformsDirty = true;
}
shaders_iter->mRiggedVariant->mUniformsDirty = true;
}
for (auto& variant : shaders_iter->mGLTFVariants)
{
variant.mUniformsDirty = true;
}
}
}

View File

@ -67,7 +67,7 @@ void load_exr(const std::string& filename)
const char* err = NULL; // or nullptr in C++11
int ret = LoadEXRWithLayer(&out, &width, &height, filename.c_str(), /* layername */ nullptr, &err);
if (ret == TINYEXR_SUCCESS)
if (ret == TINYEXR_SUCCESS)
{
U32 texName = 0;
LLImageGL::generateTextures(1, &texName);
@ -87,12 +87,12 @@ void load_exr(const std::string& filename)
gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
}
else
else
{
LLSD notif_args;
notif_args["WHAT"] = filename;
notif_args["REASON"] = "Unknown";
if (err)
if (err)
{
notif_args["REASON"] = std::string(err);
FreeEXRErrorMessage(err); // release memory of error message.
@ -231,7 +231,7 @@ void LLReflectionMapManager::update()
{
U32 res = mProbeResolution;
U32 count = log2((F32)res) + 0.5f;
mMipChain.resize(count);
for (int i = 0; i < count; ++i)
{
@ -241,7 +241,7 @@ void LLReflectionMapManager::update()
}
llassert(mProbes[0] == mDefaultProbe);
LLVector4a camera_pos;
camera_pos.load3(LLViewerCamera::instance().getOrigin().mV);
@ -256,7 +256,7 @@ void LLReflectionMapManager::update()
}
mKillList.clear();
// process create list
for (auto& probe : mCreateList)
{
@ -272,12 +272,12 @@ void LLReflectionMapManager::update()
bool did_update = false;
static LLCachedControl<S32> sDetail(gSavedSettings, "RenderReflectionProbeDetail", -1);
static LLCachedControl<S32> sLevel(gSavedSettings, "RenderReflectionProbeLevel", 3);
bool realtime = sDetail >= (S32)LLReflectionMapManager::DetailLevel::REALTIME;
LLReflectionMap* closestDynamic = nullptr;
LLReflectionMap* oldestProbe = nullptr;
@ -339,7 +339,7 @@ void LLReflectionMapManager::update()
--i;
continue;
}
if (probe != mDefaultProbe &&
(!probe->isRelevant() || mPaused))
{ // skip irrelevant probes (or all non-default probes if paused)
@ -442,7 +442,7 @@ void LLReflectionMapManager::update()
{
LLReflectionMap* probe = oldestProbe;
llassert(probe->mCubeIndex != -1);
probe->autoAdjustOrigin();
sUpdateCount++;
@ -636,7 +636,7 @@ void LLReflectionMapManager::doProbeUpdate()
llassert(mUpdatingProbe != nullptr);
updateProbeFace(mUpdatingProbe, mUpdatingFace);
bool debug_updates = gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PROBE_UPDATES) && mUpdatingProbe->mViewerObject;
if (++mUpdatingFace == 6)
@ -689,11 +689,11 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face)
touch_default_probe(probe);
gPipeline.pushRenderTypeMask();
//only render sky, water, terrain, and clouds
gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY, LLPipeline::RENDER_TYPE_WL_SKY,
LLPipeline::RENDER_TYPE_WATER, LLPipeline::RENDER_TYPE_VOIDWATER, LLPipeline::RENDER_TYPE_CLOUDS, LLPipeline::RENDER_TYPE_TERRAIN, LLPipeline::END_RENDER_TYPES);
probe->update(mRenderTarget.getWidth(), face);
gPipeline.popRenderTypeMask();
@ -702,7 +702,7 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face)
{
probe->update(mRenderTarget.getWidth(), face);
}
gPipeline.mRT = &gPipeline.mMainRT;
S32 sourceIdx = mReflectionProbeCount;
@ -779,12 +779,12 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face)
gGL.getTexUnit(diffuseChannel)->bind(&(mMipChain[i - 1]));
}
gReflectionMipProgram.uniform1f(resScale, 1.f/(mProbeResolution*2));
gPipeline.mScreenTriangleVB->setBuffer();
gPipeline.mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);
res /= 2;
S32 mip = i - (mMipChain.size() - mips);
@ -874,7 +874,7 @@ void LLReflectionMapManager::updateProbeFace(LLReflectionMap* probe, U32 face)
gIrradianceGenProgram.uniform1i(sSourceIdx, sourceIdx);
gIrradianceGenProgram.uniform1f(LLShaderMgr::REFLECTION_PROBE_MAX_LOD, mMaxProbeLOD);
mVertexBuffer->setBuffer();
int start_mip = 0;
// find the mip target to start with based on irradiance map resolution
@ -951,7 +951,7 @@ void LLReflectionMapManager::updateNeighbors(LLReflectionMap* probe)
//remove from existing neighbors
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmun - clear");
for (auto& other : probe->mNeighbors)
{
auto const & iter = std::find(other->mNeighbors.begin(), other->mNeighbors.end(), probe);
@ -1063,7 +1063,7 @@ void LLReflectionMapManager::updateUniforms()
bool is_ambiance_pass = gCubeSnapshot && !isRadiancePass();
F32 ambscale = is_ambiance_pass ? 0.f : 1.f;
F32 radscale = is_ambiance_pass ? 0.5f : 1.f;
for (auto* refmap : mReflectionMaps)
{
if (refmap == nullptr)
@ -1194,7 +1194,7 @@ void LLReflectionMapManager::updateUniforms()
{
// fill in gaps in refBucket
S32 probe_idx = mReflectionProbeCount;
for (int i = 0; i < 256; ++i)
{
if (i < count)
@ -1266,7 +1266,7 @@ void LLReflectionMapManager::setUniforms()
{
updateUniforms();
}
glBindBufferBase(GL_UNIFORM_BUFFER, 1, mUBO);
glBindBufferBase(GL_UNIFORM_BUFFER, LLGLSLShader::UB_REFLECTION_PROBES, mUBO);
}
@ -1441,9 +1441,9 @@ void LLReflectionMapManager::initReflectionMaps()
buff->allocateBuffer(4, 0);
LLStrider<LLVector3> v;
buff->getVertexStrider(v);
v[0] = LLVector3(-1, -1, -1);
v[1] = LLVector3(1, -1, -1);
v[2] = LLVector3(-1, 1, -1);
@ -1471,7 +1471,7 @@ void LLReflectionMapManager::cleanup()
mReflectionMaps.clear();
mUpdatingFace = 0;
mDefaultProbe = nullptr;
mUpdatingProbe = nullptr;

View File

@ -97,6 +97,12 @@ U32 LLSkinningUtil::getMeshJointCount(const LLMeshSkinInfo *skin)
return llmin((U32)getMaxJointCount(), (U32)skin->mJointNames.size());
}
S32 LLSkinningUtil::getMaxGLTFJointCount()
{
// this is the maximum number of 3x4 matrices than can fit in a UBO
return gGLManager.mMaxUniformBlockSize / 48;
}
void LLSkinningUtil::scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin)
{
if (skin->mInvalidJointsScrubbed)

View File

@ -40,6 +40,7 @@ class LLJointRiggingInfoTab;
namespace LLSkinningUtil
{
S32 getMaxJointCount();
S32 getMaxGLTFJointCount();
U32 getMeshJointCount(const LLMeshSkinInfo *skin);
void scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin);
void initSkinningMatrixPalette(LLMatrix4a* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar *avatar);

View File

@ -249,7 +249,7 @@ static bool make_rigged_variant(LLGLSLShader& shader, LLGLSLShader& riggedShader
}
static bool make_gltf_variant(LLGLSLShader& shader, LLGLSLShader& variant, bool alpha_blend, bool rigged)
static bool make_gltf_variant(LLGLSLShader& shader, LLGLSLShader& variant, bool alpha_blend, bool rigged, bool use_sun_shadow)
{
variant.mName = shader.mName.c_str();
variant.mFeatures = shader.mFeatures;
@ -259,20 +259,50 @@ static bool make_gltf_variant(LLGLSLShader& shader, LLGLSLShader& variant, bool
variant.mDefines = shader.mDefines; // NOTE: Must come before addPermutation
if (alpha_blend)
{
variant.addPermutation("ALPHA_BLEND", "1");
}
variant.addPermutation("MAX_JOINTS_PER_GLTF_OBJECT", std::to_string(LLSkinningUtil::getMaxGLTFJointCount()));
if (rigged)
{
variant.addPermutation("HAS_SKIN", "1");
variant.mFeatures.hasObjectSkinning = true;
}
return variant.createShader(NULL, NULL);
if (alpha_blend)
{
variant.addPermutation("ALPHA_BLEND", "1");
variant.mFeatures.calculatesLighting = false;
variant.mFeatures.hasLighting = false;
variant.mFeatures.isAlphaLighting = true;
variant.mFeatures.hasSrgb = true;
variant.mFeatures.calculatesAtmospherics = true;
variant.mFeatures.hasAtmospherics = true;
variant.mFeatures.hasGamma = true;
variant.mFeatures.hasShadows = use_sun_shadow;
variant.mFeatures.isDeferred = true; // include deferredUtils
variant.mFeatures.hasReflectionProbes = true;
if (use_sun_shadow)
{
variant.addPermutation("HAS_SUN_SHADOW", "1");
}
bool success = variant.createShader(NULL, NULL);
llassert(success);
// Alpha Shader Hack
// See: LLRender::syncMatrices()
variant.mFeatures.calculatesLighting = true;
variant.mFeatures.hasLighting = true;
return success;
}
else
{
return variant.createShader(NULL, NULL);
}
}
static bool make_gltf_variants(LLGLSLShader& shader)
static bool make_gltf_variants(LLGLSLShader& shader, bool use_sun_shadow)
{
shader.mFeatures.mGLTF = true;
shader.mGLTFVariants.resize(LLGLSLShader::NUM_GLTF_VARIANTS);
@ -282,7 +312,7 @@ static bool make_gltf_variants(LLGLSLShader& shader)
bool alpha_blend = i & 1;
bool rigged = i & 2;
if (!make_gltf_variant(shader, shader.mGLTFVariants[i], alpha_blend, rigged))
if (!make_gltf_variant(shader, shader.mGLTFVariants[i], alpha_blend, rigged, use_sun_shadow))
{
return false;
}
@ -1269,7 +1299,7 @@ bool LLViewerShaderMgr::loadShadersDeferred()
gGLTFPBRMetallicRoughnessProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED];
gGLTFPBRMetallicRoughnessProgram.clearPermutations();
success = make_gltf_variants(gGLTFPBRMetallicRoughnessProgram);
success = make_gltf_variants(gGLTFPBRMetallicRoughnessProgram, use_sun_shadow);
llassert(success);
}

View File

@ -287,6 +287,9 @@ extern LLGLSLShader gDeferredPBROpaqueProgram;
extern LLGLSLShader gDeferredPBRAlphaProgram;
extern LLGLSLShader gHUDPBRAlphaProgram;
// GLTF shaders
extern LLGLSLShader gGLTFPBRMetallicRoughnessProgram;
// Encodes detail level for dropping textures, in accordance with the GLTF spec where possible
// 0 is highest detail, -1 drops emissive, etc
// Dropping metallic roughness is off-spec - Reserve for potato machines as needed

View File

@ -6825,7 +6825,7 @@ void LLPipeline::generateLuminance(LLRenderTarget* src, LLRenderTarget* dst)
mGlow[1].bindTexture(0, channel);
}
channel = gLuminanceProgram.enableTexture(LLShaderMgr::DEFERRED_NORMAL);
channel = gLuminanceProgram.enableTexture(LLShaderMgr::NORMAL_MAP);
if (channel > -1)
{
// bind the normal map to get the environment mask
@ -7632,7 +7632,7 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_
gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
}
channel = shader.enableTexture(LLShaderMgr::DEFERRED_NORMAL, deferred_target->getUsage());
channel = shader.enableTexture(LLShaderMgr::NORMAL_MAP, deferred_target->getUsage());
if (channel > -1)
{
deferred_target->bindTexture(2, channel, LLTexUnit::TFO_POINT); // frag_data[2]
@ -8667,7 +8667,7 @@ void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
LLRenderTarget* deferred_light_target = &mRT->deferredLight;
stop_glerror();
shader.disableTexture(LLShaderMgr::DEFERRED_NORMAL, deferred_target->getUsage());
shader.disableTexture(LLShaderMgr::NORMAL_MAP, deferred_target->getUsage());
shader.disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, deferred_target->getUsage());
shader.disableTexture(LLShaderMgr::DEFERRED_SPECULAR, deferred_target->getUsage());
shader.disableTexture(LLShaderMgr::DEFERRED_EMISSIVE, deferred_target->getUsage());