diff options
author | Dave Parks <davep@lindenlab.com> | 2024-06-10 16:57:31 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-10 16:57:31 -0500 |
commit | 4522f33d2bad2cc0f67e10a0b0ad3cc7c1b43fbd (patch) | |
tree | f2e020507f3240208e8d0b105f7e100a1e7aaf36 | |
parent | 4705362a332a2347510c81c8d00a1f607ad88af8 (diff) |
#1677 Add GLTF extensions serialization and support for KHR_materials_unlit (#1686)
-rw-r--r-- | indra/llmath/llvolumeoctree.cpp | 6 | ||||
-rw-r--r-- | indra/newview/gltf/asset.cpp | 40 | ||||
-rw-r--r-- | indra/newview/gltf/asset.h | 19 | ||||
-rw-r--r-- | indra/newview/gltf/buffer_util.h | 98 | ||||
-rw-r--r-- | indra/newview/gltf/primitive.cpp | 24 |
5 files changed, 176 insertions, 11 deletions
diff --git a/indra/llmath/llvolumeoctree.cpp b/indra/llmath/llvolumeoctree.cpp index 7a4d313fb1..faa169e295 100644 --- a/indra/llmath/llvolumeoctree.cpp +++ b/indra/llmath/llvolumeoctree.cpp @@ -151,7 +151,7 @@ void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode<LLVolumeTriangle, LL U32 idx1 = tri->mIndex[1]; U32 idx2 = tri->mIndex[2]; - if (mTexCoord != NULL) + if (mTexCoord != NULL && mFace->mTexCoords) { LLVector2* tc = (LLVector2*) mFace->mTexCoords; *mTexCoord = ((1.f - a - b) * tc[idx0] + @@ -160,7 +160,7 @@ void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode<LLVolumeTriangle, LL } - if (mNormal != NULL) + if (mNormal != NULL && mFace->mNormals) { LLVector4a* norm = mFace->mNormals; @@ -180,7 +180,7 @@ void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode<LLVolumeTriangle, LL *mNormal = n1; } - if (mTangent != NULL) + if (mTangent != NULL && mFace->mTangents) { LLVector4a* tangents = mFace->mTangents; diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index 7d379c2528..a4efb25860 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -39,10 +39,15 @@ using namespace LL::GLTF; using namespace boost::json; + namespace LL { namespace GLTF { + static std::unordered_set<std::string> ExtensionsSupported = { + "KHR_materials_unlit" + }; + Material::AlphaMode gltf_alpha_mode_to_enum(const std::string& alpha_mode) { if (alpha_mode == "OPAQUE") @@ -382,6 +387,22 @@ void Asset::update() bool Asset::prep() { + // check required extensions and fail if not supported + bool unsupported = false; + for (auto& extension : mExtensionsRequired) + { + if (ExtensionsSupported.find(extension) == ExtensionsSupported.end()) + { + LL_WARNS() << "Unsupported extension: " << extension << LL_ENDL; + unsupported = true; + } + } + + if (unsupported) + { + return false; + } + // do buffers first as other resources depend on them for (auto& buffer : mBuffers) { @@ -600,6 +621,8 @@ const Asset& Asset::operator=(const Value& src) copy(obj, "accessors", mAccessors); copy(obj, "animations", mAnimations); copy(obj, "skins", mSkins); + copy(obj, "extensionsUsed", mExtensionsUsed); + copy(obj, "extensionsRequired", mExtensionsRequired); } return *this; @@ -628,6 +651,8 @@ void Asset::serialize(object& dst) const write(mAccessors, "accessors", dst); write(mAnimations, "animations", dst); write(mSkins, "skins", dst); + write(mExtensionsUsed, "extensionsUsed", dst); + write(mExtensionsRequired, "extensionsRequired", dst); } bool Asset::save(const std::string& filename) @@ -979,6 +1004,17 @@ bool Material::PbrMetallicRoughness::operator!=(const Material::PbrMetallicRough return !(*this == rhs); } +const Material::Unlit& Material::Unlit::operator=(const Value& src) +{ + mPresent = true; + return *this; +} + +void Material::Unlit::serialize(object& dst) const +{ + // no members and object has already been created, nothing to do +} + void Material::serialize(object& dst) const { write(mName, "name", dst); @@ -990,6 +1026,7 @@ void Material::serialize(object& dst) const write(mAlphaMode, "alphaMode", dst, Material::AlphaMode::OPAQUE); write(mAlphaCutoff, "alphaCutoff", dst, 0.5f); write(mDoubleSided, "doubleSided", dst, false); + write_extensions(dst, &mUnlit, "KHR_materials_unlit"); } const Material& Material::operator=(const Value& src) @@ -1005,6 +1042,8 @@ const Material& Material::operator=(const Value& src) copy(src, "alphaMode", mAlphaMode); copy(src, "alphaCutoff", mAlphaCutoff); copy(src, "doubleSided", mDoubleSided); + copy_extensions(src, + "KHR_materials_unlit", &mUnlit ); } return *this; } @@ -1027,7 +1066,6 @@ const Mesh& Mesh::operator=(const Value& src) } return *this; - } bool Mesh::prep(Asset& asset) diff --git a/indra/newview/gltf/asset.h b/indra/newview/gltf/asset.h index fd7ea17f05..8f28e5905f 100644 --- a/indra/newview/gltf/asset.h +++ b/indra/newview/gltf/asset.h @@ -49,10 +49,26 @@ namespace LL { class Asset; + class Extension + { + public: + // true if this extension is present in the gltf file + // otherwise false + bool mPresent = false; + }; + + class Material { public: + class Unlit : public Extension // KHR_materials_unlit implementation + { + public: + const Unlit& operator=(const Value& src); + void serialize(boost::json::object& dst) const; + }; + enum class AlphaMode { OPAQUE, @@ -117,6 +133,7 @@ namespace LL AlphaMode mAlphaMode = AlphaMode::OPAQUE; F32 mAlphaCutoff = 0.5f; bool mDoubleSided = false; + Unlit mUnlit; const Material& operator=(const Value& src); void serialize(boost::json::object& dst) const; @@ -300,6 +317,8 @@ namespace LL std::vector<Accessor> mAccessors; std::vector<Animation> mAnimations; std::vector<Skin> mSkins; + std::vector<std::string> mExtensionsUsed; + std::vector<std::string> mExtensionsRequired; std::string mVersion; std::string mGenerator; diff --git a/indra/newview/gltf/buffer_util.h b/indra/newview/gltf/buffer_util.h index bd43f60d19..c26752a6b6 100644 --- a/indra/newview/gltf/buffer_util.h +++ b/indra/newview/gltf/buffer_util.h @@ -519,6 +519,104 @@ namespace LL return true; } + + // to/from extension + + // for internal use only, use copy_extensions instead + template<typename T> + inline bool _copy_extension(const boost::json::object& extensions, std::string_view member, T* dst) + { + if (extensions.contains(member)) + { + return copy(extensions.at(member), *dst); + } + + return false; + } + + // Copy all extensions from src.extensions to provided destinations + // Usage: + // copy_extensions(src, + // "KHR_materials_unlit", &mUnlit, + // "KHR_materials_pbrSpecularGlossiness", &mPbrSpecularGlossiness); + // returns true if any of the extensions are copied + template<class... Types> + inline bool copy_extensions(const boost::json::value& src, Types... args) + { + // extract the extensions object (don't assume it exists and verify that it is an object) + if (src.is_object()) + { + boost::json::object obj = src.get_object(); + if (obj.contains("extensions")) + { + const boost::json::value& extensions = obj.at("extensions"); + if (extensions.is_object()) + { + const boost::json::object& ext_obj = extensions.as_object(); + bool success = false; + // copy each extension, return true if any of them succeed, do not short circuit on success + U32 count = sizeof...(args); + for (U32 i = 0; i < count; i += 2) + { + if (_copy_extension(ext_obj, args...)) + { + success = true; + } + } + return success; + } + } + } + + return false; + } + + // internal use aonly, use write_extensions instead + template<typename T> + inline bool _write_extension(boost::json::object& extensions, const T* src, string_view member) + { + if (src->mPresent) + { + Value v; + if (write(*src, v)) + { + extensions[member] = v; + return true; + } + } + return false; + } + + // Write all extensions to dst.extensions + // Usage: + // write_extensions(dst, + // "KHR_materials_unlit", mUnlit, + // "KHR_materials_pbrSpecularGlossiness", mPbrSpecularGlossiness); + // returns true if any of the extensions are written + template<class... Types> + inline bool write_extensions(boost::json::object& dst, Types... args) + { + bool success = false; + + boost::json::object extensions; + U32 count = sizeof...(args) - 1; + + for (U32 i = 0; i < count; i += 2) + { + if (_write_extension(extensions, args...)) + { + success = true; + } + } + + if (success) + { + dst["extensions"] = extensions; + } + + return success; + } + // conditionally write a member to an object if the member // is not the default value template<typename T> diff --git a/indra/newview/gltf/primitive.cpp b/indra/newview/gltf/primitive.cpp index 8d9880951b..bc333aff69 100644 --- a/indra/newview/gltf/primitive.cpp +++ b/indra/newview/gltf/primitive.cpp @@ -313,6 +313,10 @@ bool Primitive::prep(Asset& asset) // TODO: support colorless vertex buffers mask |= LLVertexBuffer::MAP_COLOR; + mShaderVariant = 0; + + bool unlit = false; + // bake material basecolor into color array if (mMaterial != INVALID_INDEX) { @@ -322,11 +326,15 @@ bool Primitive::prep(Asset& asset) { dst = LLColor4U(baseColor * LLColor4(dst)); } - } - mShaderVariant = 0; + if (material.mUnlit.mPresent) + { // material uses KHR_materials_unlit + mShaderVariant |= LLGLSLShader::GLTFVariant::UNLIT; + unlit = true; + } + } - if (mNormals.empty()) + if (mNormals.empty() && !unlit) { mTangents.clear(); @@ -334,6 +342,7 @@ bool Primitive::prep(Asset& asset) { //no normals and no surfaces, this primitive is unlit mTangents.clear(); mShaderVariant |= LLGLSLShader::GLTFVariant::UNLIT; + unlit = true; } else { @@ -350,8 +359,6 @@ bool Primitive::prep(Asset& asset) } } - bool unlit = (mShaderVariant & LLGLSLShader::GLTFVariant::UNLIT) != 0; - if (mTangents.empty() && !unlit) { // NOTE: must be done last because tangent generation rewrites the other arrays // adapted from usage of Mikktspace in llvolume.cpp @@ -388,10 +395,13 @@ bool Primitive::prep(Asset& asset) } } - - if (!unlit) + if (!mNormals.empty()) { mask |= LLVertexBuffer::MAP_NORMAL; + } + + if (!mTangents.empty()) + { mask |= LLVertexBuffer::MAP_TANGENT; } |