#1677 Add GLTF extensions serialization and support for KHR_materials_unlit (#1686)

master
Dave Parks 2024-06-10 16:57:31 -05:00 committed by GitHub
parent 4705362a33
commit 4522f33d2b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 176 additions and 11 deletions

View File

@ -151,7 +151,7 @@ void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode<LLVolumeTriangle, LL
U32 idx1 = tri->mIndex[1]; U32 idx1 = tri->mIndex[1];
U32 idx2 = tri->mIndex[2]; U32 idx2 = tri->mIndex[2];
if (mTexCoord != NULL) if (mTexCoord != NULL && mFace->mTexCoords)
{ {
LLVector2* tc = (LLVector2*) mFace->mTexCoords; LLVector2* tc = (LLVector2*) mFace->mTexCoords;
*mTexCoord = ((1.f - a - b) * tc[idx0] + *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; LLVector4a* norm = mFace->mNormals;
@ -180,7 +180,7 @@ void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode<LLVolumeTriangle, LL
*mNormal = n1; *mNormal = n1;
} }
if (mTangent != NULL) if (mTangent != NULL && mFace->mTangents)
{ {
LLVector4a* tangents = mFace->mTangents; LLVector4a* tangents = mFace->mTangents;

View File

@ -39,10 +39,15 @@
using namespace LL::GLTF; using namespace LL::GLTF;
using namespace boost::json; using namespace boost::json;
namespace LL namespace LL
{ {
namespace GLTF namespace GLTF
{ {
static std::unordered_set<std::string> ExtensionsSupported = {
"KHR_materials_unlit"
};
Material::AlphaMode gltf_alpha_mode_to_enum(const std::string& alpha_mode) Material::AlphaMode gltf_alpha_mode_to_enum(const std::string& alpha_mode)
{ {
if (alpha_mode == "OPAQUE") if (alpha_mode == "OPAQUE")
@ -382,6 +387,22 @@ void Asset::update()
bool Asset::prep() 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 // do buffers first as other resources depend on them
for (auto& buffer : mBuffers) for (auto& buffer : mBuffers)
{ {
@ -600,6 +621,8 @@ const Asset& Asset::operator=(const Value& src)
copy(obj, "accessors", mAccessors); copy(obj, "accessors", mAccessors);
copy(obj, "animations", mAnimations); copy(obj, "animations", mAnimations);
copy(obj, "skins", mSkins); copy(obj, "skins", mSkins);
copy(obj, "extensionsUsed", mExtensionsUsed);
copy(obj, "extensionsRequired", mExtensionsRequired);
} }
return *this; return *this;
@ -628,6 +651,8 @@ void Asset::serialize(object& dst) const
write(mAccessors, "accessors", dst); write(mAccessors, "accessors", dst);
write(mAnimations, "animations", dst); write(mAnimations, "animations", dst);
write(mSkins, "skins", dst); write(mSkins, "skins", dst);
write(mExtensionsUsed, "extensionsUsed", dst);
write(mExtensionsRequired, "extensionsRequired", dst);
} }
bool Asset::save(const std::string& filename) bool Asset::save(const std::string& filename)
@ -979,6 +1004,17 @@ bool Material::PbrMetallicRoughness::operator!=(const Material::PbrMetallicRough
return !(*this == rhs); 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 void Material::serialize(object& dst) const
{ {
write(mName, "name", dst); write(mName, "name", dst);
@ -990,6 +1026,7 @@ void Material::serialize(object& dst) const
write(mAlphaMode, "alphaMode", dst, Material::AlphaMode::OPAQUE); write(mAlphaMode, "alphaMode", dst, Material::AlphaMode::OPAQUE);
write(mAlphaCutoff, "alphaCutoff", dst, 0.5f); write(mAlphaCutoff, "alphaCutoff", dst, 0.5f);
write(mDoubleSided, "doubleSided", dst, false); write(mDoubleSided, "doubleSided", dst, false);
write_extensions(dst, &mUnlit, "KHR_materials_unlit");
} }
const Material& Material::operator=(const Value& src) const Material& Material::operator=(const Value& src)
@ -1005,6 +1042,8 @@ const Material& Material::operator=(const Value& src)
copy(src, "alphaMode", mAlphaMode); copy(src, "alphaMode", mAlphaMode);
copy(src, "alphaCutoff", mAlphaCutoff); copy(src, "alphaCutoff", mAlphaCutoff);
copy(src, "doubleSided", mDoubleSided); copy(src, "doubleSided", mDoubleSided);
copy_extensions(src,
"KHR_materials_unlit", &mUnlit );
} }
return *this; return *this;
} }
@ -1027,7 +1066,6 @@ const Mesh& Mesh::operator=(const Value& src)
} }
return *this; return *this;
} }
bool Mesh::prep(Asset& asset) bool Mesh::prep(Asset& asset)

View File

@ -49,10 +49,26 @@ namespace LL
{ {
class Asset; class Asset;
class Extension
{
public:
// true if this extension is present in the gltf file
// otherwise false
bool mPresent = false;
};
class Material class Material
{ {
public: 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 enum class AlphaMode
{ {
OPAQUE, OPAQUE,
@ -117,6 +133,7 @@ namespace LL
AlphaMode mAlphaMode = AlphaMode::OPAQUE; AlphaMode mAlphaMode = AlphaMode::OPAQUE;
F32 mAlphaCutoff = 0.5f; F32 mAlphaCutoff = 0.5f;
bool mDoubleSided = false; bool mDoubleSided = false;
Unlit mUnlit;
const Material& operator=(const Value& src); const Material& operator=(const Value& src);
void serialize(boost::json::object& dst) const; void serialize(boost::json::object& dst) const;
@ -300,6 +317,8 @@ namespace LL
std::vector<Accessor> mAccessors; std::vector<Accessor> mAccessors;
std::vector<Animation> mAnimations; std::vector<Animation> mAnimations;
std::vector<Skin> mSkins; std::vector<Skin> mSkins;
std::vector<std::string> mExtensionsUsed;
std::vector<std::string> mExtensionsRequired;
std::string mVersion; std::string mVersion;
std::string mGenerator; std::string mGenerator;

View File

@ -519,6 +519,104 @@ namespace LL
return true; 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 // conditionally write a member to an object if the member
// is not the default value // is not the default value
template<typename T> template<typename T>

View File

@ -313,6 +313,10 @@ bool Primitive::prep(Asset& asset)
// TODO: support colorless vertex buffers // TODO: support colorless vertex buffers
mask |= LLVertexBuffer::MAP_COLOR; mask |= LLVertexBuffer::MAP_COLOR;
mShaderVariant = 0;
bool unlit = false;
// bake material basecolor into color array // bake material basecolor into color array
if (mMaterial != INVALID_INDEX) if (mMaterial != INVALID_INDEX)
{ {
@ -322,11 +326,15 @@ bool Primitive::prep(Asset& asset)
{ {
dst = LLColor4U(baseColor * LLColor4(dst)); dst = LLColor4U(baseColor * LLColor4(dst));
} }
if (material.mUnlit.mPresent)
{ // material uses KHR_materials_unlit
mShaderVariant |= LLGLSLShader::GLTFVariant::UNLIT;
unlit = true;
}
} }
mShaderVariant = 0; if (mNormals.empty() && !unlit)
if (mNormals.empty())
{ {
mTangents.clear(); mTangents.clear();
@ -334,6 +342,7 @@ bool Primitive::prep(Asset& asset)
{ //no normals and no surfaces, this primitive is unlit { //no normals and no surfaces, this primitive is unlit
mTangents.clear(); mTangents.clear();
mShaderVariant |= LLGLSLShader::GLTFVariant::UNLIT; mShaderVariant |= LLGLSLShader::GLTFVariant::UNLIT;
unlit = true;
} }
else else
{ {
@ -350,8 +359,6 @@ bool Primitive::prep(Asset& asset)
} }
} }
bool unlit = (mShaderVariant & LLGLSLShader::GLTFVariant::UNLIT) != 0;
if (mTangents.empty() && !unlit) if (mTangents.empty() && !unlit)
{ // NOTE: must be done last because tangent generation rewrites the other arrays { // NOTE: must be done last because tangent generation rewrites the other arrays
// adapted from usage of Mikktspace in llvolume.cpp // adapted from usage of Mikktspace in llvolume.cpp
@ -388,10 +395,13 @@ bool Primitive::prep(Asset& asset)
} }
} }
if (!mNormals.empty())
if (!unlit)
{ {
mask |= LLVertexBuffer::MAP_NORMAL; mask |= LLVertexBuffer::MAP_NORMAL;
}
if (!mTangents.empty())
{
mask |= LLVertexBuffer::MAP_TANGENT; mask |= LLVertexBuffer::MAP_TANGENT;
} }