* 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 assetsmaster
parent
2d0fe5ca7b
commit
15fd13f830
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ public:
|
|||
S32 mGLMaxIndexRange;
|
||||
S32 mGLMaxTextureSize;
|
||||
F32 mMaxAnisotropy = 0.f;
|
||||
S32 mMaxUniformBlockSize = 0;
|
||||
|
||||
// GL 4.x capabilities
|
||||
bool mHasCubeMapArray = false;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
Loading…
Reference in New Issue