#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 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;

View File

@ -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)

View File

@ -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;

View File

@ -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>

View File

@ -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));
}
if (material.mUnlit.mPresent)
{ // material uses KHR_materials_unlit
mShaderVariant |= LLGLSLShader::GLTFVariant::UNLIT;
unlit = true;
}
}
mShaderVariant = 0;
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;
}