From 5e2bac01cb6e8d3de3cc0e496d94a729e4740247 Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Tue, 30 Apr 2024 17:26:48 -0500 Subject: #1357 GLTF Export Prototype --- indra/newview/gltf/asset.cpp | 332 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 332 insertions(+) (limited to 'indra/newview/gltf/asset.cpp') diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index 313e82bf01..233faac545 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -33,6 +33,267 @@ using namespace LL::GLTF; + +namespace LL +{ + namespace GLTF + { + template + void copy(const std::vector& src, std::vector& dst) + { + dst.resize(src.size()); + for (U32 i = 0; i < src.size(); ++i) + { + copy(src[i], dst[i]); + } + } + + void copy(const Node& src, tinygltf::Node& dst) + { + if (src.mMatrixValid) + { + if (!src.mMatrix.asMatrix4().isIdentity()) + { + dst.matrix.resize(16); + for (U32 i = 0; i < 16; ++i) + { + dst.matrix[i] = src.mMatrix.getF32ptr()[i]; + } + } + } + else if (src.mTRSValid) + { + if (!src.mRotation.equals(glh::quaternionf::identity(), FLT_EPSILON)) + { + dst.rotation.resize(4); + for (U32 i = 0; i < 4; ++i) + { + dst.rotation[i] = src.mRotation.get_value()[i]; + } + } + + if (src.mTranslation != glh::vec3f(0.f, 0.f, 0.f)) + { + dst.translation.resize(3); + for (U32 i = 0; i < 3; ++i) + { + dst.translation[i] = src.mTranslation.v[i]; + } + } + + if (src.mScale != glh::vec3f(1.f, 1.f, 1.f)) + { + dst.scale.resize(3); + for (U32 i = 0; i < 3; ++i) + { + dst.scale[i] = src.mScale.v[i]; + } + } + } + + dst.children = src.mChildren; + dst.mesh = src.mMesh; + dst.skin = src.mSkin; + dst.name = src.mName; + } + + void copy(const Scene& src, tinygltf::Scene& dst) + { + dst.nodes = src.mNodes; + dst.name = src.mName; + } + + void copy(const Primitive& src, tinygltf::Primitive& dst) + { + for (auto& attrib : src.mAttributes) + { + dst.attributes[attrib.first] = attrib.second; + } + dst.indices = src.mIndices; + dst.material = src.mMaterial; + dst.mode = src.mMode; + } + + void copy(const Mesh& src, tinygltf::Mesh& mesh) + { + copy(src.mPrimitives, mesh.primitives); + mesh.weights = src.mWeights; + mesh.name = src.mName; + } + + void copy(const Material::TextureInfo& src, tinygltf::TextureInfo& dst) + { + dst.index = src.mIndex; + dst.texCoord = src.mTexCoord; + } + + void copy(const Material::OcclusionTextureInfo& src, tinygltf::OcclusionTextureInfo& dst) + { + dst.index = src.mIndex; + dst.texCoord = src.mTexCoord; + dst.strength = src.mStrength; + } + + void copy(const Material::NormalTextureInfo& src, tinygltf::NormalTextureInfo& dst) + { + dst.index = src.mIndex; + dst.texCoord = src.mTexCoord; + dst.scale = src.mScale; + } + + void copy(const Material::PbrMetallicRoughness& src, tinygltf::PbrMetallicRoughness& dst) + { + dst.baseColorFactor = { src.mBaseColorFactor.v[0], src.mBaseColorFactor.v[1], src.mBaseColorFactor.v[2], src.mBaseColorFactor.v[3] }; + copy(src.mBaseColorTexture, dst.baseColorTexture); + dst.metallicFactor = src.mMetallicFactor; + dst.roughnessFactor = src.mRoughnessFactor; + copy(src.mMetallicRoughnessTexture, dst.metallicRoughnessTexture); + } + + void copy(const Material& src, tinygltf::Material& material) + { + material.name = src.mName; + + material.emissiveFactor = { src.mEmissiveFactor.v[0], src.mEmissiveFactor.v[1], src.mEmissiveFactor.v[2] }; + copy(src.mPbrMetallicRoughness, material.pbrMetallicRoughness); + copy(src.mNormalTexture, material.normalTexture); + copy(src.mEmissiveTexture, material.emissiveTexture); + } + + void copy(const Texture& src, tinygltf::Texture& texture) + { + texture.sampler = src.mSampler; + texture.source = src.mSource; + texture.name = src.mName; + } + + void copy(const Sampler& src, tinygltf::Sampler& sampler) + { + sampler.magFilter = src.mMagFilter; + sampler.minFilter = src.mMinFilter; + sampler.wrapS = src.mWrapS; + sampler.wrapT = src.mWrapT; + sampler.name = src.mName; + } + + void copy(const Skin& src, tinygltf::Skin& skin) + { + skin.joints = src.mJoints; + skin.inverseBindMatrices = src.mInverseBindMatrices; + skin.skeleton = src.mSkeleton; + skin.name = src.mName; + } + + void copy(const Accessor& src, tinygltf::Accessor& accessor) + { + accessor.bufferView = src.mBufferView; + accessor.byteOffset = src.mByteOffset; + accessor.componentType = src.mComponentType; + accessor.minValues = src.mMin; + accessor.maxValues = src.mMax; + + accessor.count = src.mCount; + accessor.type = src.mType; + accessor.normalized = src.mNormalized; + accessor.name = src.mName; + } + + void copy(const Animation::Sampler& src, tinygltf::AnimationSampler& sampler) + { + sampler.input = src.mInput; + sampler.output = src.mOutput; + sampler.interpolation = src.mInterpolation; + } + + void copy(const Animation::Channel& src, tinygltf::AnimationChannel& channel) + { + channel.sampler = src.mSampler; + channel.target_node = src.mTarget.mNode; + channel.target_path = src.mTarget.mPath; + } + + void copy(const Animation& src, tinygltf::Animation& animation) + { + animation.name = src.mName; + + copy(src.mSamplers, animation.samplers); + + U32 channel_count = src.mRotationChannels.size() + src.mTranslationChannels.size() + src.mScaleChannels.size(); + + animation.channels.resize(channel_count); + + U32 idx = 0; + for (U32 i = 0; i < src.mTranslationChannels.size(); ++i) + { + copy(src.mTranslationChannels[i], animation.channels[idx++]); + } + + for (U32 i = 0; i < src.mRotationChannels.size(); ++i) + { + copy(src.mRotationChannels[i], animation.channels[idx++]); + } + + for (U32 i = 0; i < src.mScaleChannels.size(); ++i) + { + copy(src.mScaleChannels[i], animation.channels[idx++]); + } + } + + void copy(const Buffer& src, tinygltf::Buffer& buffer) + { + buffer.uri = src.mUri; + buffer.data = src.mData; + buffer.name = src.mName; + } + + void copy(const BufferView& src, tinygltf::BufferView& bufferView) + { + bufferView.buffer = src.mBuffer; + bufferView.byteOffset = src.mByteOffset; + bufferView.byteLength = src.mByteLength; + bufferView.byteStride = src.mByteStride; + bufferView.target = src.mTarget; + bufferView.name = src.mName; + } + + void copy(const Image& src, tinygltf::Image& image) + { + image.name = src.mName; + image.width = src.mWidth; + image.height = src.mHeight; + image.component = src.mComponent; + image.bits = src.mBits; + image.pixel_type = src.mPixelType; + + image.image = src.mData; + image.bufferView = src.mBufferView; + image.mimeType = src.mMimeType; + image.uri = src.mUri; + } + + void copy(const Asset & src, tinygltf::Model& dst) + { + dst.defaultScene = src.mDefaultScene; + dst.asset.copyright = src.mCopyright; + dst.asset.version = src.mVersion; + dst.asset.minVersion = src.mMinVersion; + dst.asset.generator = "Linden Lab Experimental GLTF Export"; + + copy(src.mScenes, dst.scenes); + copy(src.mNodes, dst.nodes); + copy(src.mMeshes, dst.meshes); + copy(src.mMaterials, dst.materials); + copy(src.mBuffers, dst.buffers); + copy(src.mBufferViews, dst.bufferViews); + copy(src.mTextures, dst.textures); + copy(src.mSamplers, dst.samplers); + copy(src.mImages, dst.images); + copy(src.mAccessors, dst.accessors); + copy(src.mAnimations, dst.animations); + copy(src.mSkins, dst.skins); + } + } +} void Scene::updateTransforms(Asset& asset) { LLMatrix4a identity; @@ -237,6 +498,8 @@ void Node::makeMatrixValid() mMatrix.loadu(t.m); mMatrixValid = true; } + + llassert(mMatrixValid); } void Node::makeTRSValid() @@ -252,6 +515,8 @@ void Node::makeTRSValid() mRotation.set_value(t); mTRSValid = true; } + + llassert(mTRSValid); } void Node::setRotation(const glh::quaternionf& q) @@ -318,6 +583,7 @@ const Node& Node::operator=(const tinygltf::Node& src) { // node specifies no transformation, set to identity mMatrix.setIdentity(); + mMatrixValid = true; } mChildren = src.children; @@ -467,6 +733,14 @@ void Asset::allocateGLResources(const std::string& filename, const tinygltf::Mod const Asset& Asset::operator=(const tinygltf::Model& src) { + mVersion = src.asset.version; + mMinVersion = src.asset.minVersion; + mGenerator = src.asset.generator; + mCopyright = src.asset.copyright; + + mDefaultScene = src.defaultScene; + + mScenes.resize(src.scenes.size()); for (U32 i = 0; i < src.scenes.size(); ++i) { @@ -542,9 +816,67 @@ const Asset& Asset::operator=(const tinygltf::Model& src) return *this; } +void Asset::save(tinygltf::Model& dst) +{ + LL::GLTF::copy(*this, dst); +} + + +const Material::TextureInfo& Material::TextureInfo::operator=(const tinygltf::TextureInfo& src) +{ + mIndex = src.index; + mTexCoord = src.texCoord; + return *this; +} + +const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=(const tinygltf::OcclusionTextureInfo& src) +{ + mIndex = src.index; + mTexCoord = src.texCoord; + mStrength = src.strength; + return *this; +} + +const Material::NormalTextureInfo& Material::NormalTextureInfo::operator=(const tinygltf::NormalTextureInfo& src) +{ + mIndex = src.index; + mTexCoord = src.texCoord; + mScale = src.scale; + return *this; +} + +const Material::PbrMetallicRoughness& Material::PbrMetallicRoughness::operator=(const tinygltf::PbrMetallicRoughness& src) +{ + if (src.baseColorFactor.size() == 4) + { + mBaseColorFactor.set_value(src.baseColorFactor[0], src.baseColorFactor[1], src.baseColorFactor[2], src.baseColorFactor[3]); + } + + mBaseColorTexture = src.baseColorTexture; + mMetallicFactor = src.metallicFactor; + mRoughnessFactor = src.roughnessFactor; + mMetallicRoughnessTexture = src.metallicRoughnessTexture; + + return *this; +} const Material& Material::operator=(const tinygltf::Material& src) { mName = src.name; + + if (src.emissiveFactor.size() == 3) + { + mEmissiveFactor.set_value(src.emissiveFactor[0], src.emissiveFactor[1], src.emissiveFactor[2]); + } + + mPbrMetallicRoughness = src.pbrMetallicRoughness; + mNormalTexture = src.normalTexture; + mOcclusionTexture = src.occlusionTexture; + mEmissiveTexture = src.emissiveTexture; + + mAlphaMode = src.alphaMode; + mAlphaCutoff = src.alphaCutoff; + mDoubleSided = src.doubleSided; + return *this; } -- cgit v1.2.3 From 170765fd3505410dced83b342f87030fd9151e35 Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Tue, 30 Apr 2024 21:57:42 -0500 Subject: #1357 Proof of concept on decomposing a GLTF scene into its component parts --- indra/newview/gltf/asset.cpp | 102 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) (limited to 'indra/newview/gltf/asset.cpp') diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index 233faac545..475cbcb6e5 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -30,9 +30,11 @@ #include "llvolumeoctree.h" #include "../llviewershadermgr.h" #include "../llviewercontrol.h" +#include "../llviewertexturelist.h" using namespace LL::GLTF; +#pragma optimize("", off) namespace LL { @@ -821,6 +823,106 @@ void Asset::save(tinygltf::Model& dst) LL::GLTF::copy(*this, dst); } +void Asset::decompose(const std::string& filename) +{ + // get folder path + std::string folder = gDirUtilp->getDirName(filename); + + // decompose images + for (auto& image : mImages) + { + image.decompose(*this, folder); + } +} + +void Asset::eraseBufferView(S32 bufferView) +{ + mBufferViews.erase(mBufferViews.begin() + bufferView); + + for (auto& accessor : mAccessors) + { + if (accessor.mBufferView > bufferView) + { + accessor.mBufferView--; + } + } + + for (auto& image : mImages) + { + if (image.mBufferView > bufferView) + { + image.mBufferView--; + } + } + +} + +void Image::decompose(Asset& asset, const std::string& folder) +{ + std::string name = mName; + if (name.empty()) + { + S32 idx = this - asset.mImages.data(); + name = llformat("image_%d", idx); + } + + if (mBufferView != INVALID_INDEX) + { + // save original image + BufferView& bufferView = asset.mBufferViews[mBufferView]; + Buffer& buffer = asset.mBuffers[bufferView.mBuffer]; + + std::string extension; + + if (mMimeType == "image/jpeg") + { + extension = ".jpg"; + } + else if (mMimeType == "image/png") + { + extension = ".png"; + } + else + { + extension = ".bin"; + } + + std::string filename = folder + "/" + name + "." + extension; + + // set URI to non-j2c file for now, but later we'll want to reference the j2c hash + mUri = name + "." + extension; + + std::ofstream file(filename, std::ios::binary); + file.write((const char*)buffer.mData.data() + bufferView.mByteOffset, bufferView.mByteLength); + + buffer.erase(asset, bufferView.mByteOffset, bufferView.mByteLength); + + asset.eraseBufferView(mBufferView); + } + + if (!mData.empty()) + { + // save j2c image + std::string filename = folder + "/" + name + ".j2c"; + + LLPointer raw = new LLImageRaw(mWidth, mHeight, mComponent); + U8* data = raw->allocateData(); + llassert(mData.size() == raw->getDataSize()); + memcpy(data, mData.data(), mData.size()); + + LLViewerTextureList::createUploadFile(raw, filename, 4096); + + mData.clear(); + } + + mWidth = -1; + mHeight = -1; + mComponent = -1; + mBits = -1; + mPixelType = -1; + mMimeType = ""; + +} const Material::TextureInfo& Material::TextureInfo::operator=(const tinygltf::TextureInfo& src) { -- cgit v1.2.3 From a701cce8e0959503156a010683f6d0d57beaae36 Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Wed, 1 May 2024 09:51:32 -0500 Subject: #1357 Preserve asset "extras" and switch to std::shared_ptr for referencing Asset from LLViewerObject to cut down rebuild time --- indra/newview/gltf/asset.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/newview/gltf/asset.cpp') diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index 475cbcb6e5..42f064699c 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -34,8 +34,6 @@ using namespace LL::GLTF; -#pragma optimize("", off) - namespace LL { namespace GLTF @@ -280,6 +278,7 @@ namespace LL dst.asset.version = src.mVersion; dst.asset.minVersion = src.mMinVersion; dst.asset.generator = "Linden Lab Experimental GLTF Export"; + dst.asset.extras = src.mExtras; copy(src.mScenes, dst.scenes); copy(src.mNodes, dst.nodes); @@ -739,9 +738,10 @@ const Asset& Asset::operator=(const tinygltf::Model& src) mMinVersion = src.asset.minVersion; mGenerator = src.asset.generator; mCopyright = src.asset.copyright; + mExtras = src.asset.extras; mDefaultScene = src.defaultScene; - + mScenes.resize(src.scenes.size()); for (U32 i = 0; i < src.scenes.size(); ++i) -- cgit v1.2.3 From 799ebf21624edb8b42ca16b8cf51c138643efd32 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Fri, 10 May 2024 15:16:06 +0200 Subject: Fix broken merge and BOOL/bool issues --- indra/newview/gltf/asset.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/gltf/asset.cpp') diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index 42f064699c..5f2217a075 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -1092,7 +1092,7 @@ void Skin::uploadMatrixPalette(Asset& asset, Node& node) LLGLSLShader::sCurBoundShaderPtr->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX, mJoints.size(), - FALSE, + GL_FALSE, (GLfloat*)glmp.data()); } -- cgit v1.2.3 From 03c4458bdcc6821a3047f93b729d412e274ab9af Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 20 May 2024 13:22:55 -0500 Subject: #1392 GLTF Upload (#1394) * #1392 WIP -- Functional texture upload, stubbed out .bin upload. * #1392 GLTF Upload WIP -- Emulates successful upload Successfully uploads texture Emulates successful .gltf and .bin upload by injecting into local asset cache. Emulates rez from inventory by setting sculpt ID of selected object Currently fails in tinygltf parsing due to missing .bin * Add missing notification * Build fix * #1392 Add boost::json .gltf reading support. * #1392 boost::json GLTF writing prototype * Create gltf/README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * #1392 Add ability to render directly from LL::GLTF::Material * Fix for mac build * Mac build fix * #1392 AssetType and Inventory Type plumbing * #1392 More sane error handling and scheduling of uploads. * #1392 Actually attempt to upload glbin * Mac build fix, upload nudge * Mac build fix * Fix glTF asset uploads to server * Mac build fix (inline not static) * More consistent inline * Add glm, mac nudge. * #1392 For consistency with spec, start using glm over glh:: and LLFoo * Another attempt at placating Mac builds * Another Mac nudge * Mac build take 23 * #1392 Prune LLMatrix4a from GLTF namespace. * #1392 Fix for orientation being off (glm::quat is wxyz, not xyzw) * #1392 WIP -- Actually send the sculpt type and id, nudge readme and alpha rendering * #1392 Working download! * #1394 Add support for GLTFEnabled SimulatorFeature * #1392 Review feedback --------- Co-authored-by: Pepper Linden <3782201+rohvani@users.noreply.github.com> --- indra/newview/gltf/asset.cpp | 725 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 600 insertions(+), 125 deletions(-) (limited to 'indra/newview/gltf/asset.cpp') diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index 5f2217a075..c64d48662c 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -31,13 +31,51 @@ #include "../llviewershadermgr.h" #include "../llviewercontrol.h" #include "../llviewertexturelist.h" +#include "../pipeline.h" +#include "buffer_util.h" using namespace LL::GLTF; +using namespace boost::json; namespace LL { namespace GLTF { + Material::AlphaMode gltf_alpha_mode_to_enum(const std::string& alpha_mode) + { + if (alpha_mode == "OPAQUE") + { + return Material::AlphaMode::OPAQUE; + } + else if (alpha_mode == "MASK") + { + return Material::AlphaMode::MASK; + } + else if (alpha_mode == "BLEND") + { + return Material::AlphaMode::BLEND; + } + else + { + return Material::AlphaMode::OPAQUE; + } + } + + std::string enum_to_gltf_alpha_mode(Material::AlphaMode alpha_mode) + { + switch (alpha_mode) + { + case Material::AlphaMode::OPAQUE: + return "OPAQUE"; + case Material::AlphaMode::MASK: + return "MASK"; + case Material::AlphaMode::BLEND: + return "BLEND"; + default: + return "OPAQUE"; + } + } + template void copy(const std::vector& src, std::vector& dst) { @@ -45,49 +83,48 @@ namespace LL for (U32 i = 0; i < src.size(); ++i) { copy(src[i], dst[i]); - } + } } void copy(const Node& src, tinygltf::Node& dst) { if (src.mMatrixValid) { - if (!src.mMatrix.asMatrix4().isIdentity()) + if (src.mMatrix != glm::identity()) { dst.matrix.resize(16); + const F32* m = glm::value_ptr(src.mMatrix); for (U32 i = 0; i < 16; ++i) { - dst.matrix[i] = src.mMatrix.getF32ptr()[i]; + dst.matrix[i] = m[i]; } } } else if (src.mTRSValid) { - if (!src.mRotation.equals(glh::quaternionf::identity(), FLT_EPSILON)) + if (src.mRotation != glm::identity()) { dst.rotation.resize(4); - for (U32 i = 0; i < 4; ++i) - { - dst.rotation[i] = src.mRotation.get_value()[i]; - } - } + dst.rotation[0] = src.mRotation.x; + dst.rotation[1] = src.mRotation.y; + dst.rotation[2] = src.mRotation.z; + dst.rotation[3] = src.mRotation.w; + } - if (src.mTranslation != glh::vec3f(0.f, 0.f, 0.f)) + if (src.mTranslation != vec3(0.f, 0.f, 0.f)) { dst.translation.resize(3); - for (U32 i = 0; i < 3; ++i) - { - dst.translation[i] = src.mTranslation.v[i]; - } + dst.translation[0] = src.mTranslation.x; + dst.translation[1] = src.mTranslation.y; + dst.translation[2] = src.mTranslation.z; } - if (src.mScale != glh::vec3f(1.f, 1.f, 1.f)) + if (src.mScale != vec3(1.f, 1.f, 1.f)) { dst.scale.resize(3); - for (U32 i = 0; i < 3; ++i) - { - dst.scale[i] = src.mScale.v[i]; - } + dst.scale[0] = src.mScale.x; + dst.scale[1] = src.mScale.y; + dst.scale[2] = src.mScale.z; } } @@ -143,7 +180,7 @@ namespace LL void copy(const Material::PbrMetallicRoughness& src, tinygltf::PbrMetallicRoughness& dst) { - dst.baseColorFactor = { src.mBaseColorFactor.v[0], src.mBaseColorFactor.v[1], src.mBaseColorFactor.v[2], src.mBaseColorFactor.v[3] }; + dst.baseColorFactor = { src.mBaseColorFactor.r, src.mBaseColorFactor.g, src.mBaseColorFactor.b, src.mBaseColorFactor.a }; copy(src.mBaseColorTexture, dst.baseColorTexture); dst.metallicFactor = src.mMetallicFactor; dst.roughnessFactor = src.mRoughnessFactor; @@ -154,7 +191,7 @@ namespace LL { material.name = src.mName; - material.emissiveFactor = { src.mEmissiveFactor.v[0], src.mEmissiveFactor.v[1], src.mEmissiveFactor.v[2] }; + material.emissiveFactor = { src.mEmissiveFactor.r, src.mEmissiveFactor.g, src.mEmissiveFactor.b }; copy(src.mPbrMetallicRoughness, material.pbrMetallicRoughness); copy(src.mNormalTexture, material.normalTexture); copy(src.mEmissiveTexture, material.emissiveTexture); @@ -193,7 +230,7 @@ namespace LL accessor.maxValues = src.mMax; accessor.count = src.mCount; - accessor.type = src.mType; + accessor.type = (S32) src.mType; accessor.normalized = src.mNormalized; accessor.name = src.mName; } @@ -278,7 +315,8 @@ namespace LL dst.asset.version = src.mVersion; dst.asset.minVersion = src.mMinVersion; dst.asset.generator = "Linden Lab Experimental GLTF Export"; - dst.asset.extras = src.mExtras; + + // NOTE: extras are lost in the conversion for now copy(src.mScenes, dst.scenes); copy(src.mNodes, dst.nodes); @@ -297,8 +335,8 @@ namespace LL } void Scene::updateTransforms(Asset& asset) { - LLMatrix4a identity; - identity.setIdentity(); + mat4 identity = glm::identity(); + for (auto& nodeIndex : mNodes) { Node& node = asset.mNodes[nodeIndex]; @@ -306,7 +344,7 @@ void Scene::updateTransforms(Asset& asset) } } -void Scene::updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview) +void Scene::updateRenderTransforms(Asset& asset, const mat4& modelview) { for (auto& nodeIndex : mNodes) { @@ -315,9 +353,9 @@ void Scene::updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview) } } -void Node::updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview) +void Node::updateRenderTransforms(Asset& asset, const mat4& modelview) { - matMul(mMatrix, modelview, mRenderMatrix); + mRenderMatrix = modelview * mMatrix; for (auto& childIndex : mChildren) { @@ -326,13 +364,12 @@ void Node::updateRenderTransforms(Asset& asset, const LLMatrix4a& modelview) } } -LLMatrix4a inverse(const LLMatrix4a& mat); - -void Node::updateTransforms(Asset& asset, const LLMatrix4a& parentMatrix) +void Node::updateTransforms(Asset& asset, const mat4& parentMatrix) { makeMatrixValid(); - matMul(mMatrix, parentMatrix, mAssetMatrix); - mAssetMatrixInv = inverse(mAssetMatrix); + mAssetMatrix = parentMatrix * mMatrix; + + mAssetMatrixInv = glm::inverse(mAssetMatrix); S32 my_index = this - &asset.mNodes[0]; @@ -352,26 +389,13 @@ void Asset::updateTransforms() } } -void Asset::updateRenderTransforms(const LLMatrix4a& modelview) +void Asset::updateRenderTransforms(const mat4& modelview) { -#if 0 - // traverse hierarchy and update render transforms from scratch - for (auto& scene : mScenes) - { - scene.updateRenderTransforms(*this, modelview); - } -#else // use mAssetMatrix to update render transforms from node list for (auto& node : mNodes) { - //if (node.mMesh != INVALID_INDEX) - { - matMul(node.mAssetMatrix, modelview, node.mRenderMatrix); - } + node.mRenderMatrix = modelview * node.mAssetMatrix; } - -#endif - } S32 Asset::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, @@ -398,9 +422,11 @@ S32 Asset::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, bool newHit = false; + LLMatrix4a ami; + ami.loadu(glm::value_ptr(node.mAssetMatrixInv)); // transform start and end to this node's local space - node.mAssetMatrixInv.affineTransform(start, local_start); - node.mAssetMatrixInv.affineTransform(asset_end, local_end); + ami.affineTransform(start, local_start); + ami.affineTransform(asset_end, local_end); Mesh& mesh = mMeshes[node.mMesh]; for (auto& primitive : mesh.mPrimitives) @@ -423,8 +449,10 @@ S32 Asset::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, if (newHit) { + LLMatrix4a am; + am.loadu(glm::value_ptr(node.mAssetMatrix)); // shorten line segment on hit - node.mAssetMatrix.affineTransform(p, asset_end); + am.affineTransform(p, asset_end); // transform results back to asset space if (intersection) @@ -434,12 +462,10 @@ S32 Asset::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, if (normal || tangent) { - LLMatrix4 normalMatrix(node.mAssetMatrixInv.getF32ptr()); - - normalMatrix.transpose(); + mat4 normalMatrix = glm::transpose(node.mAssetMatrixInv); LLMatrix4a norm_mat; - norm_mat.loadu((F32*)normalMatrix.mMatrix); + norm_mat.loadu(glm::value_ptr(normalMatrix)); if (normal) { @@ -481,22 +507,7 @@ void Node::makeMatrixValid() { if (!mMatrixValid && mTRSValid) { - glh::matrix4f rot; - mRotation.get_value(rot); - - glh::matrix4f trans; - trans.set_translate(mTranslation); - - glh::matrix4f sc; - sc.set_scale(mScale); - - glh::matrix4f t; - //t = sc * rot * trans; - //t = trans * rot * sc; // best so far, still wrong on negative scale - //t = sc * trans * rot; - t = trans * sc * rot; - - mMatrix.loadu(t.m); + mMatrix = glm::recompose(mScale, mRotation, mTranslation, vec3(0,0,0), vec4(0,0,0,1)); mMatrixValid = true; } @@ -507,43 +518,72 @@ void Node::makeTRSValid() { if (!mTRSValid && mMatrixValid) { - glh::matrix4f t(mMatrix.getF32ptr()); - - glh::vec4f p = t.get_column(3); - mTranslation.set_value(p.v[0], p.v[1], p.v[2]); - - mScale.set_value(t.get_column(0).length(), t.get_column(1).length(), t.get_column(2).length()); - mRotation.set_value(t); + vec3 skew; + vec4 perspective; + glm::decompose(mMatrix, mScale, mRotation, mTranslation, skew, perspective); + mTRSValid = true; } llassert(mTRSValid); } -void Node::setRotation(const glh::quaternionf& q) +void Node::setRotation(const quat& q) { makeTRSValid(); mRotation = q; mMatrixValid = false; } -void Node::setTranslation(const glh::vec3f& t) +void Node::setTranslation(const vec3& t) { makeTRSValid(); mTranslation = t; mMatrixValid = false; } -void Node::setScale(const glh::vec3f& s) +void Node::setScale(const vec3& s) { makeTRSValid(); mScale = s; mMatrixValid = false; } +void Node::serialize(object& dst) const +{ + write(mName, "name", dst); + write(mMatrix, "matrix", dst, glm::identity()); + write(mRotation, "rotation", dst); + write(mTranslation, "translation", dst); + write(mScale, "scale", dst, vec3(1.f,1.f,1.f)); + write(mChildren, "children", dst); + write(mMesh, "mesh", dst, INVALID_INDEX); + write(mSkin, "skin", dst, INVALID_INDEX); +} + +const Node& Node::operator=(const Value& src) +{ + copy(src, "name", mName); + mMatrixValid = copy(src, "matrix", mMatrix); + + copy(src, "rotation", mRotation); + copy(src, "translation", mTranslation); + copy(src, "scale", mScale); + copy(src, "children", mChildren); + copy(src, "mesh", mMesh); + copy(src, "skin", mSkin); + + if (!mMatrixValid) + { + mTRSValid = true; + } + + return *this; +} + const Node& Node::operator=(const tinygltf::Node& src) { - F32* dstMatrix = mMatrix.getF32ptr(); + F32* dstMatrix = glm::value_ptr(mMatrix); if (src.matrix.size() == 16) { @@ -560,22 +600,21 @@ const Node& Node::operator=(const tinygltf::Node& src) // node has rotation/translation/scale, convert to matrix if (src.rotation.size() == 4) { - mRotation = glh::quaternionf((F32)src.rotation[0], (F32)src.rotation[1], (F32)src.rotation[2], (F32)src.rotation[3]); + mRotation = quat((F32)src.rotation[3], (F32)src.rotation[0], (F32)src.rotation[1], (F32)src.rotation[2]); } if (src.translation.size() == 3) { - mTranslation = glh::vec3f((F32)src.translation[0], (F32)src.translation[1], (F32)src.translation[2]); + mTranslation = vec3((F32)src.translation[0], (F32)src.translation[1], (F32)src.translation[2]); } - glh::vec3f scale; if (src.scale.size() == 3) { - mScale = glh::vec3f((F32)src.scale[0], (F32)src.scale[1], (F32)src.scale[2]); + mScale = vec3((F32)src.scale[0], (F32)src.scale[1], (F32)src.scale[2]); } else { - mScale.set_value(1.f, 1.f, 1.f); + mScale = vec3(1.f, 1.f, 1.f); } mTRSValid = true; @@ -583,7 +622,7 @@ const Node& Node::operator=(const tinygltf::Node& src) else { // node specifies no transformation, set to identity - mMatrix.setIdentity(); + mMatrix = glm::identity(); mMatrixValid = true; } @@ -595,6 +634,50 @@ const Node& Node::operator=(const tinygltf::Node& src) return *this; } +void Image::serialize(object& dst) const +{ + write(mUri, "uri", dst); + write(mMimeType, "mimeType", dst); + write(mBufferView, "bufferView", dst, INVALID_INDEX); + write(mName, "name", dst); + write(mWidth, "width", dst, -1); + write(mHeight, "height", dst, -1); + write(mComponent, "component", dst, -1); + write(mBits, "bits", dst, -1); + write(mPixelType, "pixelType", dst, -1); +} + +const Image& Image::operator=(const Value& src) +{ + copy(src, "uri", mUri); + copy(src, "mimeType", mMimeType); + copy(src, "bufferView", mBufferView); + copy(src, "name", mName); + copy(src, "width", mWidth); + copy(src, "height", mHeight); + copy(src, "component", mComponent); + copy(src, "bits", mBits); + copy(src, "pixelType", mPixelType); + + return *this; +} + +const Image& Image::operator=(const tinygltf::Image& src) +{ + mName = src.name; + mWidth = src.width; + mHeight = src.height; + mComponent = src.component; + mBits = src.bits; + mPixelType = src.pixel_type; + mUri = src.uri; + mBufferView = src.bufferView; + mMimeType = src.mimeType; + mData = src.image; + return *this; +} + + void Asset::render(bool opaque, bool rigged) { if (rigged) @@ -623,7 +706,6 @@ void Asset::render(bool opaque, bool rigged) continue; } - if (node.mMesh != INVALID_INDEX) { Mesh& mesh = mMeshes[node.mMesh]; @@ -631,19 +713,28 @@ void Asset::render(bool opaque, bool rigged) { if (!rigged) { - gGL.loadMatrix((F32*)node.mRenderMatrix.mMatrix); + gGL.loadMatrix((F32*)glm::value_ptr(node.mRenderMatrix)); } bool cull = true; if (primitive.mMaterial != INVALID_INDEX) { Material& material = mMaterials[primitive.mMaterial]; + bool mat_opaque = material.mAlphaMode != Material::AlphaMode::BLEND; - if ((material.mMaterial->mAlphaMode == LLGLTFMaterial::ALPHA_MODE_BLEND) == opaque) + if (mat_opaque != opaque) { continue; } - material.mMaterial->bind(); - cull = !material.mMaterial->mDoubleSided; + + if (mMaterials[primitive.mMaterial].mMaterial.notNull()) + { + material.mMaterial->bind(); + } + else + { + material.bind(*this); + } + cull = !material.mDoubleSided; } else { @@ -709,11 +800,16 @@ void Asset::allocateGLResources(const std::string& filename, const tinygltf::Mod image.allocateGLResources(); } + // do materials before meshes as meshes may depend on materials - for (U32 i = 0; i < mMaterials.size(); ++i) + if (!filename.empty()) { - mMaterials[i].allocateGLResources(*this); - LLTinyGLTFHelper::getMaterialFromModel(filename, model, i, mMaterials[i].mMaterial, mMaterials[i].mName, true); + for (U32 i = 0; i < mMaterials.size(); ++i) + { + // HACK: local preview mode, load material from model for now + mMaterials[i].allocateGLResources(*this); + LLTinyGLTFHelper::getMaterialFromModel(filename, model, i, mMaterials[i].mMaterial, mMaterials[i].mName, true); + } } for (auto& mesh : mMeshes) @@ -732,16 +828,26 @@ void Asset::allocateGLResources(const std::string& filename, const tinygltf::Mod } } +Asset::Asset(const tinygltf::Model& src) +{ + *this = src; +} + +Asset::Asset(const Value& src) +{ + *this = src; +} + const Asset& Asset::operator=(const tinygltf::Model& src) { mVersion = src.asset.version; mMinVersion = src.asset.minVersion; mGenerator = src.asset.generator; mCopyright = src.asset.copyright; - mExtras = src.asset.extras; + + // note: extras are lost in the conversion for now mDefaultScene = src.defaultScene; - mScenes.resize(src.scenes.size()); for (U32 i = 0; i < src.scenes.size(); ++i) @@ -818,11 +924,69 @@ const Asset& Asset::operator=(const tinygltf::Model& src) return *this; } +const Asset& Asset::operator=(const Value& src) +{ + if (src.is_object()) + { + const object& obj = src.as_object(); + + const auto it = obj.find("asset"); + + if (it != obj.end()) + { + const Value& asset = it->value(); + + copy(asset, "version", mVersion); + copy(asset, "minVersion", mMinVersion); + copy(asset, "generator", mGenerator); + copy(asset, "copyright", mCopyright); + copy(asset, "extras", mExtras); + } + + copy(obj, "defaultScene", mDefaultScene); + copy(obj, "scenes", mScenes); + copy(obj, "nodes", mNodes); + copy(obj, "meshes", mMeshes); + copy(obj, "materials", mMaterials); + copy(obj, "buffers", mBuffers); + copy(obj, "bufferViews", mBufferViews); + copy(obj, "textures", mTextures); + copy(obj, "samplers", mSamplers); + copy(obj, "images", mImages); + copy(obj, "accessors", mAccessors); + copy(obj, "animations", mAnimations); + copy(obj, "skins", mSkins); + } + + return *this; +} + void Asset::save(tinygltf::Model& dst) { LL::GLTF::copy(*this, dst); } +void Asset::serialize(object& dst) const +{ + write(mVersion, "version", dst); + write(mMinVersion, "minVersion", dst, std::string()); + write(mGenerator, "generator", dst); + write(mDefaultScene, "defaultScene", dst, 0); + + write(mScenes, "scenes", dst); + write(mNodes, "nodes", dst); + write(mMeshes, "meshes", dst); + write(mMaterials, "materials", dst); + write(mBuffers, "buffers", dst); + write(mBufferViews, "bufferViews", dst); + write(mTextures, "textures", dst); + write(mSamplers, "samplers", dst); + write(mImages, "images", dst); + write(mAccessors, "accessors", dst); + write(mAnimations, "animations", dst); + write(mSkins, "skins", dst); +} + void Asset::decompose(const std::string& filename) { // get folder path @@ -857,6 +1021,41 @@ void Asset::eraseBufferView(S32 bufferView) } +LLViewerFetchedTexture* fetch_texture(const LLUUID& id); + +void Image::allocateGLResources() +{ + LLUUID id; + if (LLUUID::parseUUID(mUri, &id) && id.notNull()) + { + mTexture = fetch_texture(id); + } +} + + +void Image::clearData(Asset& asset) +{ + if (mBufferView != INVALID_INDEX) + { + // remove data from buffer + BufferView& bufferView = asset.mBufferViews[mBufferView]; + Buffer& buffer = asset.mBuffers[bufferView.mBuffer]; + + buffer.erase(asset, bufferView.mByteOffset, bufferView.mByteLength); + + asset.eraseBufferView(mBufferView); + } + + mData.clear(); + mBufferView = INVALID_INDEX; + mWidth = -1; + mHeight = -1; + mComponent = -1; + mBits = -1; + mPixelType = -1; + mMimeType = ""; +} + void Image::decompose(Asset& asset, const std::string& folder) { std::string name = mName; @@ -894,12 +1093,9 @@ void Image::decompose(Asset& asset, const std::string& folder) std::ofstream file(filename, std::ios::binary); file.write((const char*)buffer.mData.data() + bufferView.mByteOffset, bufferView.mByteLength); - - buffer.erase(asset, bufferView.mByteOffset, bufferView.mByteLength); - - asset.eraseBufferView(mBufferView); } +#if 0 if (!mData.empty()) { // save j2c image @@ -907,21 +1103,44 @@ void Image::decompose(Asset& asset, const std::string& folder) LLPointer raw = new LLImageRaw(mWidth, mHeight, mComponent); U8* data = raw->allocateData(); - llassert(mData.size() == raw->getDataSize()); + llassert_always(mData.size() == raw->getDataSize()); memcpy(data, mData.data(), mData.size()); LLViewerTextureList::createUploadFile(raw, filename, 4096); mData.clear(); } +#endif - mWidth = -1; - mHeight = -1; - mComponent = -1; - mBits = -1; - mPixelType = -1; - mMimeType = ""; + clearData(asset); +} + +void Material::TextureInfo::serialize(object& dst) const +{ + write(mIndex, "index", dst, INVALID_INDEX); + write(mTexCoord, "texCoord", dst, 0); +} + +const Material::TextureInfo& Material::TextureInfo::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "index", mIndex); + copy(src, "texCoord", mTexCoord); + } + + return *this; +} + +bool Material::TextureInfo::operator==(const Material::TextureInfo& rhs) const +{ + return mIndex == rhs.mIndex && mTexCoord == rhs.mTexCoord; +} + +bool Material::TextureInfo::operator!=(const Material::TextureInfo& rhs) const +{ + return !(*this == rhs); } const Material::TextureInfo& Material::TextureInfo::operator=(const tinygltf::TextureInfo& src) @@ -931,6 +1150,25 @@ const Material::TextureInfo& Material::TextureInfo::operator=(const tinygltf::Te return *this; } +void Material::OcclusionTextureInfo::serialize(object& dst) const +{ + write(mIndex, "index", dst, INVALID_INDEX); + write(mTexCoord, "texCoord", dst, 0); + write(mStrength, "strength", dst, 1.f); +} + +const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "index", mIndex); + copy(src, "texCoord", mTexCoord); + copy(src, "strength", mStrength); + } + + return *this; +} + const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=(const tinygltf::OcclusionTextureInfo& src) { mIndex = src.index; @@ -939,6 +1177,24 @@ const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=( return *this; } +void Material::NormalTextureInfo::serialize(object& dst) const +{ + write(mIndex, "index", dst, INVALID_INDEX); + write(mTexCoord, "texCoord", dst, 0); + write(mScale, "scale", dst, 1.f); +} + +const Material::NormalTextureInfo& Material::NormalTextureInfo::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "index", mIndex); + copy(src, "texCoord", mTexCoord); + copy(src, "scale", mScale); + } + + return *this; +} const Material::NormalTextureInfo& Material::NormalTextureInfo::operator=(const tinygltf::NormalTextureInfo& src) { mIndex = src.index; @@ -947,11 +1203,48 @@ const Material::NormalTextureInfo& Material::NormalTextureInfo::operator=(const return *this; } +const Material::PbrMetallicRoughness& Material::PbrMetallicRoughness::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "baseColorFactor", mBaseColorFactor); + copy(src, "baseColorTexture", mBaseColorTexture); + copy(src, "metallicFactor", mMetallicFactor); + copy(src, "roughnessFactor", mRoughnessFactor); + copy(src, "metallicRoughnessTexture", mMetallicRoughnessTexture); + } + + return *this; +} + +void Material::PbrMetallicRoughness::serialize(object& dst) const +{ + write(mBaseColorFactor, "baseColorFactor", dst, vec4(1.f, 1.f, 1.f, 1.f)); + write(mBaseColorTexture, "baseColorTexture", dst); + write(mMetallicFactor, "metallicFactor", dst, 1.f); + write(mRoughnessFactor, "roughnessFactor", dst, 1.f); + write(mMetallicRoughnessTexture, "metallicRoughnessTexture", dst); +} + +bool Material::PbrMetallicRoughness::operator==(const Material::PbrMetallicRoughness& rhs) const +{ + return mBaseColorFactor == rhs.mBaseColorFactor && + mBaseColorTexture == rhs.mBaseColorTexture && + mMetallicFactor == rhs.mMetallicFactor && + mRoughnessFactor == rhs.mRoughnessFactor && + mMetallicRoughnessTexture == rhs.mMetallicRoughnessTexture; +} + +bool Material::PbrMetallicRoughness::operator!=(const Material::PbrMetallicRoughness& rhs) const +{ + return !(*this == rhs); +} + const Material::PbrMetallicRoughness& Material::PbrMetallicRoughness::operator=(const tinygltf::PbrMetallicRoughness& src) { if (src.baseColorFactor.size() == 4) { - mBaseColorFactor.set_value(src.baseColorFactor[0], src.baseColorFactor[1], src.baseColorFactor[2], src.baseColorFactor[3]); + mBaseColorFactor = vec4(src.baseColorFactor[0], src.baseColorFactor[1], src.baseColorFactor[2], src.baseColorFactor[3]); } mBaseColorTexture = src.baseColorTexture; @@ -961,13 +1254,129 @@ const Material::PbrMetallicRoughness& Material::PbrMetallicRoughness::operator=( return *this; } + +static void bindTexture(Asset& asset, S32 uniform, Material::TextureInfo& info, LLViewerTexture* fallback) +{ + if (info.mIndex != INVALID_INDEX) + { + LLViewerTexture* tex = asset.mImages[asset.mTextures[info.mIndex].mSource].mTexture; + if (tex) + { + tex->addTextureStats(2048.f * 2048.f); + LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, tex); + } + else + { + LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, fallback); + } + } + else + { + LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, fallback); + } +} + +void Material::bind(Asset& asset) +{ + // bind for rendering (derived from LLFetchedGLTFMaterial::bind) + // glTF 2.0 Specification 3.9.4. Alpha Coverage + // mAlphaCutoff is only valid for LLGLTFMaterial::ALPHA_MODE_MASK + F32 min_alpha = -1.0; + + LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; + + if (!LLPipeline::sShadowRender || (mAlphaMode == Material::AlphaMode::BLEND)) + { + if (mAlphaMode == Material::AlphaMode::MASK) + { + // dividing the alpha cutoff by transparency here allows the shader to compare against + // the alpha value of the texture without needing the transparency value + if (mPbrMetallicRoughness.mBaseColorFactor.a > 0.f) + { + min_alpha = mAlphaCutoff / mPbrMetallicRoughness.mBaseColorFactor.a; + } + else + { + min_alpha = 1024.f; + } + } + shader->uniform1f(LLShaderMgr::MINIMUM_ALPHA, min_alpha); + } + + bindTexture(asset, LLShaderMgr::DIFFUSE_MAP, mPbrMetallicRoughness.mBaseColorTexture, LLViewerFetchedTexture::sWhiteImagep); + + F32 base_color_packed[8]; + //mTextureTransform[GLTF_TEXTURE_INFO_BASE_COLOR].getPacked(base_color_packed); + LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR].getPacked(base_color_packed); + shader->uniform4fv(LLShaderMgr::TEXTURE_BASE_COLOR_TRANSFORM, 2, (F32*)base_color_packed); + + if (!LLPipeline::sShadowRender) + { + bindTexture(asset, LLShaderMgr::BUMP_MAP, mNormalTexture, LLViewerFetchedTexture::sFlatNormalImagep); + bindTexture(asset, LLShaderMgr::SPECULAR_MAP, mPbrMetallicRoughness.mMetallicRoughnessTexture, LLViewerFetchedTexture::sWhiteImagep); + bindTexture(asset, LLShaderMgr::EMISSIVE_MAP, mEmissiveTexture, LLViewerFetchedTexture::sWhiteImagep); + + // NOTE: base color factor is baked into vertex stream + + shader->uniform1f(LLShaderMgr::ROUGHNESS_FACTOR, mPbrMetallicRoughness.mRoughnessFactor); + shader->uniform1f(LLShaderMgr::METALLIC_FACTOR, mPbrMetallicRoughness.mMetallicFactor); + shader->uniform3fv(LLShaderMgr::EMISSIVE_COLOR, 1, glm::value_ptr(mEmissiveFactor)); + + F32 normal_packed[8]; + //mTextureTransform[GLTF_TEXTURE_INFO_NORMAL].getPacked(normal_packed); + LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL].getPacked(normal_packed); + shader->uniform4fv(LLShaderMgr::TEXTURE_NORMAL_TRANSFORM, 2, (F32*)normal_packed); + + F32 metallic_roughness_packed[8]; + //mTextureTransform[GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].getPacked(metallic_roughness_packed); + LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].getPacked(metallic_roughness_packed); + shader->uniform4fv(LLShaderMgr::TEXTURE_METALLIC_ROUGHNESS_TRANSFORM, 2, (F32*)metallic_roughness_packed); + + F32 emissive_packed[8]; + //mTextureTransform[GLTF_TEXTURE_INFO_EMISSIVE].getPacked(emissive_packed); + LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE].getPacked(emissive_packed); + shader->uniform4fv(LLShaderMgr::TEXTURE_EMISSIVE_TRANSFORM, 2, (F32*)emissive_packed); + } +} + +void Material::serialize(object& dst) const +{ + write(mName, "name", dst); + write(mEmissiveFactor, "emissiveFactor", dst, vec3(0.f, 0.f, 0.f)); + write(mPbrMetallicRoughness, "pbrMetallicRoughness", dst); + write(mNormalTexture, "normalTexture", dst); + write(mOcclusionTexture, "occlusionTexture", dst); + write(mEmissiveTexture, "emissiveTexture", dst); + write(mAlphaMode, "alphaMode", dst, Material::AlphaMode::OPAQUE); + write(mAlphaCutoff, "alphaCutoff", dst, 0.5f); + write(mDoubleSided, "doubleSided", dst, false); +} + +const Material& Material::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "name", mName); + copy(src, "emissiveFactor", mEmissiveFactor); + copy(src, "pbrMetallicRoughness", mPbrMetallicRoughness); + copy(src, "normalTexture", mNormalTexture); + copy(src, "occlusionTexture", mOcclusionTexture); + copy(src, "emissiveTexture", mEmissiveTexture); + copy(src, "alphaMode", mAlphaMode); + copy(src, "alphaCutoff", mAlphaCutoff); + copy(src, "doubleSided", mDoubleSided); + } + return *this; +} + + const Material& Material::operator=(const tinygltf::Material& src) { mName = src.name; if (src.emissiveFactor.size() == 3) { - mEmissiveFactor.set_value(src.emissiveFactor[0], src.emissiveFactor[1], src.emissiveFactor[2]); + mEmissiveFactor = vec3(src.emissiveFactor[0], src.emissiveFactor[1], src.emissiveFactor[2]); } mPbrMetallicRoughness = src.pbrMetallicRoughness; @@ -975,7 +1384,7 @@ const Material& Material::operator=(const tinygltf::Material& src) mOcclusionTexture = src.occlusionTexture; mEmissiveTexture = src.emissiveTexture; - mAlphaMode = src.alphaMode; + mAlphaMode = gltf_alpha_mode_to_enum(src.alphaMode); mAlphaCutoff = src.alphaCutoff; mDoubleSided = src.doubleSided; @@ -984,10 +1393,31 @@ const Material& Material::operator=(const tinygltf::Material& src) void Material::allocateGLResources(Asset& asset) { - // allocate material + // HACK: allocate an LLFetchedGLTFMaterial for now + // later we'll render directly from the GLTF Images + // and BufferViews mMaterial = new LLFetchedGLTFMaterial(); } +void Mesh::serialize(object& dst) const +{ + write(mPrimitives, "primitives", dst); + write(mWeights, "weights", dst); + write(mName, "name", dst); +} + +const Mesh& Mesh::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "primitives", mPrimitives); + copy(src, "weights", mWeights); + copy(src, "name", mName); + } + + return *this; + +} const Mesh& Mesh::operator=(const tinygltf::Mesh& src) { mPrimitives.resize(src.primitives.size()); @@ -1010,6 +1440,20 @@ void Mesh::allocateGLResources(Asset& asset) } } +void Scene::serialize(object& dst) const +{ + write(mNodes, "nodes", dst); + write(mName, "name", dst); +} + +const Scene& Scene::operator=(const Value& src) +{ + copy(src, "nodes", mNodes); + copy(src, "name", mName); + + return *this; +} + const Scene& Scene::operator=(const tinygltf::Scene& src) { mNodes = src.nodes; @@ -1018,6 +1462,25 @@ const Scene& Scene::operator=(const tinygltf::Scene& src) return *this; } +void Texture::serialize(object& dst) const +{ + write(mSampler, "sampler", dst, INVALID_INDEX); + write(mSource, "source", dst, INVALID_INDEX); + write(mName, "name", dst); +} + +const Texture& Texture::operator=(const Value& src) +{ + if (src.is_object()) + { + copy(src, "sampler", mSampler); + copy(src, "source", mSource); + copy(src, "name", mName); + } + + return *this; +} + const Texture& Texture::operator=(const tinygltf::Texture& src) { mSampler = src.sampler; @@ -1027,6 +1490,27 @@ const Texture& Texture::operator=(const tinygltf::Texture& src) return *this; } + +void Sampler::serialize(object& dst) const +{ + write(mMagFilter, "magFilter", dst, LINEAR); + write(mMinFilter, "minFilter", dst, LINEAR_MIPMAP_LINEAR); + write(mWrapS, "wrapS", dst, REPEAT); + write(mWrapT, "wrapT", dst, REPEAT); + write(mName, "name", dst); +} + +const Sampler& Sampler::operator=(const Value& src) +{ + copy(src, "magFilter", mMagFilter); + copy(src, "minFilter", mMinFilter); + copy(src, "wrapS", mWrapS); + copy(src, "wrapT", mWrapT); + copy(src, "name", mName); + + return *this; +} + const Sampler& Sampler::operator=(const tinygltf::Sampler& src) { mMagFilter = src.magFilter; @@ -1043,23 +1527,14 @@ void Skin::uploadMatrixPalette(Asset& asset, Node& node) // prepare matrix palette // modelview will be applied by the shader, so assume matrix palette is in asset space - std::vector t_mp; + std::vector t_mp; t_mp.resize(mJoints.size()); for (U32 i = 0; i < mJoints.size(); ++i) { Node& joint = asset.mNodes[mJoints[i]]; - - //t_mp[i].set_value(joint.mRenderMatrix.getF32ptr()); - //t_mp[i] = t_mp[i] * mInverseBindMatricesData[i]; - - //t_mp[i].set_value(joint.mRenderMatrix.getF32ptr()); - //t_mp[i] = mInverseBindMatricesData[i] * t_mp[i]; - - t_mp[i].set_value(joint.mRenderMatrix.getF32ptr()); - t_mp[i] = t_mp[i] * mInverseBindMatricesData[i]; - + t_mp[i] = joint.mRenderMatrix * mInverseBindMatricesData[i]; } std::vector glmp; @@ -1070,7 +1545,7 @@ void Skin::uploadMatrixPalette(Asset& asset, Node& node) for (U32 i = 0; i < mJoints.size(); ++i) { - F32* m = (F32*)t_mp[i].m; + F32* m = glm::value_ptr(t_mp[i]); U32 idx = i * 12; -- cgit v1.2.3 From 2f4120038429c6aff865f153f708ceefb60d67f4 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 28 May 2024 09:45:40 -0500 Subject: Remove tinygltf dependency from LL::GLTF (#1541) * #1535 Image loading/saving support in boost::json driven GLTF parser * #1536 GLB Support in boost::json drvien GLTF parser --- indra/newview/gltf/asset.cpp | 862 +++++++++++++++---------------------------- 1 file changed, 302 insertions(+), 560 deletions(-) (limited to 'indra/newview/gltf/asset.cpp') diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index c64d48662c..485984fac1 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -33,6 +33,8 @@ #include "../llviewertexturelist.h" #include "../pipeline.h" #include "buffer_util.h" +#include +#include "llimagejpeg.h" using namespace LL::GLTF; using namespace boost::json; @@ -75,268 +77,14 @@ namespace LL return "OPAQUE"; } } - - template - void copy(const std::vector& src, std::vector& dst) - { - dst.resize(src.size()); - for (U32 i = 0; i < src.size(); ++i) - { - copy(src[i], dst[i]); - } - } - - void copy(const Node& src, tinygltf::Node& dst) - { - if (src.mMatrixValid) - { - if (src.mMatrix != glm::identity()) - { - dst.matrix.resize(16); - const F32* m = glm::value_ptr(src.mMatrix); - for (U32 i = 0; i < 16; ++i) - { - dst.matrix[i] = m[i]; - } - } - } - else if (src.mTRSValid) - { - if (src.mRotation != glm::identity()) - { - dst.rotation.resize(4); - dst.rotation[0] = src.mRotation.x; - dst.rotation[1] = src.mRotation.y; - dst.rotation[2] = src.mRotation.z; - dst.rotation[3] = src.mRotation.w; - } - - if (src.mTranslation != vec3(0.f, 0.f, 0.f)) - { - dst.translation.resize(3); - dst.translation[0] = src.mTranslation.x; - dst.translation[1] = src.mTranslation.y; - dst.translation[2] = src.mTranslation.z; - } - - if (src.mScale != vec3(1.f, 1.f, 1.f)) - { - dst.scale.resize(3); - dst.scale[0] = src.mScale.x; - dst.scale[1] = src.mScale.y; - dst.scale[2] = src.mScale.z; - } - } - - dst.children = src.mChildren; - dst.mesh = src.mMesh; - dst.skin = src.mSkin; - dst.name = src.mName; - } - - void copy(const Scene& src, tinygltf::Scene& dst) - { - dst.nodes = src.mNodes; - dst.name = src.mName; - } - - void copy(const Primitive& src, tinygltf::Primitive& dst) - { - for (auto& attrib : src.mAttributes) - { - dst.attributes[attrib.first] = attrib.second; - } - dst.indices = src.mIndices; - dst.material = src.mMaterial; - dst.mode = src.mMode; - } - - void copy(const Mesh& src, tinygltf::Mesh& mesh) - { - copy(src.mPrimitives, mesh.primitives); - mesh.weights = src.mWeights; - mesh.name = src.mName; - } - - void copy(const Material::TextureInfo& src, tinygltf::TextureInfo& dst) - { - dst.index = src.mIndex; - dst.texCoord = src.mTexCoord; - } - - void copy(const Material::OcclusionTextureInfo& src, tinygltf::OcclusionTextureInfo& dst) - { - dst.index = src.mIndex; - dst.texCoord = src.mTexCoord; - dst.strength = src.mStrength; - } - - void copy(const Material::NormalTextureInfo& src, tinygltf::NormalTextureInfo& dst) - { - dst.index = src.mIndex; - dst.texCoord = src.mTexCoord; - dst.scale = src.mScale; - } - - void copy(const Material::PbrMetallicRoughness& src, tinygltf::PbrMetallicRoughness& dst) - { - dst.baseColorFactor = { src.mBaseColorFactor.r, src.mBaseColorFactor.g, src.mBaseColorFactor.b, src.mBaseColorFactor.a }; - copy(src.mBaseColorTexture, dst.baseColorTexture); - dst.metallicFactor = src.mMetallicFactor; - dst.roughnessFactor = src.mRoughnessFactor; - copy(src.mMetallicRoughnessTexture, dst.metallicRoughnessTexture); - } - - void copy(const Material& src, tinygltf::Material& material) - { - material.name = src.mName; - - material.emissiveFactor = { src.mEmissiveFactor.r, src.mEmissiveFactor.g, src.mEmissiveFactor.b }; - copy(src.mPbrMetallicRoughness, material.pbrMetallicRoughness); - copy(src.mNormalTexture, material.normalTexture); - copy(src.mEmissiveTexture, material.emissiveTexture); - } - - void copy(const Texture& src, tinygltf::Texture& texture) - { - texture.sampler = src.mSampler; - texture.source = src.mSource; - texture.name = src.mName; - } - - void copy(const Sampler& src, tinygltf::Sampler& sampler) - { - sampler.magFilter = src.mMagFilter; - sampler.minFilter = src.mMinFilter; - sampler.wrapS = src.mWrapS; - sampler.wrapT = src.mWrapT; - sampler.name = src.mName; - } - - void copy(const Skin& src, tinygltf::Skin& skin) - { - skin.joints = src.mJoints; - skin.inverseBindMatrices = src.mInverseBindMatrices; - skin.skeleton = src.mSkeleton; - skin.name = src.mName; - } - - void copy(const Accessor& src, tinygltf::Accessor& accessor) - { - accessor.bufferView = src.mBufferView; - accessor.byteOffset = src.mByteOffset; - accessor.componentType = src.mComponentType; - accessor.minValues = src.mMin; - accessor.maxValues = src.mMax; - - accessor.count = src.mCount; - accessor.type = (S32) src.mType; - accessor.normalized = src.mNormalized; - accessor.name = src.mName; - } - - void copy(const Animation::Sampler& src, tinygltf::AnimationSampler& sampler) - { - sampler.input = src.mInput; - sampler.output = src.mOutput; - sampler.interpolation = src.mInterpolation; - } - - void copy(const Animation::Channel& src, tinygltf::AnimationChannel& channel) - { - channel.sampler = src.mSampler; - channel.target_node = src.mTarget.mNode; - channel.target_path = src.mTarget.mPath; - } - - void copy(const Animation& src, tinygltf::Animation& animation) - { - animation.name = src.mName; - - copy(src.mSamplers, animation.samplers); - - U32 channel_count = src.mRotationChannels.size() + src.mTranslationChannels.size() + src.mScaleChannels.size(); - - animation.channels.resize(channel_count); - - U32 idx = 0; - for (U32 i = 0; i < src.mTranslationChannels.size(); ++i) - { - copy(src.mTranslationChannels[i], animation.channels[idx++]); - } - - for (U32 i = 0; i < src.mRotationChannels.size(); ++i) - { - copy(src.mRotationChannels[i], animation.channels[idx++]); - } - - for (U32 i = 0; i < src.mScaleChannels.size(); ++i) - { - copy(src.mScaleChannels[i], animation.channels[idx++]); - } - } - - void copy(const Buffer& src, tinygltf::Buffer& buffer) - { - buffer.uri = src.mUri; - buffer.data = src.mData; - buffer.name = src.mName; - } - - void copy(const BufferView& src, tinygltf::BufferView& bufferView) - { - bufferView.buffer = src.mBuffer; - bufferView.byteOffset = src.mByteOffset; - bufferView.byteLength = src.mByteLength; - bufferView.byteStride = src.mByteStride; - bufferView.target = src.mTarget; - bufferView.name = src.mName; - } - - void copy(const Image& src, tinygltf::Image& image) - { - image.name = src.mName; - image.width = src.mWidth; - image.height = src.mHeight; - image.component = src.mComponent; - image.bits = src.mBits; - image.pixel_type = src.mPixelType; - - image.image = src.mData; - image.bufferView = src.mBufferView; - image.mimeType = src.mMimeType; - image.uri = src.mUri; - } - - void copy(const Asset & src, tinygltf::Model& dst) - { - dst.defaultScene = src.mDefaultScene; - dst.asset.copyright = src.mCopyright; - dst.asset.version = src.mVersion; - dst.asset.minVersion = src.mMinVersion; - dst.asset.generator = "Linden Lab Experimental GLTF Export"; - - // NOTE: extras are lost in the conversion for now - - copy(src.mScenes, dst.scenes); - copy(src.mNodes, dst.nodes); - copy(src.mMeshes, dst.meshes); - copy(src.mMaterials, dst.materials); - copy(src.mBuffers, dst.buffers); - copy(src.mBufferViews, dst.bufferViews); - copy(src.mTextures, dst.textures); - copy(src.mSamplers, dst.samplers); - copy(src.mImages, dst.images); - copy(src.mAccessors, dst.accessors); - copy(src.mAnimations, dst.animations); - copy(src.mSkins, dst.skins); - } } } + + void Scene::updateTransforms(Asset& asset) { mat4 identity = glm::identity(); - + for (auto& nodeIndex : mNodes) { Node& node = asset.mNodes[nodeIndex]; @@ -368,9 +116,9 @@ void Node::updateTransforms(Asset& asset, const mat4& parentMatrix) { makeMatrixValid(); mAssetMatrix = parentMatrix * mMatrix; - + mAssetMatrixInv = glm::inverse(mAssetMatrix); - + S32 my_index = this - &asset.mNodes[0]; for (auto& childIndex : mChildren) @@ -419,7 +167,6 @@ S32 Asset::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, { if (node.mMesh != INVALID_INDEX) { - bool newHit = false; LLMatrix4a ami; @@ -452,7 +199,7 @@ S32 Asset::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, LLMatrix4a am; am.loadu(glm::value_ptr(node.mAssetMatrix)); // shorten line segment on hit - am.affineTransform(p, asset_end); + am.affineTransform(p, asset_end); // transform results back to asset space if (intersection) @@ -521,7 +268,7 @@ void Node::makeTRSValid() vec3 skew; vec4 perspective; glm::decompose(mMatrix, mScale, mRotation, mTranslation, skew, perspective); - + mTRSValid = true; } @@ -577,59 +324,6 @@ const Node& Node::operator=(const Value& src) { mTRSValid = true; } - - return *this; -} - -const Node& Node::operator=(const tinygltf::Node& src) -{ - F32* dstMatrix = glm::value_ptr(mMatrix); - - if (src.matrix.size() == 16) - { - // Node has a transformation matrix, just copy it - for (U32 i = 0; i < 16; ++i) - { - dstMatrix[i] = (F32)src.matrix[i]; - } - - mMatrixValid = true; - } - else if (!src.rotation.empty() || !src.translation.empty() || !src.scale.empty()) - { - // node has rotation/translation/scale, convert to matrix - if (src.rotation.size() == 4) - { - mRotation = quat((F32)src.rotation[3], (F32)src.rotation[0], (F32)src.rotation[1], (F32)src.rotation[2]); - } - - if (src.translation.size() == 3) - { - mTranslation = vec3((F32)src.translation[0], (F32)src.translation[1], (F32)src.translation[2]); - } - - if (src.scale.size() == 3) - { - mScale = vec3((F32)src.scale[0], (F32)src.scale[1], (F32)src.scale[2]); - } - else - { - mScale = vec3(1.f, 1.f, 1.f); - } - - mTRSValid = true; - } - else - { - // node specifies no transformation, set to identity - mMatrix = glm::identity(); - mMatrixValid = true; - } - - mChildren = src.children; - mMesh = src.mesh; - mSkin = src.skin; - mName = src.name; return *this; } @@ -662,22 +356,6 @@ const Image& Image::operator=(const Value& src) return *this; } -const Image& Image::operator=(const tinygltf::Image& src) -{ - mName = src.name; - mWidth = src.width; - mHeight = src.height; - mComponent = src.component; - mBits = src.bits; - mPixelType = src.pixel_type; - mUri = src.uri; - mBufferView = src.bufferView; - mMimeType = src.mimeType; - mData = src.image; - return *this; -} - - void Asset::render(bool opaque, bool rigged) { if (rigged) @@ -726,14 +404,8 @@ void Asset::render(bool opaque, bool rigged) continue; } - if (mMaterials[primitive.mMaterial].mMaterial.notNull()) - { - material.mMaterial->bind(); - } - else - { - material.bind(*this); - } + material.bind(*this); + cull = !material.mDoubleSided; } else @@ -792,45 +464,50 @@ void Asset::update() } } -void Asset::allocateGLResources(const std::string& filename, const tinygltf::Model& model) +bool Asset::prep() { - // do images first as materials may depend on images - for (auto& image : mImages) + // do buffers first as other resources depend on them + for (auto& buffer : mBuffers) { - image.allocateGLResources(); + if (!buffer.prep(*this)) + { + return false; + } } - - // do materials before meshes as meshes may depend on materials - if (!filename.empty()) + for (auto& image : mImages) { - for (U32 i = 0; i < mMaterials.size(); ++i) + if (!image.prep(*this)) { - // HACK: local preview mode, load material from model for now - mMaterials[i].allocateGLResources(*this); - LLTinyGLTFHelper::getMaterialFromModel(filename, model, i, mMaterials[i].mMaterial, mMaterials[i].mName, true); + return false; } } for (auto& mesh : mMeshes) { - mesh.allocateGLResources(*this); + if (!mesh.prep(*this)) + { + return false; + } } for (auto& animation : mAnimations) { - animation.allocateGLResources(*this); + if (!animation.prep(*this)) + { + return false; + } } for (auto& skin : mSkins) { - skin.allocateGLResources(*this); + if (!skin.prep(*this)) + { + return false; + } } -} -Asset::Asset(const tinygltf::Model& src) -{ - *this = src; + return true; } Asset::Asset(const Value& src) @@ -838,90 +515,141 @@ Asset::Asset(const Value& src) *this = src; } -const Asset& Asset::operator=(const tinygltf::Model& src) +bool Asset::load(std::string_view filename) { - mVersion = src.asset.version; - mMinVersion = src.asset.minVersion; - mGenerator = src.asset.generator; - mCopyright = src.asset.copyright; + mFilename = filename; + std::string ext = gDirUtilp->getExtension(mFilename); - // note: extras are lost in the conversion for now - - mDefaultScene = src.defaultScene; - - mScenes.resize(src.scenes.size()); - for (U32 i = 0; i < src.scenes.size(); ++i) + std::ifstream file(filename.data(), std::ios::binary); + if (file.is_open()) { - mScenes[i] = src.scenes[i]; - } + std::string str((std::istreambuf_iterator(file)), std::istreambuf_iterator()); + file.close(); - mNodes.resize(src.nodes.size()); - for (U32 i = 0; i < src.nodes.size(); ++i) - { - mNodes[i] = src.nodes[i]; + if (ext == "gltf") + { + Value val = parse(str); + *this = val; + return prep(); + } + else if (ext == "glb") + { + return loadBinary(str); + } + else + { + LL_WARNS() << "Unsupported file type: " << ext << LL_ENDL; + return false; + } } - - mMeshes.resize(src.meshes.size()); - for (U32 i = 0; i < src.meshes.size(); ++i) + else { - mMeshes[i] = src.meshes[i]; + LL_WARNS() << "Failed to open file: " << filename << LL_ENDL; + return false; } - mMaterials.resize(src.materials.size()); - for (U32 i = 0; i < src.materials.size(); ++i) - { - mMaterials[i] = src.materials[i]; - } + return false; +} - mBuffers.resize(src.buffers.size()); - for (U32 i = 0; i < src.buffers.size(); ++i) - { - mBuffers[i] = src.buffers[i]; - } +bool Asset::loadBinary(const std::string& data) +{ + // load from binary gltf + const U8* ptr = (const U8*)data.data(); + const U8* end = ptr + data.size(); - mBufferViews.resize(src.bufferViews.size()); - for (U32 i = 0; i < src.bufferViews.size(); ++i) + if (end - ptr < 12) { - mBufferViews[i] = src.bufferViews[i]; + LL_WARNS("GLTF") << "GLB file too short" << LL_ENDL; + return false; } - mTextures.resize(src.textures.size()); - for (U32 i = 0; i < src.textures.size(); ++i) + U32 magic = *(U32*)ptr; + ptr += 4; + + if (magic != 0x46546C67) { - mTextures[i] = src.textures[i]; + LL_WARNS("GLTF") << "Invalid GLB magic" << LL_ENDL; + return false; } - mSamplers.resize(src.samplers.size()); - for (U32 i = 0; i < src.samplers.size(); ++i) + U32 version = *(U32*)ptr; + ptr += 4; + + if (version != 2) { - mSamplers[i] = src.samplers[i]; + LL_WARNS("GLTF") << "Unsupported GLB version" << LL_ENDL; + return false; } - mImages.resize(src.images.size()); - for (U32 i = 0; i < src.images.size(); ++i) + U32 length = *(U32*)ptr; + ptr += 4; + + if (length != data.size()) { - mImages[i] = src.images[i]; + LL_WARNS("GLTF") << "GLB length mismatch" << LL_ENDL; + return false; } - mAccessors.resize(src.accessors.size()); - for (U32 i = 0; i < src.accessors.size(); ++i) + U32 chunkLength = *(U32*)ptr; + ptr += 4; + + if (end - ptr < chunkLength + 8) { - mAccessors[i] = src.accessors[i]; + LL_WARNS("GLTF") << "GLB chunk too short" << LL_ENDL; + return false; } - mAnimations.resize(src.animations.size()); - for (U32 i = 0; i < src.animations.size(); ++i) + U32 chunkType = *(U32*)ptr; + ptr += 4; + + if (chunkType != 0x4E4F534A) { - mAnimations[i] = src.animations[i]; + LL_WARNS("GLTF") << "Invalid GLB chunk type" << LL_ENDL; + return false; } - mSkins.resize(src.skins.size()); - for (U32 i = 0; i < src.skins.size(); ++i) + Value val = parse(std::string_view((const char*)ptr, chunkLength)); + *this = val; + + if (mBuffers.size() > 0 && mBuffers[0].mUri.empty()) { - mSkins[i] = src.skins[i]; + // load binary chunk + ptr += chunkLength; + + if (end - ptr < 8) + { + LL_WARNS("GLTF") << "GLB chunk too short" << LL_ENDL; + return false; + } + + chunkLength = *(U32*)ptr; + ptr += 4; + + chunkType = *(U32*)ptr; + ptr += 4; + + if (chunkType != 0x004E4942) + { + LL_WARNS("GLTF") << "Invalid GLB chunk type" << LL_ENDL; + return false; + } + + auto& buffer = mBuffers[0]; + + if (ptr + buffer.mByteLength <= end) + { + buffer.mData.resize(buffer.mByteLength); + memcpy(buffer.mData.data(), ptr, buffer.mByteLength); + ptr += buffer.mByteLength; + } + else + { + LL_WARNS("GLTF") << "Buffer too short" << LL_ENDL; + return false; + } } - - return *this; + + return prep(); } const Asset& Asset::operator=(const Value& src) @@ -943,7 +671,7 @@ const Asset& Asset::operator=(const Value& src) copy(asset, "extras", mExtras); } - copy(obj, "defaultScene", mDefaultScene); + copy(obj, "scene", mScene); copy(obj, "scenes", mScenes); copy(obj, "nodes", mNodes); copy(obj, "meshes", mMeshes); @@ -961,18 +689,17 @@ const Asset& Asset::operator=(const Value& src) return *this; } -void Asset::save(tinygltf::Model& dst) -{ - LL::GLTF::copy(*this, dst); -} - void Asset::serialize(object& dst) const { - write(mVersion, "version", dst); - write(mMinVersion, "minVersion", dst, std::string()); - write(mGenerator, "generator", dst); - write(mDefaultScene, "defaultScene", dst, 0); - + static const std::string sGenerator = "Linden Lab GLTF Prototype v0.1"; + + dst["asset"] = object{}; + object& asset = dst["asset"].get_object(); + + write(mVersion, "version", asset); + write(mMinVersion, "minVersion", asset, std::string()); + write(sGenerator, "generator", asset); + write(mScene, "scene", dst, INVALID_INDEX); write(mScenes, "scenes", dst); write(mNodes, "nodes", dst); write(mMeshes, "meshes", dst); @@ -987,16 +714,39 @@ void Asset::serialize(object& dst) const write(mSkins, "skins", dst); } -void Asset::decompose(const std::string& filename) +bool Asset::save(const std::string& filename) { // get folder path std::string folder = gDirUtilp->getDirName(filename); - // decompose images + // save images for (auto& image : mImages) { - image.decompose(*this, folder); + if (!image.save(*this, folder)) + { + return false; + } + } + + // save buffers + // NOTE: save buffers after saving images as saving images + // may remove image data from buffers + for (auto& buffer : mBuffers) + { + if (!buffer.save(*this, folder)) + { + return false; + } } + + // save .gltf + object obj; + serialize(obj); + std::string buffer = boost::json::serialize(obj, {}); + std::ofstream file(filename, std::ios::binary); + file.write(buffer.c_str(), buffer.size()); + + return true; } void Asset::eraseBufferView(S32 bufferView) @@ -1023,13 +773,63 @@ void Asset::eraseBufferView(S32 bufferView) LLViewerFetchedTexture* fetch_texture(const LLUUID& id); -void Image::allocateGLResources() +bool Image::prep(Asset& asset) { LLUUID id; - if (LLUUID::parseUUID(mUri, &id) && id.notNull()) - { + if (mUri.size() == UUID_STR_SIZE && LLUUID::parseUUID(mUri, &id) && id.notNull()) + { // loaded from an asset, fetch the texture from the asset system mTexture = fetch_texture(id); } + else if (mUri.find("data:") == 0) + { // embedded in a data URI, load the texture from the URI + LL_WARNS() << "Data URIs not yet supported" << LL_ENDL; + return false; + } + else if (mBufferView != INVALID_INDEX) + { // embedded in a buffer, load the texture from the buffer + BufferView& bufferView = asset.mBufferViews[mBufferView]; + Buffer& buffer = asset.mBuffers[bufferView.mBuffer]; + + U8* data = buffer.mData.data() + bufferView.mByteOffset; + + mTexture = LLViewerTextureManager::getFetchedTextureFromMemory(data, bufferView.mByteLength, mMimeType); + + if (mTexture.isNull()) + { + LL_WARNS("GLTF") << "Failed to load image from buffer:" << LL_ENDL; + LL_WARNS("GLTF") << " image: " << mName << LL_ENDL; + LL_WARNS("GLTF") << " mimeType: " << mMimeType << LL_ENDL; + + return false; + } + } + else if (!asset.mFilename.empty() && !mUri.empty()) + { // loaded locally and not embedded, load the texture as a local preview + std::string dir = gDirUtilp->getDirName(asset.mFilename); + std::string img_file = dir + gDirUtilp->getDirDelimiter() + mUri; + + LLUUID tracking_id = LLLocalBitmapMgr::getInstance()->addUnit(img_file); + if (tracking_id.notNull()) + { + LLUUID world_id = LLLocalBitmapMgr::getInstance()->getWorldID(tracking_id); + mTexture = LLViewerTextureManager::getFetchedTexture(world_id); + } + else + { + LL_WARNS("GLTF") << "Failed to load image from file:" << LL_ENDL; + LL_WARNS("GLTF") << " image: " << mName << LL_ENDL; + LL_WARNS("GLTF") << " file: " << img_file << LL_ENDL; + + return false; + } + } + else + { + LL_WARNS("GLTF") << "Failed to load image: " << mName << LL_ENDL; + return false; + } + + return true; } @@ -1046,7 +846,6 @@ void Image::clearData(Asset& asset) asset.eraseBufferView(mBufferView); } - mData.clear(); mBufferView = INVALID_INDEX; mWidth = -1; mHeight = -1; @@ -1056,9 +855,15 @@ void Image::clearData(Asset& asset) mMimeType = ""; } -void Image::decompose(Asset& asset, const std::string& folder) +bool Image::save(Asset& asset, const std::string& folder) { + // NOTE: this *MUST* be a lossless save + // Artists use this to save their work repeatedly, so + // adding any compression artifacts here will degrade + // images over time. std::string name = mName; + std::string error; + const std::string& delim = gDirUtilp->getDirDelimiter(); if (name.empty()) { S32 idx = this - asset.mImages.data(); @@ -1067,10 +872,11 @@ void Image::decompose(Asset& asset, const std::string& folder) if (mBufferView != INVALID_INDEX) { - // save original image + // we have the bytes of the original image, save that out in its + // original format BufferView& bufferView = asset.mBufferViews[mBufferView]; Buffer& buffer = asset.mBuffers[bufferView.mBuffer]; - + std::string extension; if (mMimeType == "image/jpeg") @@ -1083,37 +889,76 @@ void Image::decompose(Asset& asset, const std::string& folder) } else { + error = "Unknown mime type, saved as .bin"; extension = ".bin"; } - std::string filename = folder + "/" + name + "." + extension; + std::string filename = folder + delim + name + extension; // set URI to non-j2c file for now, but later we'll want to reference the j2c hash - mUri = name + "." + extension; + mUri = name + extension; std::ofstream file(filename, std::ios::binary); file.write((const char*)buffer.mData.data() + bufferView.mByteOffset, bufferView.mByteLength); } - -#if 0 - if (!mData.empty()) + else if (mTexture.notNull()) { - // save j2c image - std::string filename = folder + "/" + name + ".j2c"; - - LLPointer raw = new LLImageRaw(mWidth, mHeight, mComponent); - U8* data = raw->allocateData(); - llassert_always(mData.size() == raw->getDataSize()); - memcpy(data, mData.data(), mData.size()); - - LLViewerTextureList::createUploadFile(raw, filename, 4096); + auto bitmapmgr = LLLocalBitmapMgr::getInstance(); + if (bitmapmgr->isLocal(mTexture->getID())) + { + LLUUID tracking_id = bitmapmgr->getTrackingID(mTexture->getID()); + if (tracking_id.notNull()) + { // copy original file to destination folder + std::string source = bitmapmgr->getFilename(tracking_id); + if (gDirUtilp->fileExists(source)) + { + std::string filename = gDirUtilp->getBaseFileName(source); + std::string dest = folder + delim + filename; - mData.clear(); + LLFile::copy(source, dest); + mUri = filename; + } + else + { + error = "File not found: " + source; + } + } + else + { + error = "Local image missing."; + } + } + else if (!mUri.empty()) + { + std::string from_dir = gDirUtilp->getDirName(asset.mFilename); + std::string base_filename = gDirUtilp->getBaseFileName(mUri); + std::string filename = from_dir + delim + base_filename; + if (gDirUtilp->fileExists(filename)) + { + std::string dest = folder + delim + base_filename; + LLFile::copy(filename, dest); + mUri = base_filename; + } + else + { + error = "Original image file not found: " + filename; + } + } + else + { + error = "Image is not a local image and has no uri, cannot save."; + } } -#endif + if (!error.empty()) + { + LL_WARNS("GLTF") << "Failed to save " << name << ": " << error << LL_ENDL; + return false; + } clearData(asset); + + return true; } void Material::TextureInfo::serialize(object& dst) const @@ -1143,13 +988,6 @@ bool Material::TextureInfo::operator!=(const Material::TextureInfo& rhs) const return !(*this == rhs); } -const Material::TextureInfo& Material::TextureInfo::operator=(const tinygltf::TextureInfo& src) -{ - mIndex = src.index; - mTexCoord = src.texCoord; - return *this; -} - void Material::OcclusionTextureInfo::serialize(object& dst) const { write(mIndex, "index", dst, INVALID_INDEX); @@ -1169,14 +1007,6 @@ const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=( return *this; } -const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=(const tinygltf::OcclusionTextureInfo& src) -{ - mIndex = src.index; - mTexCoord = src.texCoord; - mStrength = src.strength; - return *this; -} - void Material::NormalTextureInfo::serialize(object& dst) const { write(mIndex, "index", dst, INVALID_INDEX); @@ -1195,13 +1025,6 @@ const Material::NormalTextureInfo& Material::NormalTextureInfo::operator=(const return *this; } -const Material::NormalTextureInfo& Material::NormalTextureInfo::operator=(const tinygltf::NormalTextureInfo& src) -{ - mIndex = src.index; - mTexCoord = src.texCoord; - mScale = src.scale; - return *this; -} const Material::PbrMetallicRoughness& Material::PbrMetallicRoughness::operator=(const Value& src) { @@ -1240,21 +1063,6 @@ bool Material::PbrMetallicRoughness::operator!=(const Material::PbrMetallicRough return !(*this == rhs); } -const Material::PbrMetallicRoughness& Material::PbrMetallicRoughness::operator=(const tinygltf::PbrMetallicRoughness& src) -{ - if (src.baseColorFactor.size() == 4) - { - mBaseColorFactor = vec4(src.baseColorFactor[0], src.baseColorFactor[1], src.baseColorFactor[2], src.baseColorFactor[3]); - } - - mBaseColorTexture = src.baseColorTexture; - mMetallicFactor = src.metallicFactor; - mRoughnessFactor = src.roughnessFactor; - mMetallicRoughnessTexture = src.metallicRoughnessTexture; - - return *this; -} - static void bindTexture(Asset& asset, S32 uniform, Material::TextureInfo& info, LLViewerTexture* fallback) { if (info.mIndex != INVALID_INDEX) @@ -1312,10 +1120,10 @@ void Material::bind(Asset& asset) if (!LLPipeline::sShadowRender) { - bindTexture(asset, LLShaderMgr::BUMP_MAP, mNormalTexture, LLViewerFetchedTexture::sFlatNormalImagep); + bindTexture(asset, LLShaderMgr::BUMP_MAP, mNormalTexture, LLViewerFetchedTexture::sFlatNormalImagep); bindTexture(asset, LLShaderMgr::SPECULAR_MAP, mPbrMetallicRoughness.mMetallicRoughnessTexture, LLViewerFetchedTexture::sWhiteImagep); bindTexture(asset, LLShaderMgr::EMISSIVE_MAP, mEmissiveTexture, LLViewerFetchedTexture::sWhiteImagep); - + // NOTE: base color factor is baked into vertex stream shader->uniform1f(LLShaderMgr::ROUGHNESS_FACTOR, mPbrMetallicRoughness.mRoughnessFactor); @@ -1370,35 +1178,6 @@ const Material& Material::operator=(const Value& src) } -const Material& Material::operator=(const tinygltf::Material& src) -{ - mName = src.name; - - if (src.emissiveFactor.size() == 3) - { - mEmissiveFactor = vec3(src.emissiveFactor[0], src.emissiveFactor[1], src.emissiveFactor[2]); - } - - mPbrMetallicRoughness = src.pbrMetallicRoughness; - mNormalTexture = src.normalTexture; - mOcclusionTexture = src.occlusionTexture; - mEmissiveTexture = src.emissiveTexture; - - mAlphaMode = gltf_alpha_mode_to_enum(src.alphaMode); - mAlphaCutoff = src.alphaCutoff; - mDoubleSided = src.doubleSided; - - return *this; -} - -void Material::allocateGLResources(Asset& asset) -{ - // HACK: allocate an LLFetchedGLTFMaterial for now - // later we'll render directly from the GLTF Images - // and BufferViews - mMaterial = new LLFetchedGLTFMaterial(); -} - void Mesh::serialize(object& dst) const { write(mPrimitives, "primitives", dst); @@ -1418,26 +1197,18 @@ const Mesh& Mesh::operator=(const Value& src) return *this; } -const Mesh& Mesh::operator=(const tinygltf::Mesh& src) -{ - mPrimitives.resize(src.primitives.size()); - for (U32 i = 0; i < src.primitives.size(); ++i) - { - mPrimitives[i] = src.primitives[i]; - } - - mWeights = src.weights; - mName = src.name; - return *this; -} - -void Mesh::allocateGLResources(Asset& asset) +bool Mesh::prep(Asset& asset) { for (auto& primitive : mPrimitives) { - primitive.allocateGLResources(asset); + if (!primitive.prep(asset)) + { + return false; + } } + + return true; } void Scene::serialize(object& dst) const @@ -1450,14 +1221,6 @@ const Scene& Scene::operator=(const Value& src) { copy(src, "nodes", mNodes); copy(src, "name", mName); - - return *this; -} - -const Scene& Scene::operator=(const tinygltf::Scene& src) -{ - mNodes = src.nodes; - mName = src.name; return *this; } @@ -1481,16 +1244,6 @@ const Texture& Texture::operator=(const Value& src) return *this; } -const Texture& Texture::operator=(const tinygltf::Texture& src) -{ - mSampler = src.sampler; - mSource = src.source; - mName = src.name; - - return *this; -} - - void Sampler::serialize(object& dst) const { write(mMagFilter, "magFilter", dst, LINEAR); @@ -1511,17 +1264,6 @@ const Sampler& Sampler::operator=(const Value& src) return *this; } -const Sampler& Sampler::operator=(const tinygltf::Sampler& src) -{ - mMagFilter = src.magFilter; - mMinFilter = src.minFilter; - mWrapS = src.wrapS; - mWrapT = src.wrapT; - mName = src.name; - - return *this; -} - void Skin::uploadMatrixPalette(Asset& asset, Node& node) { // prepare matrix palette -- cgit v1.2.3 From 15fd13f83036ff781160957a21bb2d59771044bc Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 29 May 2024 16:56:39 -0500 Subject: #1530 Increase joint limit for GLTF Assets (#1582) * Migrate GLTF scene rendering to its own shaders * Add support for ambient occlusion map separate from metallic roughness map (or absent) * Use UBO's for GLTF joints * Better error handling of downloading GLTF assets --- indra/newview/gltf/asset.cpp | 229 ++----------------------------------------- 1 file changed, 7 insertions(+), 222 deletions(-) (limited to 'indra/newview/gltf/asset.cpp') diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index 485984fac1..7870eb28b0 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -84,7 +84,7 @@ namespace LL void Scene::updateTransforms(Asset& asset) { mat4 identity = glm::identity(); - + for (auto& nodeIndex : mNodes) { Node& node = asset.mNodes[nodeIndex]; @@ -116,7 +116,7 @@ void Node::updateTransforms(Asset& asset, const mat4& parentMatrix) { makeMatrixValid(); mAssetMatrix = parentMatrix * mMatrix; - + mAssetMatrixInv = glm::inverse(mAssetMatrix); S32 my_index = this - &asset.mNodes[0]; @@ -356,94 +356,6 @@ const Image& Image::operator=(const Value& src) return *this; } -void Asset::render(bool opaque, bool rigged) -{ - if (rigged) - { - gGL.loadIdentity(); - } - - for (auto& node : mNodes) - { - if (node.mSkin != INVALID_INDEX) - { - if (rigged) - { - Skin& skin = mSkins[node.mSkin]; - skin.uploadMatrixPalette(*this, node); - } - else - { - //skip static nodes if we're rendering rigged - continue; - } - } - else if (rigged) - { - // skip rigged nodes if we're not rendering rigged - continue; - } - - if (node.mMesh != INVALID_INDEX) - { - Mesh& mesh = mMeshes[node.mMesh]; - for (auto& primitive : mesh.mPrimitives) - { - if (!rigged) - { - gGL.loadMatrix((F32*)glm::value_ptr(node.mRenderMatrix)); - } - bool cull = true; - if (primitive.mMaterial != INVALID_INDEX) - { - Material& material = mMaterials[primitive.mMaterial]; - bool mat_opaque = material.mAlphaMode != Material::AlphaMode::BLEND; - - if (mat_opaque != opaque) - { - continue; - } - - material.bind(*this); - - cull = !material.mDoubleSided; - } - else - { - if (!opaque) - { - continue; - } - LLFetchedGLTFMaterial::sDefault.bind(); - } - - LLGLDisable cull_face(!cull ? GL_CULL_FACE : 0); - - primitive.mVertexBuffer->setBuffer(); - if (primitive.mVertexBuffer->getNumIndices() > 0) - { - primitive.mVertexBuffer->draw(primitive.mGLMode, primitive.mVertexBuffer->getNumIndices(), 0); - } - else - { - primitive.mVertexBuffer->drawArrays(primitive.mGLMode, 0, primitive.mVertexBuffer->getNumVerts()); - } - - } - } - } -} - -void Asset::renderOpaque() -{ - render(true); -} - -void Asset::renderTransparent() -{ - render(false); -} - void Asset::update() { F32 dt = gFrameTimeSeconds - mLastUpdateTime; @@ -461,6 +373,11 @@ void Asset::update() } updateTransforms(); + + for (auto& skin : mSkins) + { + skin.uploadMatrixPalette(*this); + } } } @@ -1063,90 +980,6 @@ bool Material::PbrMetallicRoughness::operator!=(const Material::PbrMetallicRough return !(*this == rhs); } -static void bindTexture(Asset& asset, S32 uniform, Material::TextureInfo& info, LLViewerTexture* fallback) -{ - if (info.mIndex != INVALID_INDEX) - { - LLViewerTexture* tex = asset.mImages[asset.mTextures[info.mIndex].mSource].mTexture; - if (tex) - { - tex->addTextureStats(2048.f * 2048.f); - LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, tex); - } - else - { - LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, fallback); - } - } - else - { - LLGLSLShader::sCurBoundShaderPtr->bindTexture(uniform, fallback); - } -} - -void Material::bind(Asset& asset) -{ - // bind for rendering (derived from LLFetchedGLTFMaterial::bind) - // glTF 2.0 Specification 3.9.4. Alpha Coverage - // mAlphaCutoff is only valid for LLGLTFMaterial::ALPHA_MODE_MASK - F32 min_alpha = -1.0; - - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - - if (!LLPipeline::sShadowRender || (mAlphaMode == Material::AlphaMode::BLEND)) - { - if (mAlphaMode == Material::AlphaMode::MASK) - { - // dividing the alpha cutoff by transparency here allows the shader to compare against - // the alpha value of the texture without needing the transparency value - if (mPbrMetallicRoughness.mBaseColorFactor.a > 0.f) - { - min_alpha = mAlphaCutoff / mPbrMetallicRoughness.mBaseColorFactor.a; - } - else - { - min_alpha = 1024.f; - } - } - shader->uniform1f(LLShaderMgr::MINIMUM_ALPHA, min_alpha); - } - - bindTexture(asset, LLShaderMgr::DIFFUSE_MAP, mPbrMetallicRoughness.mBaseColorTexture, LLViewerFetchedTexture::sWhiteImagep); - - F32 base_color_packed[8]; - //mTextureTransform[GLTF_TEXTURE_INFO_BASE_COLOR].getPacked(base_color_packed); - LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR].getPacked(base_color_packed); - shader->uniform4fv(LLShaderMgr::TEXTURE_BASE_COLOR_TRANSFORM, 2, (F32*)base_color_packed); - - if (!LLPipeline::sShadowRender) - { - bindTexture(asset, LLShaderMgr::BUMP_MAP, mNormalTexture, LLViewerFetchedTexture::sFlatNormalImagep); - bindTexture(asset, LLShaderMgr::SPECULAR_MAP, mPbrMetallicRoughness.mMetallicRoughnessTexture, LLViewerFetchedTexture::sWhiteImagep); - bindTexture(asset, LLShaderMgr::EMISSIVE_MAP, mEmissiveTexture, LLViewerFetchedTexture::sWhiteImagep); - - // NOTE: base color factor is baked into vertex stream - - shader->uniform1f(LLShaderMgr::ROUGHNESS_FACTOR, mPbrMetallicRoughness.mRoughnessFactor); - shader->uniform1f(LLShaderMgr::METALLIC_FACTOR, mPbrMetallicRoughness.mMetallicFactor); - shader->uniform3fv(LLShaderMgr::EMISSIVE_COLOR, 1, glm::value_ptr(mEmissiveFactor)); - - F32 normal_packed[8]; - //mTextureTransform[GLTF_TEXTURE_INFO_NORMAL].getPacked(normal_packed); - LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL].getPacked(normal_packed); - shader->uniform4fv(LLShaderMgr::TEXTURE_NORMAL_TRANSFORM, 2, (F32*)normal_packed); - - F32 metallic_roughness_packed[8]; - //mTextureTransform[GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].getPacked(metallic_roughness_packed); - LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].getPacked(metallic_roughness_packed); - shader->uniform4fv(LLShaderMgr::TEXTURE_METALLIC_ROUGHNESS_TRANSFORM, 2, (F32*)metallic_roughness_packed); - - F32 emissive_packed[8]; - //mTextureTransform[GLTF_TEXTURE_INFO_EMISSIVE].getPacked(emissive_packed); - LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE].getPacked(emissive_packed); - shader->uniform4fv(LLShaderMgr::TEXTURE_EMISSIVE_TRANSFORM, 2, (F32*)emissive_packed); - } -} - void Material::serialize(object& dst) const { write(mName, "name", dst); @@ -1264,52 +1097,4 @@ const Sampler& Sampler::operator=(const Value& src) return *this; } -void Skin::uploadMatrixPalette(Asset& asset, Node& node) -{ - // prepare matrix palette - - // modelview will be applied by the shader, so assume matrix palette is in asset space - std::vector t_mp; - - t_mp.resize(mJoints.size()); - - for (U32 i = 0; i < mJoints.size(); ++i) - { - Node& joint = asset.mNodes[mJoints[i]]; - t_mp[i] = joint.mRenderMatrix * mInverseBindMatricesData[i]; - } - - std::vector glmp; - - glmp.resize(mJoints.size() * 12); - - F32* mp = glmp.data(); - - for (U32 i = 0; i < mJoints.size(); ++i) - { - F32* m = glm::value_ptr(t_mp[i]); - - U32 idx = i * 12; - - mp[idx + 0] = m[0]; - mp[idx + 1] = m[1]; - mp[idx + 2] = m[2]; - mp[idx + 3] = m[12]; - - mp[idx + 4] = m[4]; - mp[idx + 5] = m[5]; - mp[idx + 6] = m[6]; - mp[idx + 7] = m[13]; - - mp[idx + 8] = m[8]; - mp[idx + 9] = m[9]; - mp[idx + 10] = m[10]; - mp[idx + 11] = m[14]; - } - - LLGLSLShader::sCurBoundShaderPtr->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX, - mJoints.size(), - GL_FALSE, - (GLfloat*)glmp.data()); -} -- cgit v1.2.3 From e279aae51a0f43cba0e284da4c0ea7c168316ca1 Mon Sep 17 00:00:00 2001 From: RunitaiLinden Date: Thu, 30 May 2024 13:42:27 -0500 Subject: #1597 Fix for some GLTF transforms not loading properly. Also incidental fix for unreachable code error. --- indra/newview/gltf/asset.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'indra/newview/gltf/asset.cpp') diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index 7870eb28b0..7d379c2528 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -300,8 +300,8 @@ void Node::serialize(object& dst) const { write(mName, "name", dst); write(mMatrix, "matrix", dst, glm::identity()); - write(mRotation, "rotation", dst); - write(mTranslation, "translation", dst); + write(mRotation, "rotation", dst, glm::identity()); + write(mTranslation, "translation", dst, glm::vec3(0.f, 0.f, 0.f)); write(mScale, "scale", dst, vec3(1.f,1.f,1.f)); write(mChildren, "children", dst); write(mMesh, "mesh", dst, INVALID_INDEX); @@ -312,7 +312,6 @@ const Node& Node::operator=(const Value& src) { copy(src, "name", mName); mMatrixValid = copy(src, "matrix", mMatrix); - copy(src, "rotation", mRotation); copy(src, "translation", mTranslation); copy(src, "scale", mScale); -- cgit v1.2.3 From 4522f33d2bad2cc0f67e10a0b0ad3cc7c1b43fbd Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 10 Jun 2024 16:57:31 -0500 Subject: #1677 Add GLTF extensions serialization and support for KHR_materials_unlit (#1686) --- indra/newview/gltf/asset.cpp | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'indra/newview/gltf/asset.cpp') 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 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) -- cgit v1.2.3 From 429c92ad75fd3b3f7b9dfc52ed034b25004a3b9c Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 11 Jun 2024 13:27:54 -0500 Subject: #1687 Add support for KHR_texture_transform (#1717) --- indra/newview/gltf/asset.cpp | 51 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 7 deletions(-) (limited to 'indra/newview/gltf/asset.cpp') diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index a4efb25860..4c1da3e645 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -45,7 +45,8 @@ namespace LL namespace GLTF { static std::unordered_set ExtensionsSupported = { - "KHR_materials_unlit" + "KHR_materials_unlit", + "KHR_texture_transform" }; Material::AlphaMode gltf_alpha_mode_to_enum(const std::string& alpha_mode) @@ -906,6 +907,7 @@ void Material::TextureInfo::serialize(object& dst) const { write(mIndex, "index", dst, INVALID_INDEX); write(mTexCoord, "texCoord", dst, 0); + write_extensions(dst, &mTextureTransform, "KHR_texture_transform"); } const Material::TextureInfo& Material::TextureInfo::operator=(const Value& src) @@ -914,6 +916,7 @@ const Material::TextureInfo& Material::TextureInfo::operator=(const Value& src) { copy(src, "index", mIndex); copy(src, "texCoord", mTexCoord); + copy_extensions(src, "KHR_texture_transform", &mTextureTransform); } return *this; @@ -931,17 +934,16 @@ bool Material::TextureInfo::operator!=(const Material::TextureInfo& rhs) const void Material::OcclusionTextureInfo::serialize(object& dst) const { - write(mIndex, "index", dst, INVALID_INDEX); - write(mTexCoord, "texCoord", dst, 0); + TextureInfo::serialize(dst); write(mStrength, "strength", dst, 1.f); } const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=(const Value& src) { + TextureInfo::operator=(src); + if (src.is_object()) { - copy(src, "index", mIndex); - copy(src, "texCoord", mTexCoord); copy(src, "strength", mStrength); } @@ -950,13 +952,13 @@ const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=( void Material::NormalTextureInfo::serialize(object& dst) const { - write(mIndex, "index", dst, INVALID_INDEX); - write(mTexCoord, "texCoord", dst, 0); + TextureInfo::serialize(dst); write(mScale, "scale", dst, 1.f); } const Material::NormalTextureInfo& Material::NormalTextureInfo::operator=(const Value& src) { + TextureInfo::operator=(src); if (src.is_object()) { copy(src, "index", mIndex); @@ -1015,6 +1017,41 @@ void Material::Unlit::serialize(object& dst) const // no members and object has already been created, nothing to do } +void TextureTransform::getPacked(F32* packed) const +{ + packed[0] = mScale.x; + packed[1] = mScale.y; + packed[2] = mRotation; + packed[3] = mOffset.x; + packed[4] = mOffset.y; + + packed[5] = packed[6] = packed[7] = 0.f; +} + + +const TextureTransform& TextureTransform::operator=(const Value& src) +{ + mPresent = true; + if (src.is_object()) + { + copy(src, "offset", mOffset); + copy(src, "rotation", mRotation); + copy(src, "scale", mScale); + copy(src, "texCoord", mTexCoord); + } + + return *this; +} + +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); +} + + void Material::serialize(object& dst) const { write(mName, "name", dst); -- cgit v1.2.3 From f40fbdf4ad27a547e30781cd44cd6847d68d3300 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Tue, 11 Jun 2024 17:10:13 -0500 Subject: #1718 Add GLTF support for multiple texcoords (#1720) * Fix for GLTF MeshPrimitiveModes test --- indra/newview/gltf/asset.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'indra/newview/gltf/asset.cpp') 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); } -- cgit v1.2.3 From 80ea30af1a8b38360f71c29cc45872c4399dab0d Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 21 Jun 2024 13:13:08 -0500 Subject: #1769 gltf optimization pass (#1816) #1814 and #1517 Fix mirror update rate and occlusion culling --- indra/newview/gltf/asset.cpp | 299 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 256 insertions(+), 43 deletions(-) (limited to 'indra/newview/gltf/asset.cpp') diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index 21be69aae2..a454e68a92 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -35,6 +35,7 @@ #include "buffer_util.h" #include #include "llimagejpeg.h" +#include "../llskinningutil.h" using namespace LL::GLTF; using namespace boost::json; @@ -86,7 +87,6 @@ namespace LL } } - void Scene::updateTransforms(Asset& asset) { mat4 identity = glm::identity(); @@ -98,26 +98,6 @@ void Scene::updateTransforms(Asset& asset) } } -void Scene::updateRenderTransforms(Asset& asset, const mat4& modelview) -{ - for (auto& nodeIndex : mNodes) - { - Node& node = asset.mNodes[nodeIndex]; - node.updateRenderTransforms(asset, modelview); - } -} - -void Node::updateRenderTransforms(Asset& asset, const mat4& modelview) -{ - mRenderMatrix = modelview * mMatrix; - - for (auto& childIndex : mChildren) - { - Node& child = asset.mNodes[childIndex]; - child.updateRenderTransforms(asset, mRenderMatrix); - } -} - void Node::updateTransforms(Asset& asset, const mat4& parentMatrix) { makeMatrixValid(); @@ -137,19 +117,119 @@ void Node::updateTransforms(Asset& asset, const mat4& parentMatrix) void Asset::updateTransforms() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF; for (auto& scene : mScenes) { scene.updateTransforms(*this); } + + uploadTransforms(); } -void Asset::updateRenderTransforms(const mat4& modelview) +void Asset::uploadTransforms() { - // use mAssetMatrix to update render transforms from node list - for (auto& node : mNodes) + LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF; + // prepare matrix palette + U32 max_nodes = LLSkinningUtil::getMaxGLTFJointCount(); + + size_t node_count = llmin(max_nodes, mNodes.size()); + + std::vector t_mp; + + t_mp.resize(node_count); + + for (U32 i = 0; i < node_count; ++i) { - node.mRenderMatrix = modelview * node.mAssetMatrix; + Node& node = mNodes[i]; + // build matrix palette in asset space + t_mp[i] = node.mAssetMatrix; } + + std::vector glmp; + + glmp.resize(node_count * 12); + + F32* mp = glmp.data(); + + for (U32 i = 0; i < node_count; ++i) + { + F32* m = glm::value_ptr(t_mp[i]); + + U32 idx = i * 12; + + mp[idx + 0] = m[0]; + mp[idx + 1] = m[1]; + mp[idx + 2] = m[2]; + mp[idx + 3] = m[12]; + + mp[idx + 4] = m[4]; + mp[idx + 5] = m[5]; + mp[idx + 6] = m[6]; + mp[idx + 7] = m[13]; + + mp[idx + 8] = m[8]; + mp[idx + 9] = m[9]; + mp[idx + 10] = m[10]; + mp[idx + 11] = m[14]; + } + + if (mNodesUBO == 0) + { + glGenBuffers(1, &mNodesUBO); + } + + glBindBuffer(GL_UNIFORM_BUFFER, mNodesUBO); + glBufferData(GL_UNIFORM_BUFFER, glmp.size() * sizeof(F32), glmp.data(), GL_STREAM_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); +} + +void Asset::uploadMaterials() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF; + // see pbrmetallicroughnessV.glsl for the layout of the material UBO + std::vector md; + + U32 material_size = sizeof(vec4) * 12; + U32 max_materials = gGLManager.mMaxUniformBlockSize / material_size; + + U32 mat_count = (U32)mMaterials.size(); + mat_count = llmin(mat_count, max_materials); + + md.resize(mat_count * 12); + + for (U32 i = 0; i < mat_count*12; i += 12) + { + Material& material = mMaterials[i/12]; + + // add texture transforms and UV indices + material.mPbrMetallicRoughness.mBaseColorTexture.mTextureTransform.getPacked(&md[i+0]); + md[i + 1].g = (F32)material.mPbrMetallicRoughness.mBaseColorTexture.getTexCoord(); + material.mNormalTexture.mTextureTransform.getPacked(&md[i + 2]); + md[i + 3].g = (F32)material.mNormalTexture.getTexCoord(); + material.mPbrMetallicRoughness.mMetallicRoughnessTexture.mTextureTransform.getPacked(&md[i+4]); + md[i + 5].g = (F32)material.mPbrMetallicRoughness.mMetallicRoughnessTexture.getTexCoord(); + material.mEmissiveTexture.mTextureTransform.getPacked(&md[i + 6]); + md[i + 7].g = (F32)material.mEmissiveTexture.getTexCoord(); + material.mOcclusionTexture.mTextureTransform.getPacked(&md[i + 8]); + md[i + 9].g = (F32)material.mOcclusionTexture.getTexCoord(); + + // add material properties + F32 min_alpha = material.mAlphaMode == Material::AlphaMode::MASK ? material.mAlphaCutoff : -1.0f; + md[i + 10] = vec4(material.mEmissiveFactor, 1.f); + md[i + 11] = vec4(0.f, + material.mPbrMetallicRoughness.mRoughnessFactor, + material.mPbrMetallicRoughness.mMetallicFactor, + min_alpha); + } + + if (mMaterialsUBO == 0) + { + glGenBuffers(1, &mMaterialsUBO); + } + + glBindBuffer(GL_UNIFORM_BUFFER, mMaterialsUBO); + glBufferData(GL_UNIFORM_BUFFER, md.size() * sizeof(vec4), md.data(), GL_STREAM_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); } S32 Asset::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, @@ -363,6 +443,7 @@ const Image& Image::operator=(const Value& src) void Asset::update() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF; F32 dt = gFrameTimeSeconds - mLastUpdateTime; if (dt > 0.f) @@ -383,11 +464,27 @@ void Asset::update() { skin.uploadMatrixPalette(*this); } + + uploadMaterials(); + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_GLTF("gltf - addTextureStats"); + + for (auto& image : mImages) + { + if (image.mTexture.notNull()) + { // HACK - force texture to be loaded full rez + // TODO: calculate actual vsize + image.mTexture->addTextureStats(2048.f * 2048.f); + } + } + } } } bool Asset::prep() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF; // check required extensions and fail if not supported bool unsupported = false; for (auto& extension : mExtensionsRequired) @@ -445,6 +542,127 @@ bool Asset::prep() } } + // prepare vertex buffers + + // material count is number of materials + 1 for default material + U32 mat_count = (U32) mMaterials.size() + 1; + + if (LLGLSLShader::sCurBoundShaderPtr == nullptr) + { // make sure a shader is bound to satisfy mVertexBuffer->setBuffer + gDebugProgram.bind(); + } + + for (S32 double_sided = 0; double_sided < 2; ++double_sided) + { + RenderData& rd = mRenderData[double_sided]; + for (U32 i = 0; i < LLGLSLShader::NUM_GLTF_VARIANTS; ++i) + { + rd.mBatches[i].resize(mat_count); + } + + // for each material + for (S32 mat_id = -1; mat_id < (S32)mMaterials.size(); ++mat_id) + { + // for each shader variant + U32 vertex_count[LLGLSLShader::NUM_GLTF_VARIANTS] = { 0 }; + U32 index_count[LLGLSLShader::NUM_GLTF_VARIANTS] = { 0 }; + + S32 ds_mat = mat_id == -1 ? 0 : mMaterials[mat_id].mDoubleSided; + if (ds_mat != double_sided) + { + continue; + } + + for (U32 variant = 0; variant < LLGLSLShader::NUM_GLTF_VARIANTS; ++variant) + { + U32 attribute_mask = 0; + // for each mesh + for (auto& mesh : mMeshes) + { + // for each primitive + for (auto& primitive : mesh.mPrimitives) + { + if (primitive.mMaterial == mat_id && primitive.mShaderVariant == variant) + { + // accumulate vertex and index counts + primitive.mVertexOffset = vertex_count[variant]; + primitive.mIndexOffset = index_count[variant]; + + vertex_count[variant] += primitive.getVertexCount(); + index_count[variant] += primitive.getIndexCount(); + + // all primitives of a given variant and material should all have the same attribute mask + llassert(attribute_mask == 0 || primitive.mAttributeMask == attribute_mask); + attribute_mask |= primitive.mAttributeMask; + } + } + } + + // allocate vertex buffer and pack it + if (vertex_count[variant] > 0) + { + U32 mat_idx = mat_id + 1; + LLVertexBuffer* vb = new LLVertexBuffer(attribute_mask); + + rd.mBatches[variant][mat_idx].mVertexBuffer = vb; + vb->allocateBuffer(vertex_count[variant], + index_count[variant] * 2); // hack double index count... TODO: find a better way to indicate 32-bit indices will be used + vb->setBuffer(); + + for (auto& mesh : mMeshes) + { + for (auto& primitive : mesh.mPrimitives) + { + if (primitive.mMaterial == mat_id && primitive.mShaderVariant == variant) + { + primitive.upload(vb); + } + } + } + + vb->unmapBuffer(); + + vb->unbind(); + } + } + } + } + + // sanity check that all primitives have a vertex buffer + for (auto& mesh : mMeshes) + { + for (auto& primitive : mesh.mPrimitives) + { + llassert(primitive.mVertexBuffer.notNull()); + } + } + + // build render batches + for (S32 node_id = 0; node_id < mNodes.size(); ++node_id) + { + Node& node = mNodes[node_id]; + + if (node.mMesh != INVALID_INDEX) + { + auto& mesh = mMeshes[node.mMesh]; + + S32 mat_idx = mesh.mPrimitives[0].mMaterial + 1; + + S32 double_sided = mat_idx == 0 ? 0 : mMaterials[mat_idx - 1].mDoubleSided; + + for (S32 j = 0; j < mesh.mPrimitives.size(); ++j) + { + auto& primitive = mesh.mPrimitives[j]; + + S32 variant = primitive.mShaderVariant; + + RenderData& rd = mRenderData[double_sided]; + RenderBatch& rb = rd.mBatches[variant][mat_idx]; + + rb.mPrimitives.push_back({ j, node_id }); + } + } + } return true; } @@ -455,6 +673,7 @@ Asset::Asset(const Value& src) bool Asset::load(std::string_view filename) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_GLTF; mFilename = filename; std::string ext = gDirUtilp->getExtension(mFilename); @@ -903,14 +1122,14 @@ bool Image::save(Asset& asset, const std::string& folder) return true; } -void Material::TextureInfo::serialize(object& dst) const +void TextureInfo::serialize(object& dst) const { write(mIndex, "index", dst, INVALID_INDEX); write(mTexCoord, "texCoord", dst, 0); write_extensions(dst, &mTextureTransform, "KHR_texture_transform"); } -S32 Material::TextureInfo::getTexCoord() const +S32 TextureInfo::getTexCoord() const { if (mTextureTransform.mPresent && mTextureTransform.mTexCoord != INVALID_INDEX) { @@ -928,7 +1147,7 @@ bool Material::isMultiUV() const mEmissiveTexture.getTexCoord() != 0; } -const Material::TextureInfo& Material::TextureInfo::operator=(const Value& src) +const TextureInfo& TextureInfo::operator=(const Value& src) { if (src.is_object()) { @@ -940,23 +1159,23 @@ const Material::TextureInfo& Material::TextureInfo::operator=(const Value& src) return *this; } -bool Material::TextureInfo::operator==(const Material::TextureInfo& rhs) const +bool TextureInfo::operator==(const TextureInfo& rhs) const { return mIndex == rhs.mIndex && mTexCoord == rhs.mTexCoord; } -bool Material::TextureInfo::operator!=(const Material::TextureInfo& rhs) const +bool TextureInfo::operator!=(const TextureInfo& rhs) const { return !(*this == rhs); } -void Material::OcclusionTextureInfo::serialize(object& dst) const +void OcclusionTextureInfo::serialize(object& dst) const { TextureInfo::serialize(dst); write(mStrength, "strength", dst, 1.f); } -const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=(const Value& src) +const OcclusionTextureInfo& OcclusionTextureInfo::operator=(const Value& src) { TextureInfo::operator=(src); @@ -968,13 +1187,13 @@ const Material::OcclusionTextureInfo& Material::OcclusionTextureInfo::operator=( return *this; } -void Material::NormalTextureInfo::serialize(object& dst) const +void NormalTextureInfo::serialize(object& dst) const { TextureInfo::serialize(dst); write(mScale, "scale", dst, 1.f); } -const Material::NormalTextureInfo& Material::NormalTextureInfo::operator=(const Value& src) +const NormalTextureInfo& NormalTextureInfo::operator=(const Value& src) { TextureInfo::operator=(src); if (src.is_object()) @@ -1035,18 +1254,12 @@ void Material::Unlit::serialize(object& dst) const // no members and object has already been created, nothing to do } -void TextureTransform::getPacked(F32* packed) const +void TextureTransform::getPacked(vec4* packed) const { - packed[0] = mScale.x; - packed[1] = mScale.y; - packed[2] = mRotation; - packed[3] = mOffset.x; - packed[4] = mOffset.y; - - packed[5] = packed[6] = packed[7] = 0.f; + packed[0] = vec4(mScale.x, mScale.y, mRotation, mOffset.x); + packed[1] = vec4(mOffset.y, 0.f, 0.f, 0.f); } - const TextureTransform& TextureTransform::operator=(const Value& src) { mPresent = true; -- cgit v1.2.3 From 08b933a0c67463f06f124420f16c8a3f7dc83f1f Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 3 Jul 2024 17:42:24 -0500 Subject: #1870 Tune up for better experience on integrated intel with low memory (#1872) * More deterministic vsize calculation. Add control for choosing downscale method. * Quick hack to make GLTF preview work again --- indra/newview/gltf/asset.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'indra/newview/gltf/asset.cpp') diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index a454e68a92..e07befef3b 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -476,6 +476,7 @@ void Asset::update() { // HACK - force texture to be loaded full rez // TODO: calculate actual vsize image.mTexture->addTextureStats(2048.f * 2048.f); + image.mTexture->setBoostLevel(LLViewerTexture::BOOST_HIGH); } } } -- cgit v1.2.3 From 9fdca96f8bd2211a99fe88e57b70cbecefa20b6d Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 8 Jul 2024 20:27:14 +0200 Subject: Re-enable compiler warnings C4244 and C4396 except for lltracerecording.h and llunittype.h for now --- indra/newview/gltf/asset.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'indra/newview/gltf/asset.cpp') diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index e07befef3b..5ba5951064 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -105,7 +105,7 @@ void Node::updateTransforms(Asset& asset, const mat4& parentMatrix) mAssetMatrixInv = glm::inverse(mAssetMatrix); - S32 my_index = this - &asset.mNodes[0]; + S32 my_index = (S32)(this - &asset.mNodes[0]); for (auto& childIndex : mChildren) { @@ -271,11 +271,11 @@ S32 Asset::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, local_end = p; // pointer math to get the node index - node_hit = &node - &mNodes[0]; + node_hit = (S32)(&node - &mNodes[0]); llassert(&mNodes[node_hit] == &node); //pointer math to get the primitive index - primitive_hit = &primitive - &mesh.mPrimitives[0]; + primitive_hit = (S32)(&primitive - &mesh.mPrimitives[0]); llassert(&mesh.mPrimitives[primitive_hit] == &primitive); } } @@ -1028,7 +1028,7 @@ bool Image::save(Asset& asset, const std::string& folder) const std::string& delim = gDirUtilp->getDirDelimiter(); if (name.empty()) { - S32 idx = this - asset.mImages.data(); + S32 idx = (S32)(this - asset.mImages.data()); name = llformat("image_%d", idx); } -- cgit v1.2.3 From 98941831e4afab1cd5ccb5bab995a671df320f72 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 11 Jul 2024 11:36:36 -0500 Subject: Fix for GLTF scenes not uploading (#1994) --- indra/newview/gltf/asset.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'indra/newview/gltf/asset.cpp') diff --git a/indra/newview/gltf/asset.cpp b/indra/newview/gltf/asset.cpp index 5ba5951064..c210b9c61d 100644 --- a/indra/newview/gltf/asset.cpp +++ b/indra/newview/gltf/asset.cpp @@ -991,6 +991,12 @@ bool Image::prep(Asset& asset) return false; } + if (!asset.mFilename.empty()) + { // local preview, boost image so it doesn't discard and force to save raw image in case we save out or upload + mTexture->setBoostLevel(LLViewerTexture::BOOST_PREVIEW); + mTexture->forceToSaveRawImage(0, F32_MAX); + } + return true; } -- cgit v1.2.3