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 /indra | |
| parent | 4705362a332a2347510c81c8d00a1f607ad88af8 (diff) | |
#1677 Add GLTF extensions serialization and support for KHR_materials_unlit (#1686)
Diffstat (limited to 'indra')
| -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;      } | 
