diff options
author | Dave Parks <davep@lindenlab.com> | 2024-06-11 17:10:13 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-11 17:10:13 -0500 |
commit | f40fbdf4ad27a547e30781cd44cd6847d68d3300 (patch) | |
tree | b26dd135413752a90037bd48ad2217c4dea027ef /indra | |
parent | 429c92ad75fd3b3f7b9dfc52ed034b25004a3b9c (diff) |
#1718 Add GLTF support for multiple texcoords (#1720)
* Fix for GLTF MeshPrimitiveModes test
Diffstat (limited to 'indra')
-rw-r--r-- | indra/llrender/llglslshader.h | 4 | ||||
-rw-r--r-- | indra/llrender/llrender.cpp | 2 | ||||
-rw-r--r-- | indra/llrender/llshadermgr.cpp | 5 | ||||
-rw-r--r-- | indra/llrender/llshadermgr.h | 5 | ||||
-rw-r--r-- | indra/llrender/llvertexbuffer.cpp | 10 | ||||
-rw-r--r-- | indra/llrender/llvertexbuffer.h | 3 | ||||
-rw-r--r-- | indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl | 20 | ||||
-rw-r--r-- | indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl | 92 | ||||
-rw-r--r-- | indra/newview/gltf/asset.cpp | 20 | ||||
-rw-r--r-- | indra/newview/gltf/asset.h | 6 | ||||
-rw-r--r-- | indra/newview/gltf/buffer_util.h | 2 | ||||
-rw-r--r-- | indra/newview/gltf/primitive.cpp | 201 | ||||
-rw-r--r-- | indra/newview/gltf/primitive.h | 3 | ||||
-rw-r--r-- | indra/newview/gltfscenemanager.cpp | 19 | ||||
-rw-r--r-- | indra/newview/llviewershadermgr.cpp | 10 |
15 files changed, 318 insertions, 84 deletions
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index f2b5c4881c..d42df28809 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -328,14 +328,16 @@ public: // bit 0 = alpha mode blend (1) or opaque (0) // bit 1 = rigged (1) or static (0) // bit 2 = unlit (1) or lit (0) + // bit 3 = single (0) or multi (1) uv coordinates struct GLTFVariant { constexpr static U8 ALPHA_BLEND = 1; constexpr static U8 RIGGED = 2; constexpr static U8 UNLIT = 4; + constexpr static U8 MULTI_UV = 8; }; - constexpr static U8 NUM_GLTF_VARIANTS = 8; + constexpr static U8 NUM_GLTF_VARIANTS = 16; std::vector<LLGLSLShader> mGLTFVariants; diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 51028e5667..cfefde3acc 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -1686,7 +1686,7 @@ void LLRender::flush() if (attribute_mask & LLVertexBuffer::MAP_TEXCOORD0) { - vb->setTexCoordData(mTexcoordsp.get()); + vb->setTexCoord0Data(mTexcoordsp.get()); } if (attribute_mask & LLVertexBuffer::MAP_COLOR) diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 5f30fc3879..6f4454f07a 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1180,6 +1180,11 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("texture_metallic_roughness_transform"); // (GLTF) mReservedUniforms.push_back("texture_occlusion_transform"); // (GLTF) mReservedUniforms.push_back("texture_emissive_transform"); // (GLTF) + mReservedUniforms.push_back("base_color_texcoord"); // (GLTF) + mReservedUniforms.push_back("emissive_texcoord"); // (GLTF) + mReservedUniforms.push_back("normal_texcoord"); // (GLTF) + mReservedUniforms.push_back("metallic_roughness_texcoord"); // (GLTF) + mReservedUniforms.push_back("occlusion_texcoord"); // (GLTF) mReservedUniforms.push_back("terrain_texture_transforms"); // (GLTF) diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 244fc41de6..c00aff3a9a 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -58,6 +58,11 @@ public: TEXTURE_METALLIC_ROUGHNESS_TRANSFORM, // "texture_metallic_roughness_transform" (GLTF) TEXTURE_OCCLUSION_TRANSFORM, // "texture_occlusion_transform" (GLTF) TEXTURE_EMISSIVE_TRANSFORM, // "texture_emissive_transform" (GLTF) + BASE_COLOR_TEXCOORD, // "base_color_texcoord" (GLTF) + EMISSIVE_TEXCOORD, // "emissive_texcoord" (GLTF) + NORMAL_TEXCOORD, // "normal_texcoord" (GLTF) + METALLIC_ROUGHNESS_TEXCOORD, // "metallic_roughness_texcoord" (GLTF) + OCCLUSION_TEXCOORD, // "occlusion_texcoord" (GLTF) TERRAIN_TEXTURE_TRANSFORMS, // "terrain_texture_transforms" (GLTF) diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index a4d33c91df..33f7a6527f 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -1635,7 +1635,7 @@ void LLVertexBuffer::setPositionData(const LLVector4a* data) flush_vbo(GL_ARRAY_BUFFER, 0, sizeof(LLVector4a) * getNumVerts()-1, (U8*) data, mMappedData); } -void LLVertexBuffer::setTexCoordData(const LLVector2* data) +void LLVertexBuffer::setTexCoord0Data(const LLVector2* data) { #if !LL_DARWIN llassert(sGLRenderBuffer == mGLBuffer); @@ -1643,6 +1643,14 @@ void LLVertexBuffer::setTexCoordData(const LLVector2* data) flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD0], mOffsets[TYPE_TEXCOORD0] + sTypeSize[TYPE_TEXCOORD0] * getNumVerts() - 1, (U8*)data, mMappedData); } +void LLVertexBuffer::setTexCoord1Data(const LLVector2* data) +{ +#if !LL_DARWIN + llassert(sGLRenderBuffer == mGLBuffer); +#endif + flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD1], mOffsets[TYPE_TEXCOORD1] + sTypeSize[TYPE_TEXCOORD1] * getNumVerts() - 1, (U8*)data, mMappedData); +} + void LLVertexBuffer::setColorData(const LLColor4U* data) { #if !LL_DARWIN diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index 94339191a4..66a7f2bf26 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -196,7 +196,8 @@ public: void setTangentData(const LLVector4a* data); void setWeight4Data(const LLVector4a* data); void setJointData(const U64* data); - void setTexCoordData(const LLVector2* data); + void setTexCoord0Data(const LLVector2* data); + void setTexCoord1Data(const LLVector2* data); void setColorData(const LLColor4U* data); void setIndexData(const U16* data); void setIndexData(const U32* data); diff --git a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl index 99bfcf70fa..789c00259b 100644 --- a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl +++ b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessF.glsl @@ -37,8 +37,8 @@ uniform sampler2D emissiveMap; uniform vec3 emissiveColor; in vec3 vary_position; in vec4 vertex_color; -in vec2 base_color_texcoord; -in vec2 emissive_texcoord; +in vec2 base_color_uv; +in vec2 emissive_uv; uniform float minimum_alpha; void mirrorClip(vec3 pos); @@ -59,9 +59,9 @@ uniform float roughnessFactor; in vec3 vary_normal; in vec3 vary_tangent; flat in float vary_sign; -in vec2 normal_texcoord; -in vec2 metallic_roughness_texcoord; -in vec2 occlusion_texcoord; +in vec2 normal_uv; +in vec2 metallic_roughness_uv; +in vec2 occlusion_uv; #endif // ================================== @@ -165,7 +165,7 @@ void main() vec3 pos = vary_position; mirrorClip(pos); - vec4 basecolor = texture(diffuseMap, base_color_texcoord.xy).rgba; + vec4 basecolor = texture(diffuseMap, base_color_uv.xy).rgba; basecolor.rgb = srgb_to_linear(basecolor.rgb); basecolor *= vertex_color; @@ -175,7 +175,7 @@ void main() } vec3 emissive = emissiveColor; - emissive *= srgb_to_linear(texture(emissiveMap, emissive_texcoord.xy).rgb); + emissive *= srgb_to_linear(texture(emissiveMap, emissive_uv.xy).rgb); // ================================== // ================================== @@ -185,7 +185,7 @@ void main() // ================================== #ifndef UNLIT // from mikktspace.com - vec3 vNt = texture(normalMap, normal_texcoord.xy).xyz*2.0-1.0; + vec3 vNt = texture(normalMap, normal_uv.xy).xyz*2.0-1.0; float sign = vary_sign; vec3 vN = vary_normal; vec3 vT = vary_tangent.xyz; @@ -199,8 +199,8 @@ void main() // occlusion 1.0 // roughness 0.0 // metal 0.0 - vec3 orm = texture(metallicRoughnessMap, metallic_roughness_texcoord.xy).rgb; - orm.r = texture(occlusionMap, occlusion_texcoord.xy).r; + vec3 orm = texture(metallicRoughnessMap, metallic_roughness_uv.xy).rgb; + orm.r = texture(occlusionMap, occlusion_uv.xy).r; orm.g *= roughnessFactor; orm.b *= metallicFactor; #endif diff --git a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl index bc9a47d41e..aac3dc917f 100644 --- a/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl +++ b/indra/newview/app_settings/shaders/class1/gltf/pbrmetallicroughnessV.glsl @@ -33,7 +33,6 @@ uniform mat4 projection_matrix; uniform mat3 normal_matrix; uniform mat4 modelview_projection_matrix; #endif -uniform mat4 texture_matrix0; uniform vec4[2] texture_base_color_transform; uniform vec4[2] texture_normal_transform; @@ -44,21 +43,31 @@ uniform vec4[2] texture_occlusion_transform; in vec3 position; in vec4 diffuse_color; in vec2 texcoord0; -out vec2 base_color_texcoord; -out vec2 emissive_texcoord; +out vec2 base_color_uv; +out vec2 emissive_uv; out vec4 vertex_color; out vec3 vary_position; #ifndef UNLIT in vec3 normal; in vec4 tangent; -out vec2 normal_texcoord; -out vec2 metallic_roughness_texcoord; -out vec2 occlusion_texcoord; +out vec2 normal_uv; +out vec2 metallic_roughness_uv; +out vec2 occlusion_uv; out vec3 vary_tangent; flat out float vary_sign; out vec3 vary_normal; -vec3 tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); +#endif + +#ifdef MULTI_UV +in vec2 texcoord1; +uniform int base_color_texcoord; +uniform int emissive_texcoord; +#ifndef UNLIT +uniform int normal_texcoord; +uniform int metallic_roughness_texcoord; +uniform int occlusion_texcoord; +#endif #endif vec2 gltf_texture_transform(vec2 texcoord, vec4[2] p) @@ -86,6 +95,36 @@ vec2 gltf_texture_transform(vec2 texcoord, vec4[2] p) return uvTransformed; } +#ifndef UNLIT +vec3 gltf_tangent_space_transform(vec4 vertex_tangent, vec3 vertex_normal, vec4[2] khr_gltf_transform) +{ //derived from tangent_space_transform in textureUtilV.glsl + vec2 weights = vec2(0, 1); + + // Convert to left-handed coordinate system + weights.y = -weights.y; + + // Apply KHR_texture_transform (rotation only) + float khr_rotation = khr_gltf_transform[0].z; + mat2 khr_rotation_mat = mat2( + cos(khr_rotation),-sin(khr_rotation), + sin(khr_rotation), cos(khr_rotation) + ); + weights = khr_rotation_mat * weights; + + // Convert back to right-handed coordinate system + weights.y = -weights.y; + + // Similar to the MikkTSpace-compatible method of extracting the binormal + // from the normal and tangent, as seen in the fragment shader + vec3 vertex_binormal = vertex_tangent.w * cross(vertex_normal, vertex_tangent.xyz); + + return (weights.x * vertex_binormal.xyz) + (weights.y * vertex_tangent.xyz); + + return vertex_tangent.xyz; +} +#endif + + #ifdef ALPHA_BLEND out vec3 vary_fragcoord; @@ -161,13 +200,40 @@ void main() gl_Position = vert; #endif - base_color_texcoord = gltf_texture_transform(texcoord0, texture_base_color_transform); - emissive_texcoord = gltf_texture_transform(texcoord0, texture_emissive_transform); + vec2 bcuv; + vec2 emuv; + +#ifdef MULTI_UV + vec2 uv[2]; + uv[0] = texcoord0; + uv[1] = texcoord1; + + bcuv = uv[base_color_texcoord]; + emuv = uv[emissive_texcoord]; +#else + bcuv = texcoord0; + emuv = texcoord0; +#endif + + base_color_uv = gltf_texture_transform(bcuv, texture_base_color_transform); + emissive_uv = gltf_texture_transform(emuv, texture_emissive_transform); #ifndef UNLIT - normal_texcoord = gltf_texture_transform(texcoord0, texture_normal_transform); - metallic_roughness_texcoord = gltf_texture_transform(texcoord0, texture_metallic_roughness_transform); - occlusion_texcoord = gltf_texture_transform(texcoord0, texture_occlusion_transform); + vec2 normuv; + vec2 rmuv; + vec2 ouv; +#ifdef MULTI_UV + normuv = uv[normal_texcoord]; + rmuv = uv[metallic_roughness_texcoord]; + ouv = uv[occlusion_texcoord]; +#else + normuv = texcoord0; + rmuv = texcoord0; + ouv = texcoord0; +#endif + normal_uv = gltf_texture_transform(normuv, texture_normal_transform); + metallic_roughness_uv = gltf_texture_transform(rmuv, texture_metallic_roughness_transform); + occlusion_uv = gltf_texture_transform(ouv, texture_occlusion_transform); #endif #ifndef UNLIT @@ -180,7 +246,7 @@ void main() #endif n = normalize(n); - vary_tangent = normalize(tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform, texture_matrix0)); + vary_tangent = normalize(gltf_tangent_space_transform(vec4(t, tangent.w), n, texture_normal_transform)); vary_sign = tangent.w; vary_normal = n; #endif diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index 4c1da3e645..21be69aae2 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -910,6 +910,24 @@ void Material::TextureInfo::serialize(object& dst) const write_extensions(dst, &mTextureTransform, "KHR_texture_transform"); } +S32 Material::TextureInfo::getTexCoord() const +{ + if (mTextureTransform.mPresent && mTextureTransform.mTexCoord != INVALID_INDEX) + { + return mTextureTransform.mTexCoord; + } + return mTexCoord; +} + +bool Material::isMultiUV() const +{ + return mPbrMetallicRoughness.mBaseColorTexture.getTexCoord() != 0 || + mPbrMetallicRoughness.mMetallicRoughnessTexture.getTexCoord() != 0 || + mNormalTexture.getTexCoord() != 0 || + mOcclusionTexture.getTexCoord() != 0 || + mEmissiveTexture.getTexCoord() != 0; +} + const Material::TextureInfo& Material::TextureInfo::operator=(const Value& src) { if (src.is_object()) @@ -1048,7 +1066,7 @@ void TextureTransform::serialize(object& dst) const write(mOffset, "offset", dst, vec2(0.f, 0.f)); write(mRotation, "rotation", dst, 0.f); write(mScale, "scale", dst, vec2(1.f, 1.f)); - write(mTexCoord, "texCoord", dst, 0); + write(mTexCoord, "texCoord", dst, -1); } diff --git a/indra/newview/gltf/asset.h b/indra/newview/gltf/asset.h index bca269d5dc..ea3f7d480a 100644 --- a/indra/newview/gltf/asset.h +++ b/indra/newview/gltf/asset.h @@ -102,6 +102,10 @@ namespace LL bool operator==(const TextureInfo& rhs) const; bool operator!=(const TextureInfo& rhs) const; + // get the UV channel that should be used for sampling this texture + // returns mTextureTransform.mTexCoord if present and valid, otherwise mTexCoord + S32 getTexCoord() const; + const TextureInfo& operator=(const Value& src); void serialize(boost::json::object& dst) const; }; @@ -152,6 +156,8 @@ namespace LL bool mDoubleSided = false; Unlit mUnlit; + bool isMultiUV() const; + const Material& operator=(const Value& src); void serialize(boost::json::object& dst) const; }; diff --git a/indra/newview/gltf/buffer_util.h b/indra/newview/gltf/buffer_util.h index 943a1748f9..c1101818b7 100644 --- a/indra/newview/gltf/buffer_util.h +++ b/indra/newview/gltf/buffer_util.h @@ -826,7 +826,7 @@ namespace LL if (arr.size() == 2) { std::error_code ec; - vec3 t; + vec2 t; t.x = arr[0].to_number<F32>(ec); if (ec) return false; t.y = arr[1].to_number<F32>(ec); if (ec) return false; diff --git a/indra/newview/gltf/primitive.cpp b/indra/newview/gltf/primitive.cpp index bc333aff69..4cff0622b3 100644 --- a/indra/newview/gltf/primitive.cpp +++ b/indra/newview/gltf/primitive.cpp @@ -42,13 +42,14 @@ using namespace boost::json; // Mesh data useful for Mikktspace tangent generation (and flat normal generation) struct MikktMesh { - std::vector<LLVector3> p; - std::vector<LLVector3> n; - std::vector<LLVector2> tc; - std::vector<LLVector4> w; - std::vector<LLVector4> t; - std::vector<LLColor4U> c; - std::vector<U64> j; + std::vector<LLVector3> p; //positions + std::vector<LLVector3> n; //normals + std::vector<LLVector4> t; //tangents + std::vector<LLVector2> tc0; //texcoords 0 + std::vector<LLVector2> tc1; //texcoords 1 + std::vector<LLColor4U> c; //colors + std::vector<LLVector4> w; //weights + std::vector<U64> j; //joints // initialize from src primitive and make an unrolled triangle list // returns false if the Primitive cannot be converted to a triangle list @@ -57,15 +58,28 @@ struct MikktMesh bool indexed = !prim->mIndexArray.empty(); U32 vert_count = indexed ? prim->mIndexArray.size() : prim->mPositions.size(); - if (prim->mMode != Primitive::Mode::TRIANGLES) + U32 triangle_count = 0; + + if (prim->mMode == Primitive::Mode::TRIANGLE_STRIP || + prim->mMode == Primitive::Mode::TRIANGLE_FAN) + { + triangle_count = vert_count - 2; + } + else if (prim->mMode == Primitive::Mode::TRIANGLES) { - LL_WARNS("GLTF") << "Unsupported primitive mode for conversion to triangles: " << (S32) prim->mMode << LL_ENDL; + triangle_count = vert_count / 3; + } + else + { + LL_WARNS("GLTF") << "Unsupported primitive mode for conversion to triangles: " << (S32)prim->mMode << LL_ENDL; return false; } + vert_count = triangle_count * 3; + p.resize(vert_count); n.resize(vert_count); - tc.resize(vert_count); + tc0.resize(vert_count); c.resize(vert_count); bool has_normals = !prim->mNormals.empty(); @@ -78,6 +92,7 @@ struct MikktMesh { t.resize(vert_count); } + bool rigged = !prim->mWeights.empty(); if (rigged) { @@ -85,23 +100,69 @@ struct MikktMesh j.resize(vert_count); } - for (int i = 0; i < vert_count; ++i) + bool multi_uv = !prim->mTexCoords1.empty(); + if (multi_uv) { - U32 idx = indexed ? prim->mIndexArray[i] : i; + tc1.resize(vert_count); + } - p[i].set(prim->mPositions[idx].getF32ptr()); - tc[i].set(prim->mTexCoords[idx]); - c[i] = prim->mColors[idx]; + for (int tri_idx = 0; tri_idx < triangle_count; ++tri_idx) + { + U32 idx[3]; + + if (prim->mMode == Primitive::Mode::TRIANGLES) + { + idx[0] = tri_idx * 3; + idx[1] = tri_idx * 3 + 1; + idx[2] = tri_idx * 3 + 2; + } + else if (prim->mMode == Primitive::Mode::TRIANGLE_STRIP) + { + idx[0] = tri_idx; + idx[1] = tri_idx + 1; + idx[2] = tri_idx + 2; - if (has_normals) + if (tri_idx % 2 != 0) + { + std::swap(idx[1], idx[2]); + } + } + else if (prim->mMode == Primitive::Mode::TRIANGLE_FAN) { - n[i].set(prim->mNormals[idx].getF32ptr()); + idx[0] = 0; + idx[1] = tri_idx + 1; + idx[2] = tri_idx + 2; } - if (rigged) + if (indexed) { - w[i].set(prim->mWeights[idx].getF32ptr()); - j[i] = prim->mJoints[idx]; + idx[0] = prim->mIndexArray[idx[0]]; + idx[1] = prim->mIndexArray[idx[1]]; + idx[2] = prim->mIndexArray[idx[2]]; + } + + for (U32 v = 0; v < 3; ++v) + { + U32 i = tri_idx * 3 + v; + p[i].set(prim->mPositions[idx[v]].getF32ptr()); + tc0[i].set(prim->mTexCoords0[idx[v]]); + c[i] = prim->mColors[idx[v]]; + + if (multi_uv) + { + tc1[i].set(prim->mTexCoords1[idx[v]]); + } + + if (has_normals) + { + n[i].set(prim->mNormals[idx[v]].getF32ptr()); + } + + if (rigged) + { + w[i].set(prim->mWeights[idx[v]].getF32ptr()); + j[i] = prim->mJoints[idx[v]]; + } } } @@ -138,25 +199,34 @@ struct MikktMesh void write(Primitive* prim) const { //re-weld - meshopt_Stream mos[] = + std::vector<meshopt_Stream> mos = { { &p[0], sizeof(LLVector3), sizeof(LLVector3) }, { &n[0], sizeof(LLVector3), sizeof(LLVector3) }, { &t[0], sizeof(LLVector4), sizeof(LLVector4) }, - { &tc[0], sizeof(LLVector2), sizeof(LLVector2) }, - { &c[0], sizeof(LLColor4U), sizeof(LLColor4U) }, - { w.empty() ? nullptr : &w[0], sizeof(LLVector4), sizeof(LLVector4) }, - { j.empty() ? nullptr : &j[0], sizeof(U64), sizeof(U64) } + { &tc0[0], sizeof(LLVector2), sizeof(LLVector2) }, + { &c[0], sizeof(LLColor4U), sizeof(LLColor4U) } }; + if (!w.empty()) + { + mos.push_back({ &w[0], sizeof(LLVector4), sizeof(LLVector4) }); + mos.push_back({ &j[0], sizeof(U64), sizeof(U64) }); + } + + if (!tc1.empty()) + { + mos.push_back({ &tc1[0], sizeof(LLVector2), sizeof(LLVector2) }); + } + std::vector<U32> remap; remap.resize(p.size()); - U32 stream_count = w.empty() ? 5 : 7; + U32 stream_count = mos.size(); - size_t vert_count = meshopt_generateVertexRemapMulti(&remap[0], nullptr, p.size(), p.size(), mos, stream_count); + size_t vert_count = meshopt_generateVertexRemapMulti(&remap[0], nullptr, p.size(), p.size(), mos.data(), stream_count); - prim->mTexCoords.resize(vert_count); + prim->mTexCoords0.resize(vert_count); prim->mNormals.resize(vert_count); prim->mTangents.resize(vert_count); prim->mPositions.resize(vert_count); @@ -166,6 +236,10 @@ struct MikktMesh prim->mWeights.resize(vert_count); prim->mJoints.resize(vert_count); } + if (!tc1.empty()) + { + prim->mTexCoords1.resize(vert_count); + } prim->mIndexArray.resize(remap.size()); @@ -178,7 +252,7 @@ struct MikktMesh prim->mPositions[dst_idx].load3(p[src_idx].mV); prim->mNormals[dst_idx].load3(n[src_idx].mV); - prim->mTexCoords[dst_idx] = tc[src_idx]; + prim->mTexCoords0[dst_idx] = tc0[src_idx]; prim->mTangents[dst_idx].loadua(t[src_idx].mV); prim->mColors[dst_idx] = c[src_idx]; @@ -187,6 +261,11 @@ struct MikktMesh prim->mWeights[dst_idx].loadua(w[src_idx].mV); prim->mJoints[dst_idx] = j[src_idx]; } + + if (!tc1.empty()) + { + prim->mTexCoords1[dst_idx] = tc1[src_idx]; + } } prim->mGLMode = LLRender::TRIANGLES; @@ -210,8 +289,8 @@ struct MikktMesh mikk::float3 GetTexCoord(const uint32_t face_num, const uint32_t vert_num) { - F32* uv = tc[face_num * 3 + vert_num].mV; - return mikk::float3(uv[0], uv[1], 1.0f); + F32* uv = tc0[face_num * 3 + vert_num].mV; + return mikk::float3(uv[0], 1.f-uv[1], 1.0f); } mikk::float3 GetNormal(const uint32_t face_num, const uint32_t vert_num) @@ -228,6 +307,14 @@ struct MikktMesh }; +static void vertical_flip(std::vector<LLVector2>& texcoords) +{ + for (auto& tc : texcoords) + { + tc[1] = 1.f - tc[1]; + } +} + bool Primitive::prep(Asset& asset) { // allocate vertex buffer @@ -261,7 +348,11 @@ bool Primitive::prep(Asset& asset) } else if (attribName == "TEXCOORD_0") { - copy(asset, accessor, mTexCoords); + copy(asset, accessor, mTexCoords0); + } + else if (attribName == "TEXCOORD_1") + { + copy(asset, accessor, mTexCoords1); } else if (attribName == "JOINTS_0") { @@ -297,24 +388,28 @@ bool Primitive::prep(Asset& asset) mask |= LLVertexBuffer::MAP_JOINT; } - if (mTexCoords.empty()) + if (mTexCoords0.empty()) { - mTexCoords.resize(mPositions.size()); + mTexCoords0.resize(mPositions.size()); } - // TODO: support more than one texcoord set (or no texcoords) mask |= LLVertexBuffer::MAP_TEXCOORD0; + if (!mTexCoords1.empty()) + { + mask |= LLVertexBuffer::MAP_TEXCOORD1; + } + if (mColors.empty()) { mColors.resize(mPositions.size(), LLColor4U::white); } + mShaderVariant = 0; + // TODO: support colorless vertex buffers mask |= LLVertexBuffer::MAP_COLOR; - mShaderVariant = 0; - bool unlit = false; // bake material basecolor into color array @@ -332,6 +427,11 @@ bool Primitive::prep(Asset& asset) mShaderVariant |= LLGLSLShader::GLTFVariant::UNLIT; unlit = true; } + + if (material.isMultiUV()) + { + mShaderVariant |= LLGLSLShader::GLTFVariant::MULTI_UV; + } } if (mNormals.empty() && !unlit) @@ -434,15 +534,17 @@ bool Primitive::prep(Asset& asset) } // flip texcoord y, upload, then flip back (keep the off-spec data in vram only) - for (auto& tc : mTexCoords) - { - tc[1] = 1.f - tc[1]; - } - mVertexBuffer->setTexCoordData(mTexCoords.data()); - for (auto& tc : mTexCoords) + vertical_flip(mTexCoords0); + mVertexBuffer->setTexCoord0Data(mTexCoords0.data()); + vertical_flip(mTexCoords0); + + if (!mTexCoords1.empty()) { - tc[1] = 1.f - tc[1]; + vertical_flip(mTexCoords1); + mVertexBuffer->setTexCoord1Data(mTexCoords1.data()); + vertical_flip(mTexCoords1); } + if (!mIndexArray.empty()) { @@ -453,10 +555,13 @@ bool Primitive::prep(Asset& asset) mVertexBuffer->unbind(); - Material& material = asset.mMaterials[mMaterial]; - if (material.mAlphaMode == Material::AlphaMode::BLEND) + if (mMaterial != INVALID_INDEX) { - mShaderVariant |= LLGLSLShader::GLTFVariant::ALPHA_BLEND; + Material& material = asset.mMaterials[mMaterial]; + if (material.mAlphaMode == Material::AlphaMode::BLEND) + { + mShaderVariant |= LLGLSLShader::GLTFVariant::ALPHA_BLEND; + } } return true; @@ -614,7 +719,7 @@ const LLVolumeTriangle* Primitive::lineSegmentIntersect(const LLVector4a& start, //create a proxy LLVolumeFace for the raycast LLVolumeFace face; face.mPositions = mPositions.data(); - face.mTexCoords = mTexCoords.data(); + face.mTexCoords = mTexCoords0.data(); face.mNormals = mNormals.data(); face.mTangents = mTangents.data(); face.mIndices = nullptr; // unreferenced diff --git a/indra/newview/gltf/primitive.h b/indra/newview/gltf/primitive.h index f9d7c63c65..7cc05cf831 100644 --- a/indra/newview/gltf/primitive.h +++ b/indra/newview/gltf/primitive.h @@ -58,7 +58,8 @@ namespace LL LLPointer<LLVertexBuffer> mVertexBuffer; // CPU copy of mesh data, keep these as LLVector types for compatibility with raycasting code - std::vector<LLVector2> mTexCoords; + std::vector<LLVector2> mTexCoords0; + std::vector<LLVector2> mTexCoords1; std::vector<LLVector4a> mNormals; std::vector<LLVector4a> mTangents; std::vector<LLVector4a> mPositions; diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index b390afee37..16f362b3e4 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -549,10 +549,16 @@ void GLTFSceneManager::render(bool opaque, bool rigged, bool unlit) void GLTFSceneManager::render(U8 variant) { - // for debugging, just render the whole scene as opaque - // by traversing the whole scenegraph - // Assumes camera transform is already set and - // appropriate shader is already boundd + // just render the whole scene by traversing the whole scenegraph + // Assumes camera transform is already set and appropriate shader is already bound. + // Eventually we'll want a smarter render pipe that has pre-sorted the scene graph + // into buckets by material and shader. + + // HACK -- implicitly render multi-uv variant + if (!(variant & LLGLSLShader::GLTFVariant::MULTI_UV)) + { + render((U8) (variant | LLGLSLShader::GLTFVariant::MULTI_UV)); + } gGL.matrixMode(LLRender::MM_MODELVIEW); @@ -732,6 +738,7 @@ void GLTFSceneManager::bind(Asset& asset, Material& material) F32 tf[8]; material.mPbrMetallicRoughness.mBaseColorTexture.mTextureTransform.getPacked(tf); shader->uniform4fv(LLShaderMgr::TEXTURE_BASE_COLOR_TRANSFORM, 2, tf); + shader->uniform1i(LLShaderMgr::BASE_COLOR_TEXCOORD, material.mPbrMetallicRoughness.mBaseColorTexture.getTexCoord()); if (!LLPipeline::sShadowRender) { @@ -748,15 +755,19 @@ void GLTFSceneManager::bind(Asset& asset, Material& material) material.mNormalTexture.mTextureTransform.getPacked(tf); shader->uniform4fv(LLShaderMgr::TEXTURE_NORMAL_TRANSFORM, 2, tf); + shader->uniform1i(LLShaderMgr::NORMAL_TEXCOORD, material.mNormalTexture.getTexCoord()); material.mPbrMetallicRoughness.mMetallicRoughnessTexture.mTextureTransform.getPacked(tf); shader->uniform4fv(LLShaderMgr::TEXTURE_METALLIC_ROUGHNESS_TRANSFORM, 2, tf); + shader->uniform1i(LLShaderMgr::METALLIC_ROUGHNESS_TEXCOORD, material.mPbrMetallicRoughness.mMetallicRoughnessTexture.getTexCoord()); material.mOcclusionTexture.mTextureTransform.getPacked(tf); shader->uniform4fv(LLShaderMgr::TEXTURE_OCCLUSION_TRANSFORM, 2, tf); + shader->uniform1i(LLShaderMgr::OCCLUSION_TEXCOORD, material.mOcclusionTexture.getTexCoord()); material.mEmissiveTexture.mTextureTransform.getPacked(tf); shader->uniform4fv(LLShaderMgr::TEXTURE_EMISSIVE_TRANSFORM, 2, tf); + shader->uniform1i(LLShaderMgr::EMISSIVE_TEXCOORD, material.mEmissiveTexture.getTexCoord()); } } diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index d43d6fea37..5913e7ba6f 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -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, bool unlit, bool use_sun_shadow) +static bool make_gltf_variant(LLGLSLShader& shader, LLGLSLShader& variant, bool alpha_blend, bool rigged, bool unlit, bool multi_uv, bool use_sun_shadow) { variant.mName = shader.mName.c_str(); variant.mFeatures = shader.mFeatures; @@ -271,6 +271,11 @@ static bool make_gltf_variant(LLGLSLShader& shader, LLGLSLShader& variant, bool variant.addPermutation("UNLIT", "1"); } + if (multi_uv) + { + variant.addPermutation("MULTI_UV", "1"); + } + if (alpha_blend) { variant.addPermutation("ALPHA_BLEND", "1"); @@ -317,8 +322,9 @@ static bool make_gltf_variants(LLGLSLShader& shader, bool use_sun_shadow) bool alpha_blend = i & LLGLSLShader::GLTFVariant::ALPHA_BLEND; bool rigged = i & LLGLSLShader::GLTFVariant::RIGGED; bool unlit = i & LLGLSLShader::GLTFVariant::UNLIT; + bool multi_uv = i & LLGLSLShader::GLTFVariant::MULTI_UV; - if (!make_gltf_variant(shader, shader.mGLTFVariants[i], alpha_blend, rigged, unlit, use_sun_shadow)) + if (!make_gltf_variant(shader, shader.mGLTFVariants[i], alpha_blend, rigged, unlit, multi_uv, use_sun_shadow)) { return false; } |