diff options
Diffstat (limited to 'indra')
-rw-r--r-- | indra/llprimitive/CMakeLists.txt | 2 | ||||
-rw-r--r-- | indra/llprimitive/llgltfmaterial.cpp | 151 | ||||
-rw-r--r-- | indra/llprimitive/llgltfmaterial.h | 53 | ||||
-rw-r--r-- | indra/llprimitive/tests/llgltfmaterial_test.cpp | 256 | ||||
-rw-r--r-- | indra/newview/llgltfmateriallist.cpp | 4 | ||||
-rw-r--r-- | indra/newview/llmaterialeditor.cpp | 209 | ||||
-rw-r--r-- | indra/newview/llmaterialeditor.h | 9 | ||||
-rw-r--r-- | indra/newview/llpanelface.cpp | 29 | ||||
-rw-r--r-- | indra/newview/llselectmgr.cpp | 68 | ||||
-rw-r--r-- | indra/newview/lltinygltfhelper.cpp | 16 | ||||
-rw-r--r-- | indra/newview/llviewermenufile.cpp | 8 | ||||
-rw-r--r-- | indra/newview/llviewerobject.cpp | 43 |
12 files changed, 464 insertions, 384 deletions
diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt index 328b22f900..dd25c19713 100644 --- a/indra/llprimitive/CMakeLists.txt +++ b/indra/llprimitive/CMakeLists.txt @@ -99,6 +99,8 @@ if (LL_TESTS) SET(llprimitive_TEST_SOURCE_FILES llmediaentry.cpp llprimitive.cpp + llgltfmaterial.cpp ) + LL_ADD_PROJECT_UNIT_TESTS(llprimitive "${llprimitive_TEST_SOURCE_FILES}") endif (LL_TESTS) diff --git a/indra/llprimitive/llgltfmaterial.cpp b/indra/llprimitive/llgltfmaterial.cpp index a8dad89292..291e2c2bf5 100644 --- a/indra/llprimitive/llgltfmaterial.cpp +++ b/indra/llprimitive/llgltfmaterial.cpp @@ -31,6 +31,10 @@ // NOTE -- this should be the one and only place tiny_gltf.h is included #include "tinygltf/tiny_gltf.h" +const char* LLGLTFMaterial::ASSET_VERSION = "1.1"; +const char* LLGLTFMaterial::ASSET_TYPE = "GLTF 2.0"; +const std::array<std::string, 2> LLGLTFMaterial::ACCEPTED_ASSET_VERSIONS = { "1.0", "1.1" }; + const char* GLTF_FILE_EXTENSION_TRANSFORM = "KHR_texture_transform"; const char* GLTF_FILE_EXTENSION_TRANSFORM_SCALE = "scale"; const char* GLTF_FILE_EXTENSION_TRANSFORM_OFFSET = "offset"; @@ -73,16 +77,14 @@ LLGLTFMaterial::LLGLTFMaterial(const LLGLTFMaterial& rhs) LLGLTFMaterial& LLGLTFMaterial::operator=(const LLGLTFMaterial& rhs) { - LL_PROFILE_ZONE_SCOPED; - //have to do a manual operator= because of LLRefCount - mBaseColorId = rhs.mBaseColorId; - mNormalId = rhs.mNormalId; - mMetallicRoughnessId = rhs.mMetallicRoughnessId; - mEmissiveId = rhs.mEmissiveId; + //have to do a manual operator= because of LLRefCount + mTextureId = rhs.mTextureId; + + mTextureTransform = rhs.mTextureTransform; mBaseColor = rhs.mBaseColor; mEmissiveColor = rhs.mEmissiveColor; - + mMetallicFactor = rhs.mMetallicFactor; mRoughnessFactor = rhs.mRoughnessFactor; mAlphaCutoff = rhs.mAlphaCutoff; @@ -90,8 +92,6 @@ LLGLTFMaterial& LLGLTFMaterial::operator=(const LLGLTFMaterial& rhs) mDoubleSided = rhs.mDoubleSided; mAlphaMode = rhs.mAlphaMode; - mTextureTransform = rhs.mTextureTransform; - mOverrideDoubleSided = rhs.mOverrideDoubleSided; mOverrideAlphaMode = rhs.mOverrideAlphaMode; @@ -100,10 +100,9 @@ LLGLTFMaterial& LLGLTFMaterial::operator=(const LLGLTFMaterial& rhs) bool LLGLTFMaterial::operator==(const LLGLTFMaterial& rhs) const { - return mBaseColorId == rhs.mBaseColorId && - mNormalId == rhs.mNormalId && - mMetallicRoughnessId == rhs.mMetallicRoughnessId && - mEmissiveId == rhs.mEmissiveId && + return mTextureId == rhs.mTextureId && + + mTextureTransform == rhs.mTextureTransform && mBaseColor == rhs.mBaseColor && mEmissiveColor == rhs.mEmissiveColor && @@ -115,8 +114,6 @@ bool LLGLTFMaterial::operator==(const LLGLTFMaterial& rhs) const mDoubleSided == rhs.mDoubleSided && mAlphaMode == rhs.mAlphaMode && - mTextureTransform == rhs.mTextureTransform && - mOverrideDoubleSided == rhs.mOverrideDoubleSided && mOverrideAlphaMode == rhs.mOverrideAlphaMode; } @@ -148,6 +145,8 @@ std::string LLGLTFMaterial::asJSON(bool prettyprint) const writeToModel(model_out, 0); + // To ensure consistency in asset upload, this should be the only reference + // to WriteGltfSceneToStream in the viewer. gltf.WriteGltfSceneToStream(&model_out, str, prettyprint, false); return str.str(); @@ -164,13 +163,13 @@ void LLGLTFMaterial::setFromModel(const tinygltf::Model& model, S32 mat_index) const tinygltf::Material& material_in = model.materials[mat_index]; // Apply base color texture - setFromTexture(model, material_in.pbrMetallicRoughness.baseColorTexture, GLTF_TEXTURE_INFO_BASE_COLOR, mBaseColorId); + setFromTexture(model, material_in.pbrMetallicRoughness.baseColorTexture, GLTF_TEXTURE_INFO_BASE_COLOR); // Apply normal map - setFromTexture(model, material_in.normalTexture, GLTF_TEXTURE_INFO_NORMAL, mNormalId); + setFromTexture(model, material_in.normalTexture, GLTF_TEXTURE_INFO_NORMAL); // Apply metallic-roughness texture - setFromTexture(model, material_in.pbrMetallicRoughness.metallicRoughnessTexture, GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS, mMetallicRoughnessId); + setFromTexture(model, material_in.pbrMetallicRoughness.metallicRoughnessTexture, GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS); // Apply emissive texture - setFromTexture(model, material_in.emissiveTexture, GLTF_TEXTURE_INFO_EMISSIVE, mEmissiveId); + setFromTexture(model, material_in.emissiveTexture, GLTF_TEXTURE_INFO_EMISSIVE); setAlphaMode(material_in.alphaMode); mAlphaCutoff = llclamp((F32)material_in.alphaCutoff, 0.f, 1.f); @@ -264,11 +263,11 @@ std::string gltf_get_texture_image(const tinygltf::Model& model, const T& textur // *NOTE: Use template here as workaround for the different similar texture info classes template<typename T> -void LLGLTFMaterial::setFromTexture(const tinygltf::Model& model, const T& texture_info, TextureInfo texture_info_id, LLUUID& texture_id_out) +void LLGLTFMaterial::setFromTexture(const tinygltf::Model& model, const T& texture_info, TextureInfo texture_info_id) { LL_PROFILE_ZONE_SCOPED; const std::string uri = gltf_get_texture_image(model, texture_info); - texture_id_out.set(uri); + mTextureId[texture_info_id].set(uri); const tinygltf::Value::Object& extensions_object = texture_info.extensions; const auto transform_it = extensions_object.find(GLTF_FILE_EXTENSION_TRANSFORM); @@ -297,21 +296,24 @@ void LLGLTFMaterial::writeToModel(tinygltf::Model& model, S32 mat_index) const tinygltf::Material& material_out = model.materials[mat_index]; // set base color texture - writeToTexture(model, material_out.pbrMetallicRoughness.baseColorTexture, GLTF_TEXTURE_INFO_BASE_COLOR, mBaseColorId); + writeToTexture(model, material_out.pbrMetallicRoughness.baseColorTexture, GLTF_TEXTURE_INFO_BASE_COLOR); // set normal texture - writeToTexture(model, material_out.normalTexture, GLTF_TEXTURE_INFO_NORMAL, mNormalId); + writeToTexture(model, material_out.normalTexture, GLTF_TEXTURE_INFO_NORMAL); // set metallic-roughness texture - writeToTexture(model, material_out.pbrMetallicRoughness.metallicRoughnessTexture, GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS, mMetallicRoughnessId); + writeToTexture(model, material_out.pbrMetallicRoughness.metallicRoughnessTexture, GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS); // set emissive texture - writeToTexture(model, material_out.emissiveTexture, GLTF_TEXTURE_INFO_EMISSIVE, mEmissiveId); + writeToTexture(model, material_out.emissiveTexture, GLTF_TEXTURE_INFO_EMISSIVE); + // set occlusion texture + // *NOTE: This is required for ORM materials for GLTF compliance. + // See: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#_material_occlusiontexture + writeToTexture(model, material_out.occlusionTexture, GLTF_TEXTURE_INFO_OCCLUSION); + material_out.alphaMode = getAlphaMode(); material_out.alphaCutoff = mAlphaCutoff; - + mBaseColor.write(material_out.pbrMetallicRoughness.baseColorFactor); - material_out.emissiveFactor.resize(3); // 0 size by default - if (mEmissiveColor != LLGLTFMaterial::getDefaultEmissiveColor()) { material_out.emissiveFactor.resize(3); @@ -323,7 +325,6 @@ void LLGLTFMaterial::writeToModel(tinygltf::Model& model, S32 mat_index) const material_out.doubleSided = mDoubleSided; - // generate "extras" string tinygltf::Value::Object extras; bool write_extras = false; @@ -364,28 +365,43 @@ void gltf_allocate_texture_image(tinygltf::Model& model, T& texture_info, const } template<typename T> -void LLGLTFMaterial::writeToTexture(tinygltf::Model& model, T& texture_info, TextureInfo texture_info_id, const LLUUID& texture_id) const +void LLGLTFMaterial::writeToTexture(tinygltf::Model& model, T& texture_info, TextureInfo texture_info_id, bool force_write) const { LL_PROFILE_ZONE_SCOPED; + const LLUUID& texture_id = mTextureId[texture_info_id]; const TextureTransform& transform = mTextureTransform[texture_info_id]; - if (texture_id.isNull() && transform == sDefault.mTextureTransform[0]) + const bool is_blank_transform = transform == sDefault.mTextureTransform[0]; + // Check if this material matches all the fallback values, and if so, then + // skip including it to reduce material size + if (!force_write && texture_id.isNull() && is_blank_transform) { return; } + // tinygltf will discard this texture info if there is no valid texture, + // causing potential loss of information for overrides, so ensure one is + // defined. -Cosmic,2023-01-30 gltf_allocate_texture_image(model, texture_info, texture_id.asString()); - tinygltf::Value::Object transform_map; - transform_map[GLTF_FILE_EXTENSION_TRANSFORM_OFFSET] = tinygltf::Value(tinygltf::Value::Array({ - tinygltf::Value(transform.mOffset.mV[VX]), - tinygltf::Value(transform.mOffset.mV[VY]) - })); - transform_map[GLTF_FILE_EXTENSION_TRANSFORM_SCALE] = tinygltf::Value(tinygltf::Value::Array({ - tinygltf::Value(transform.mScale.mV[VX]), - tinygltf::Value(transform.mScale.mV[VY]) - })); - transform_map[GLTF_FILE_EXTENSION_TRANSFORM_ROTATION] = tinygltf::Value(transform.mRotation); - texture_info.extensions[GLTF_FILE_EXTENSION_TRANSFORM] = tinygltf::Value(transform_map); + if (!is_blank_transform) + { + tinygltf::Value::Object transform_map; + transform_map[GLTF_FILE_EXTENSION_TRANSFORM_OFFSET] = tinygltf::Value(tinygltf::Value::Array({ + tinygltf::Value(transform.mOffset.mV[VX]), + tinygltf::Value(transform.mOffset.mV[VY]) + })); + transform_map[GLTF_FILE_EXTENSION_TRANSFORM_SCALE] = tinygltf::Value(tinygltf::Value::Array({ + tinygltf::Value(transform.mScale.mV[VX]), + tinygltf::Value(transform.mScale.mV[VY]) + })); + transform_map[GLTF_FILE_EXTENSION_TRANSFORM_ROTATION] = tinygltf::Value(transform.mRotation); + texture_info.extensions[GLTF_FILE_EXTENSION_TRANSFORM] = tinygltf::Value(transform_map); + } +} + +void LLGLTFMaterial::sanitizeAssetMaterial() +{ + mTextureTransform = sDefault.mTextureTransform; } bool LLGLTFMaterial::setBaseMaterial() @@ -419,40 +435,33 @@ void LLGLTFMaterial::hackOverrideUUID(LLUUID& id) } } -void LLGLTFMaterial::setBaseColorId(const LLUUID& id, bool for_override) +void LLGLTFMaterial::setTextureId(TextureInfo texture_info, const LLUUID& id, bool for_override) { - mBaseColorId = id; + mTextureId[texture_info] = id; if (for_override) { - hackOverrideUUID(mBaseColorId); + hackOverrideUUID(mTextureId[texture_info]); } } +void LLGLTFMaterial::setBaseColorId(const LLUUID& id, bool for_override) +{ + setTextureId(GLTF_TEXTURE_INFO_BASE_COLOR, id, for_override); +} + void LLGLTFMaterial::setNormalId(const LLUUID& id, bool for_override) { - mNormalId = id; - if (for_override) - { - hackOverrideUUID(mNormalId); - } + setTextureId(GLTF_TEXTURE_INFO_NORMAL, id, for_override); } -void LLGLTFMaterial::setMetallicRoughnessId(const LLUUID& id, bool for_override) +void LLGLTFMaterial::setOcclusionRoughnessMetallicId(const LLUUID& id, bool for_override) { - mMetallicRoughnessId = id; - if (for_override) - { - hackOverrideUUID(mMetallicRoughnessId); - } + setTextureId(GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS, id, for_override); } void LLGLTFMaterial::setEmissiveId(const LLUUID& id, bool for_override) { - mEmissiveId = id; - if (for_override) - { - hackOverrideUUID(mEmissiveId); - } + setTextureId(GLTF_TEXTURE_INFO_EMISSIVE, id, for_override); } void LLGLTFMaterial::setBaseColorFactor(const LLColor4& baseColor, bool for_override) @@ -533,10 +542,7 @@ const char* LLGLTFMaterial::getAlphaMode() const void LLGLTFMaterial::setAlphaMode(S32 mode, bool for_override) { mAlphaMode = (AlphaMode) llclamp(mode, (S32) ALPHA_MODE_OPAQUE, (S32) ALPHA_MODE_MASK); - if (for_override) - { - mOverrideAlphaMode = true; - } + mOverrideAlphaMode = for_override && mAlphaMode == getDefaultAlphaMode(); } void LLGLTFMaterial::setDoubleSided(bool double_sided, bool for_override) @@ -544,10 +550,7 @@ void LLGLTFMaterial::setDoubleSided(bool double_sided, bool for_override) // sure, no clamping will ever be needed for a bool, but include the // setter for consistency with the clamping API mDoubleSided = double_sided; - if (for_override) - { - mOverrideDoubleSided = true; - } + mOverrideDoubleSided = for_override && mDoubleSided == getDefaultDoubleSided(); } void LLGLTFMaterial::setTextureOffset(TextureInfo texture_info, const LLVector2& offset) @@ -640,10 +643,12 @@ void LLGLTFMaterial::applyOverride(const LLGLTFMaterial& override_mat) { LL_PROFILE_ZONE_SCOPED; - applyOverrideUUID(mBaseColorId, override_mat.mBaseColorId); - applyOverrideUUID(mNormalId, override_mat.mNormalId); - applyOverrideUUID(mMetallicRoughnessId, override_mat.mMetallicRoughnessId); - applyOverrideUUID(mEmissiveId, override_mat.mEmissiveId); + for (int i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) + { + LLUUID& texture_id = mTextureId[i]; + const LLUUID& override_texture_id = override_mat.mTextureId[i]; + applyOverrideUUID(texture_id, override_texture_id); + } if (override_mat.mBaseColor != getDefaultBaseColor()) { diff --git a/indra/llprimitive/llgltfmaterial.h b/indra/llprimitive/llgltfmaterial.h index 2bd2d34b53..a3e0c0d9ca 100644 --- a/indra/llprimitive/llgltfmaterial.h +++ b/indra/llprimitive/llgltfmaterial.h @@ -49,6 +49,11 @@ public: // default material for reference static const LLGLTFMaterial sDefault; + static const char* ASSET_VERSION; + static const char* ASSET_TYPE; + static const std::array<std::string, 2> ACCEPTED_ASSET_VERSIONS; + static bool isAcceptedVersion(const std::string& version) { return std::find(ACCEPTED_ASSET_VERSIONS.cbegin(), ACCEPTED_ASSET_VERSIONS.cend(), version) != ACCEPTED_ASSET_VERSIONS.cend(); } + struct TextureTransform { LLVector2 mOffset = { 0.f, 0.f }; @@ -74,10 +79,25 @@ public: bool operator==(const LLGLTFMaterial& rhs) const; bool operator!=(const LLGLTFMaterial& rhs) const { return !(*this == rhs); } - LLUUID mBaseColorId; - LLUUID mNormalId; - LLUUID mMetallicRoughnessId; - LLUUID mEmissiveId; + enum TextureInfo : U32 + { + GLTF_TEXTURE_INFO_BASE_COLOR, + GLTF_TEXTURE_INFO_NORMAL, + GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS, + // *NOTE: GLTF_TEXTURE_INFO_OCCLUSION is currently ignored, in favor of + // the values specified with GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS. + // Currently, only ORM materials are supported (materials which define + // occlusion, roughness, and metallic in the same texture). + // -Cosmic,2023-01-26 + GLTF_TEXTURE_INFO_OCCLUSION = GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS, + GLTF_TEXTURE_INFO_EMISSIVE, + + GLTF_TEXTURE_INFO_COUNT + }; + + std::array<LLUUID, GLTF_TEXTURE_INFO_COUNT> mTextureId; + + std::array<TextureTransform, GLTF_TEXTURE_INFO_COUNT> mTextureTransform; // NOTE : initialize values to defaults according to the GLTF spec LLColor4 mBaseColor = LLColor4(1, 1, 1, 1); @@ -104,24 +124,14 @@ public: return hash; } - enum TextureInfo : U32 - { - GLTF_TEXTURE_INFO_BASE_COLOR, - GLTF_TEXTURE_INFO_NORMAL, - GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS, - GLTF_TEXTURE_INFO_EMISSIVE, - - GLTF_TEXTURE_INFO_COUNT - }; - - std::array<TextureTransform, GLTF_TEXTURE_INFO_COUNT> mTextureTransform; - //setters for various members (will clamp to acceptable ranges) // for_override - set to true if this value is being set as part of an override (important for handling override to default value) + void setTextureId(TextureInfo texture_info, const LLUUID& id, bool for_override = false); + void setBaseColorId(const LLUUID& id, bool for_override = false); void setNormalId(const LLUUID& id, bool for_override = false); - void setMetallicRoughnessId(const LLUUID& id, bool for_override = false); + void setOcclusionRoughnessMetallicId(const LLUUID& id, bool for_override = false); void setEmissiveId(const LLUUID& id, bool for_override = false); void setBaseColorFactor(const LLColor4& baseColor, bool for_override = false); @@ -180,6 +190,10 @@ public: void applyOverride(const LLGLTFMaterial& override_mat); + // For base materials only (i.e. assets). Clears transforms to + // default since they're not supported in assets yet. + void sanitizeAssetMaterial(); + // For material overrides only. Clears most properties to // default/fallthrough, but preserves the transforms. bool setBaseMaterial(); @@ -187,12 +201,11 @@ public: bool isClearedForBaseMaterial(); private: - template<typename T> - void setFromTexture(const tinygltf::Model& model, const T& texture_info, TextureInfo texture_info_id, LLUUID& texture_id_out); + void setFromTexture(const tinygltf::Model& model, const T& texture_info, TextureInfo texture_info_id); template<typename T> - void writeToTexture(tinygltf::Model& model, T& texture_info, TextureInfo texture_info_id, const LLUUID& texture_id) const; + void writeToTexture(tinygltf::Model& model, T& texture_info, TextureInfo texture_info_id, bool force_write = false) const; void setBaseMaterial(const LLGLTFMaterial& old_override_mat); }; diff --git a/indra/llprimitive/tests/llgltfmaterial_test.cpp b/indra/llprimitive/tests/llgltfmaterial_test.cpp new file mode 100644 index 0000000000..859cf99e3a --- /dev/null +++ b/indra/llprimitive/tests/llgltfmaterial_test.cpp @@ -0,0 +1,256 @@ +/** + * @file llgltfmaterial_test.cpp + * + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2023, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "lltut.h" + +#include "../llgltfmaterial.h" +#include "lluuid.cpp" + +// Import & define single-header gltf import/export lib +#define TINYGLTF_IMPLEMENTATION +#define TINYGLTF_USE_CPP14 // default is C++ 11 + +// tinygltf by default loads image files using STB +#define STB_IMAGE_IMPLEMENTATION +// to use our own image loading: +// 1. replace this definition with TINYGLTF_NO_STB_IMAGE +// 2. provide image loader callback with TinyGLTF::SetImageLoader(LoadimageDataFunction LoadImageData, void *user_data) + +// tinygltf saves image files using STB +#define STB_IMAGE_WRITE_IMPLEMENTATION +// similarly, can override with TINYGLTF_NO_STB_IMAGE_WRITE and TinyGLTF::SetImageWriter(fxn, data) + +// Disable reading external images to prevent warnings and speed up the tests. +// We don't need this for the tests, but still need the filesystem +// implementation to be defined in order for llprimitive to link correctly. +#define TINYGLTF_NO_EXTERNAL_IMAGE 1 + +#include "tinygltf/tiny_gltf.h" + +namespace tut +{ + struct llgltfmaterial + { + }; + typedef test_group<llgltfmaterial> llgltfmaterial_t; + typedef llgltfmaterial_t::object llgltfmaterial_object_t; + tut::llgltfmaterial_t tut_llgltfmaterial("llgltfmaterial"); + + // A positive 32-bit float with a long string representation + constexpr F32 test_fraction = 1.09045365e-32; + // A larger positive 32-bit float for values that get zeroed if below a threshold + constexpr F32 test_fraction_big = 0.109045; + + void apply_test_material_texture_ids(LLGLTFMaterial& material) + { + material.setBaseColorId(LLUUID::generateNewID()); + material.setNormalId(LLUUID::generateNewID()); + material.setOcclusionRoughnessMetallicId(LLUUID::generateNewID()); + material.setEmissiveId(LLUUID::generateNewID()); + } + + void apply_test_material_texture_transforms(LLGLTFMaterial& material) + { + LLGLTFMaterial::TextureTransform test_transform; + test_transform.mOffset.mV[VX] = test_fraction; + test_transform.mOffset.mV[VY] = test_fraction; + test_transform.mScale.mV[VX] = test_fraction; + test_transform.mScale.mV[VY] = test_fraction; + test_transform.mRotation = test_fraction; + for (LLGLTFMaterial::TextureInfo i = LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; i = LLGLTFMaterial::TextureInfo((U32)i + 1)) + { + material.setTextureOffset(i, test_transform.mOffset); + material.setTextureScale(i, test_transform.mScale); + material.setTextureRotation(i, test_transform.mRotation); + } + } + + void apply_test_material_factors(LLGLTFMaterial& material) + { + material.setBaseColorFactor(LLColor4(test_fraction_big, test_fraction_big, test_fraction_big, test_fraction_big)); + material.setEmissiveColorFactor(LLColor3(test_fraction_big, test_fraction_big, test_fraction_big)); + material.setMetallicFactor(test_fraction); + material.setRoughnessFactor(test_fraction); + } + + LLGLTFMaterial create_test_material() + { + LLGLTFMaterial material; + + apply_test_material_texture_ids(material); + + apply_test_material_texture_transforms(material); + + apply_test_material_factors(material); + + material.setAlphaCutoff(test_fraction); + // Because this is the default value, it should append to the extras field to mark it as an override + material.setAlphaMode(LLGLTFMaterial::ALPHA_MODE_OPAQUE); + // Because this is the default value, it should append to the extras field to mark it as an override + material.setDoubleSided(false); + + return material; + } + + void ensure_gltf_material_serialize(const std::string& ensure_suffix, const LLGLTFMaterial& material_in) + { + const std::string json_in = material_in.asJSON(); + LLGLTFMaterial material_out; + std::string warn_msg; + std::string error_msg; + bool serialize_success = material_out.fromJSON(json_in, warn_msg, error_msg); + ensure_equals("LLGLTFMaterial serialization has no warnings: " + ensure_suffix, "", warn_msg); + ensure_equals("LLGLTFMaterial serialization has no errors: " + ensure_suffix, "", error_msg); + ensure("LLGLTFMaterial serializes successfully: " + ensure_suffix, serialize_success); + ensure("LLGLTFMaterial is preserved when deserialized: " + ensure_suffix, material_in == material_out); + const std::string json_out = material_out.asJSON(); + ensure_equals("LLGLTFMaterial is preserved when serialized: " + ensure_suffix, json_in, json_out); + } + + void ensure_gltf_material_trimmed(const std::string& material_json, const std::string& must_not_contain) + { + ensure("LLGLTFMaterial serialization trims property '" + must_not_contain + "'", material_json.find(must_not_contain) == std::string::npos); + } + + // Test that GLTF material fields have not changed since these tests were written + template<> template<> + void llgltfmaterial_object_t::test<1>() + { + if (sizeof(void*) > 4) // Don't bother running this test for 32-bit systems + { + // If any fields are added/changed, these tests should be updated (consider also updating ASSET_VERSION in LLGLTFMaterial) + // This test result will vary between compilers, so only test a single platform +#if LL_WINDOWS + ensure_equals("fields supported for GLTF (sizeof check)", sizeof(LLGLTFMaterial), 216); +#endif + } + ensure_equals("LLGLTFMaterial texture info count", (U32)LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT, 4); + } + + // Test that occlusion and metallicRoughness are the same (They are different for asset validation. See lluploadmaterial.cpp) + template<> template<> + void llgltfmaterial_object_t::test<2>() + { + ensure_equals("LLGLTFMaterial occlusion does not differ from metallic roughness", LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS, LLGLTFMaterial::GLTF_TEXTURE_INFO_OCCLUSION); + } + + // Ensure double sided and alpha mode overrides serialize as expected + template<> template<> + void llgltfmaterial_object_t::test<3>() + { + const bool doubleSideds[] { false, true }; + const LLGLTFMaterial::AlphaMode alphaModes[] { LLGLTFMaterial::ALPHA_MODE_OPAQUE, LLGLTFMaterial::ALPHA_MODE_BLEND, LLGLTFMaterial::ALPHA_MODE_MASK }; + const bool forOverrides[] { false, true }; + + for (bool doubleSided : doubleSideds) + { + for (bool forOverride : forOverrides) + { + LLGLTFMaterial material; + material.setDoubleSided(doubleSided, forOverride); + const bool overrideBit = (doubleSided == false) && forOverride; + ensure_equals("LLGLTFMaterial: double sided = " + std::to_string(doubleSided) + " override bit when forOverride = " + std::to_string(forOverride), material.mOverrideDoubleSided, overrideBit); + ensure_gltf_material_serialize("double sided = " + std::to_string(doubleSided), material); + } + } + + for (LLGLTFMaterial::AlphaMode alphaMode : alphaModes) + { + for (bool forOverride : forOverrides) + { + LLGLTFMaterial material; + material.setAlphaMode(alphaMode, forOverride); + const bool overrideBit = (alphaMode == LLGLTFMaterial::ALPHA_MODE_OPAQUE) && forOverride; + ensure_equals("LLGLTFMaterial: alpha mode = " + std::to_string(alphaMode) + " override bit when forOverride = " + std::to_string(forOverride), material.mOverrideAlphaMode, overrideBit); + ensure_gltf_material_serialize("alpha mode = " + std::to_string(alphaMode), material); + } + } + } + + // Test that a GLTF material's transform components serialize as expected + template<> template<> + void llgltfmaterial_object_t::test<4>() + { + LLGLTFMaterial material; + LLGLTFMaterial::TextureTransform& transform = material.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR]; + transform.mOffset[VX] = 1.f; + transform.mOffset[VY] = 2.f; + transform.mScale[VX] = 0.05f; + transform.mScale[VY] = 100.f; + transform.mRotation = 1.571f; + ensure_gltf_material_serialize("material with transform", material); + } + + // Test that a GLTF material avoids serializing a material unnecessarily + template<> template<> + void llgltfmaterial_object_t::test<5>() + { + { + const LLGLTFMaterial material; + const std::string material_json = material.asJSON(); + ensure_gltf_material_trimmed(material_json, "pbrMetallicRoughness"); + ensure_gltf_material_trimmed(material_json, "normalTexture"); + ensure_gltf_material_trimmed(material_json, "emissiveTexture"); + ensure_gltf_material_trimmed(material_json, "occlusionTexture"); + } + + { + LLGLTFMaterial metallic_factor_material; + metallic_factor_material.setMetallicFactor(0.5); + const std::string metallic_factor_material_json = metallic_factor_material.asJSON(); + ensure_gltf_material_trimmed(metallic_factor_material_json, "baseColorTexture"); + ensure_gltf_material_trimmed(metallic_factor_material_json, "metallicRoughnessTexture"); + } + } + + // Test that a GLTF material preserves values on serialization + template<> template<> + void llgltfmaterial_object_t::test<6>() + { + { + const LLGLTFMaterial full_material = create_test_material(); + ensure_gltf_material_serialize("full material", full_material); + } + + { + LLGLTFMaterial texture_ids_only_material; + apply_test_material_texture_ids(texture_ids_only_material); + ensure_gltf_material_serialize("material with texture IDs only", texture_ids_only_material); + } + + { + LLGLTFMaterial texture_transforms_only_material; + apply_test_material_texture_ids(texture_transforms_only_material); + ensure_gltf_material_serialize("material with texture transforms only", texture_transforms_only_material); + } + + { + LLGLTFMaterial factors_only_material; + apply_test_material_factors(factors_only_material); + ensure_gltf_material_serialize("material with scaling/tint factors only", factors_only_material); + } + } +} diff --git a/indra/newview/llgltfmateriallist.cpp b/indra/newview/llgltfmateriallist.cpp index bc094ac838..4051521ad4 100644 --- a/indra/newview/llgltfmateriallist.cpp +++ b/indra/newview/llgltfmateriallist.cpp @@ -564,9 +564,9 @@ void LLGLTFMaterialList::onAssetLoadComplete(const LLUUID& id, LLAssetType::ETyp if (LLSDSerialize::deserialize(asset, str, buffer.size())) { - if (asset.has("version") && asset["version"] == "1.0") + if (asset.has("version") && LLGLTFMaterial::isAcceptedVersion(asset["version"].asString())) { - if (asset.has("type") && asset["type"].asString() == "GLTF 2.0") + if (asset.has("type") && asset["type"].asString() == LLGLTFMaterial::ASSET_TYPE) { if (asset.has("data") && asset["data"].isString()) { diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 14ebfa451a..41085afb3d 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -277,10 +277,10 @@ bool LLSelectedTEGetMatData::apply(LLViewerObject* objectp, S32 te_index) llassert(mat.notNull()); // by this point shouldn't be null if (mat.notNull()) { - tex_color_id = mat->mBaseColorId; - tex_metal_id = mat->mMetallicRoughnessId; - tex_emissive_id = mat->mEmissiveId; - tex_normal_id = mat->mNormalId; + tex_color_id = mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR]; + tex_metal_id = mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS]; + tex_emissive_id = mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE]; + tex_normal_id = mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL]; } if (mFirst) { @@ -949,7 +949,7 @@ void LLMaterialEditor::onSelectCtrl(LLUICtrl* ctrl, const LLSD& data, S32 dirty_ } case MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY: { - nodep->mSavedGLTFOverrideMaterials[te]->setMetallicRoughnessId(mCtrl->getValue().asUUID(), true); + nodep->mSavedGLTFOverrideMaterials[te]->setOcclusionRoughnessMetallicId(mCtrl->getValue().asUUID(), true); break; } case MATERIAL_EMISIVE_TEX_DIRTY: @@ -991,30 +991,6 @@ void LLMaterialEditor::onSelectCtrl(LLUICtrl* ctrl, const LLSD& data, S32 dirty_ LLSelectMgr::getInstance()->getSelection()->applyToNodes(&func); } -static void write_color(const LLColor4& color, std::vector<double>& c) -{ - for (int i = 0; i < c.size(); ++i) // NOTE -- use c.size because some gltf colors are 3-component - { - c[i] = color.mV[i]; - } -} - -static U32 write_texture(const LLUUID& id, tinygltf::Model& model) -{ - tinygltf::Image image; - image.uri = id.asString(); - model.images.push_back(image); - U32 image_idx = model.images.size() - 1; - - tinygltf::Texture texture; - texture.source = image_idx; - model.textures.push_back(texture); - U32 texture_idx = model.textures.size() - 1; - - return texture_idx; -} - - void LLMaterialEditor::onClickSave() { if (!capabilitiesAvailable()) @@ -1034,109 +1010,14 @@ void LLMaterialEditor::onClickSave() saveIfNeeded(); } - -std::string LLMaterialEditor::getGLTFJson(bool prettyprint) -{ - tinygltf::Model model; - getGLTFModel(model); - - std::ostringstream str; - - tinygltf::TinyGLTF gltf; - - gltf.WriteGltfSceneToStream(&model, str, prettyprint, false); - - std::string dump = str.str(); - - return dump; -} - -void LLMaterialEditor::getGLBData(std::vector<U8>& data) -{ - tinygltf::Model model; - getGLTFModel(model); - - std::ostringstream str; - - tinygltf::TinyGLTF gltf; - - gltf.WriteGltfSceneToStream(&model, str, false, true); - - std::string dump = str.str(); - - data.resize(dump.length()); - - memcpy(&data[0], dump.c_str(), dump.length()); -} - -void LLMaterialEditor::getGLTFModel(tinygltf::Model& model) -{ - model.materials.resize(1); - tinygltf::PbrMetallicRoughness& pbrMaterial = model.materials[0].pbrMetallicRoughness; - - // write base color - LLColor4 base_color = getBaseColor(); - base_color.mV[3] = getTransparency(); - write_color(base_color, pbrMaterial.baseColorFactor); - - model.materials[0].alphaCutoff = getAlphaCutoff(); - model.materials[0].alphaMode = getAlphaMode(); - - LLUUID base_color_id = getBaseColorId(); - - if (base_color_id.notNull()) - { - U32 texture_idx = write_texture(base_color_id, model); - - pbrMaterial.baseColorTexture.index = texture_idx; - } - - // write metallic/roughness - F32 metalness = getMetalnessFactor(); - F32 roughness = getRoughnessFactor(); - - pbrMaterial.metallicFactor = metalness; - pbrMaterial.roughnessFactor = roughness; - - LLUUID mr_id = getMetallicRoughnessId(); - if (mr_id.notNull()) - { - U32 texture_idx = write_texture(mr_id, model); - pbrMaterial.metallicRoughnessTexture.index = texture_idx; - } - - //write emissive - LLColor4 emissive_color = getEmissiveColor(); - model.materials[0].emissiveFactor.resize(3); - write_color(emissive_color, model.materials[0].emissiveFactor); - - LLUUID emissive_id = getEmissiveId(); - if (emissive_id.notNull()) - { - U32 idx = write_texture(emissive_id, model); - model.materials[0].emissiveTexture.index = idx; - } - - //write normal - LLUUID normal_id = getNormalId(); - if (normal_id.notNull()) - { - U32 idx = write_texture(normal_id, model); - model.materials[0].normalTexture.index = idx; - } - - //write doublesided - model.materials[0].doubleSided = getDoubleSided(); - - model.asset.version = "2.0"; -} - std::string LLMaterialEditor::getEncodedAsset() { LLSD asset; - asset["version"] = "1.0"; - asset["type"] = "GLTF 2.0"; - asset["data"] = getGLTFJson(false); + asset["version"] = LLGLTFMaterial::ASSET_VERSION; + asset["type"] = LLGLTFMaterial::ASSET_TYPE; + LLGLTFMaterial mat; + getGLTFMaterial(&mat); + asset["data"] = mat.asJSON(); std::ostringstream str; LLSDSerialize::serialize(asset, str, LLSDSerialize::LLSD_BINARY); @@ -1151,9 +1032,9 @@ bool LLMaterialEditor::decodeAsset(const std::vector<char>& buffer) std::istrstream str(&buffer[0], buffer.size()); if (LLSDSerialize::deserialize(asset, str, buffer.size())) { - if (asset.has("version") && asset["version"] == "1.0") + if (asset.has("version") && LLGLTFMaterial::isAcceptedVersion(asset["version"].asString())) { - if (asset.has("type") && asset["type"] == "GLTF 2.0") + if (asset.has("type") && asset["type"] == LLGLTFMaterial::ASSET_TYPE) { if (asset.has("data") && asset["data"].isString()) { @@ -1169,6 +1050,12 @@ bool LLMaterialEditor::decodeAsset(const std::vector<char>& buffer) if (loader.LoadASCIIFromString(&model_in, &error_msg, &warn_msg, data.c_str(), data.length(), "")) { // assets are only supposed to have one item + // *NOTE: This duplicates some functionality from + // LLGLTFMaterial::fromJSON, but currently does the job + // better for the material editor use case. + // However, LLGLTFMaterial::asJSON should always be + // used when uploading materials, to ensure the + // asset is valid. return setFromGltfModel(model_in, 0, true); } else @@ -1975,7 +1862,9 @@ void LLMaterialEditor::saveMaterialAs(const LLGLTFMaterial* render_material, con { // don't use override material here, it has 'hacked ids' // and values, use end result, apply it on top of local. - me->setBaseColor(render_material->mBaseColor); + const LLColor4& base_color = render_material->mBaseColor; + me->setBaseColor(LLColor3(base_color)); + me->setTransparency(base_color[VW]); me->setMetalnessFactor(render_material->mMetallicFactor); me->setRoughnessFactor(render_material->mRoughnessFactor); me->setEmissiveColor(render_material->mEmissiveColor); @@ -1986,24 +1875,24 @@ void LLMaterialEditor::saveMaterialAs(const LLGLTFMaterial* render_material, con // most things like colors we can apply without verifying // but texture ids are going to be different from both, base and override // so only apply override id if there is actually a difference - if (local_material->mBaseColorId != render_material->mBaseColorId) + if (local_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR] != render_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR]) { - me->setBaseColorId(render_material->mBaseColorId); + me->setBaseColorId(render_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR]); me->childSetValue("base_color_upload_fee", me->getString("no_upload_fee_string")); } - if (local_material->mNormalId != render_material->mNormalId) + if (local_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL] != render_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL]) { - me->setNormalId(render_material->mNormalId); + me->setNormalId(render_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL]); me->childSetValue("normal_upload_fee", me->getString("no_upload_fee_string")); } - if (local_material->mMetallicRoughnessId != render_material->mMetallicRoughnessId) + if (local_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS] != render_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS]) { - me->setMetallicRoughnessId(render_material->mMetallicRoughnessId); + me->setMetallicRoughnessId(render_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS]); me->childSetValue("metallic_upload_fee", me->getString("no_upload_fee_string")); } - if (local_material->mEmissiveId != render_material->mEmissiveId) + if (local_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE] != render_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE]) { - me->setEmissiveId(render_material->mEmissiveId); + me->setEmissiveId(render_material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE]); me->childSetValue("emissive_upload_fee", me->getString("no_upload_fee_string")); } @@ -2017,7 +1906,11 @@ void LLMaterialEditor::saveMaterialAs(const LLGLTFMaterial* render_material, con LLSD payload; if (render_material) { - payload["data"] = render_material->asJSON(); + // Make a copy of the render material with unsupported transforms removed + LLGLTFMaterial asset_material = *render_material; + asset_material.sanitizeAssetMaterial(); + // Serialize the sanitized render material + payload["data"] = asset_material.asJSON(); } else { @@ -2040,8 +1933,9 @@ void LLMaterialEditor::onSaveObjectsMaterialAsMsgCallback(const LLSD& notificati if (0 == option) { LLSD asset; - asset["version"] = "1.0"; - asset["type"] = "GLTF 2.0"; + asset["version"] = LLGLTFMaterial::ASSET_VERSION; + asset["type"] = LLGLTFMaterial::ASSET_TYPE; + // This is the string serialized from LLGLTFMaterial::asJSON asset["data"] = notification["payload"]["data"]; std::ostringstream str; @@ -2584,7 +2478,7 @@ public: } else if ((reverted_flags & MATERIAL_BASE_COLOR_TEX_DIRTY) && revert_mat.notNull()) { - material->setBaseColorId(revert_mat->mBaseColorId, false); + material->setBaseColorId(revert_mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR], false); } if (changed_flags & MATERIAL_NORMAL_TEX_DIRTY) @@ -2593,16 +2487,16 @@ public: } else if ((reverted_flags & MATERIAL_NORMAL_TEX_DIRTY) && revert_mat.notNull()) { - material->setNormalId(revert_mat->mNormalId, false); + material->setNormalId(revert_mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL], false); } if (changed_flags & MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY) { - material->setMetallicRoughnessId(mEditor->getMetallicRoughnessId(), true); + material->setOcclusionRoughnessMetallicId(mEditor->getMetallicRoughnessId(), true); } else if ((reverted_flags & MATERIAL_METALLIC_ROUGHTNESS_TEX_DIRTY) && revert_mat.notNull()) { - material->setMetallicRoughnessId(revert_mat->mMetallicRoughnessId, false); + material->setOcclusionRoughnessMetallicId(revert_mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS], false); } if (changed_flags & MATERIAL_METALLIC_ROUGHTNESS_METALNESS_DIRTY) @@ -2638,7 +2532,7 @@ public: } else if ((reverted_flags & MATERIAL_EMISIVE_TEX_DIRTY) && revert_mat.notNull()) { - material->setEmissiveId(revert_mat->mEmissiveId, false); + material->setEmissiveId(revert_mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE], false); } if (changed_flags & MATERIAL_DOUBLE_SIDED_DIRTY) @@ -2751,20 +2645,23 @@ void LLMaterialEditor::applyToSelection() } } +// Get a dump of the json representation of the current state of the editor UI +// in GLTF format, excluding transforms as they are not supported in material +// assets. (See also LLGLTFMaterial::sanitizeAssetMaterial()) void LLMaterialEditor::getGLTFMaterial(LLGLTFMaterial* mat) { mat->mBaseColor = getBaseColor(); mat->mBaseColor.mV[3] = getTransparency(); - mat->mBaseColorId = getBaseColorId(); + mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR] = getBaseColorId(); - mat->mNormalId = getNormalId(); + mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL] = getNormalId(); - mat->mMetallicRoughnessId = getMetallicRoughnessId(); + mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS] = getMetallicRoughnessId(); mat->mMetallicFactor = getMetalnessFactor(); mat->mRoughnessFactor = getRoughnessFactor(); mat->mEmissiveColor = getEmissiveColor(); - mat->mEmissiveId = getEmissiveId(); + mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE] = getEmissiveId(); mat->mDoubleSided = getDoubleSided(); mat->setAlphaMode(getAlphaMode()); @@ -2774,15 +2671,15 @@ void LLMaterialEditor::getGLTFMaterial(LLGLTFMaterial* mat) void LLMaterialEditor::setFromGLTFMaterial(LLGLTFMaterial* mat) { setBaseColor(mat->mBaseColor); - setBaseColorId(mat->mBaseColorId); - setNormalId(mat->mNormalId); + setBaseColorId(mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR]); + setNormalId(mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL]); - setMetallicRoughnessId(mat->mMetallicRoughnessId); + setMetallicRoughnessId(mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS]); setMetalnessFactor(mat->mMetallicFactor); setRoughnessFactor(mat->mRoughnessFactor); setEmissiveColor(mat->mEmissiveColor); - setEmissiveId(mat->mEmissiveId); + setEmissiveId(mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE]); setDoubleSided(mat->mDoubleSided); setAlphaMode(mat->getAlphaMode()); diff --git a/indra/newview/llmaterialeditor.h b/indra/newview/llmaterialeditor.h index 74c776031e..0401190773 100644 --- a/indra/newview/llmaterialeditor.h +++ b/indra/newview/llmaterialeditor.h @@ -84,8 +84,7 @@ protected: }; class LLMaterialEditor : public LLPreview, public LLVOInventoryListener -{ -public: +{ public: LLMaterialEditor(const LLSD& key); bool setFromGltfModel(const tinygltf::Model& model, S32 index, bool set_textures = false); @@ -98,6 +97,7 @@ public: // for live preview, apply current material to currently selected object void applyToSelection(); + // get a dump of the json representation of the current state of the editor UI as a material object void getGLTFMaterial(LLGLTFMaterial* mat); void loadAsset() override; @@ -131,11 +131,6 @@ public: void onClickSave(); - // get a dump of the json representation of the current state of the editor UI in GLTF format - std::string getGLTFJson(bool prettyprint = true); - - void getGLBData(std::vector<U8>& data); - void getGLTFModel(tinygltf::Model& model); std::string getEncodedAsset(); diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index ce086f2520..cb7bc7b5df 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -3825,34 +3825,12 @@ private: struct LLPanelFaceUpdateFunctor : public LLSelectedObjectFunctor { - LLPanelFaceUpdateFunctor(bool update_media, bool update_pbr) + LLPanelFaceUpdateFunctor(bool update_media) : mUpdateMedia(update_media) - , mUpdatePbr(update_pbr) {} virtual bool apply(LLViewerObject* object) { - if (mUpdatePbr) - { - // setRenderMaterialId is supposed to create it - LLRenderMaterialParams* param_block = (LLRenderMaterialParams*)object->getParameterEntry(LLNetworkData::PARAMS_RENDER_MATERIAL); - if (param_block) - { - if (param_block->isEmpty()) - { - object->setHasRenderMaterialParams(false); - } - else if (object->hasRenderMaterialParams()) - { - object->parameterChanged(LLNetworkData::PARAMS_RENDER_MATERIAL, true); - } - else - { - object->setHasRenderMaterialParams(true); - } - } - } - object->sendTEUpdate(); if (mUpdateMedia) @@ -3867,7 +3845,6 @@ struct LLPanelFaceUpdateFunctor : public LLSelectedObjectFunctor } private: bool mUpdateMedia; - bool mUpdatePbr; }; struct LLPanelFaceNavigateHomeFunctor : public LLSelectedTEFunctor @@ -4003,7 +3980,7 @@ void LLPanelFace::onPasteColor() LLPanelFacePasteTexFunctor paste_func(this, PASTE_COLOR); selected_objects->applyToTEs(&paste_func); - LLPanelFaceUpdateFunctor sendfunc(false, false); + LLPanelFaceUpdateFunctor sendfunc(false); selected_objects->applyToObjects(&sendfunc); } @@ -4364,7 +4341,7 @@ void LLPanelFace::onPasteTexture() LLPanelFacePasteTexFunctor paste_func(this, PASTE_TEXTURE); selected_objects->applyToTEs(&paste_func); - LLPanelFaceUpdateFunctor sendfunc(true, true); + LLPanelFaceUpdateFunctor sendfunc(true); selected_objects->applyToObjects(&sendfunc); LLGLTFMaterialList::flushUpdates(); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 02e85d7470..55cf6795fe 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -1941,12 +1941,6 @@ void LLSelectMgr::selectionSetGLTFMaterial(const LLUUID& mat_id) asset_id = mItem->getAssetUUID(); } - if (asset_id.notNull() && !objectp->hasRenderMaterialParams()) - { - // make sure param section exists - objectp->setParameterEntryInUse(LLNetworkData::PARAMS_RENDER_MATERIAL, TRUE, false /*prevent an update*/); - } - // Blank out most override data on the object and send to server objectp->setRenderMaterialID(te, asset_id); @@ -1975,25 +1969,6 @@ void LLSelectMgr::selectionSetGLTFMaterial(const LLUUID& mat_id) return false; } - LLRenderMaterialParams* param_block = (LLRenderMaterialParams*)object->getParameterEntry(LLNetworkData::PARAMS_RENDER_MATERIAL); - if (param_block) - { - // To not cause multiple competing request that modify - // same param field send update only once per object - if (param_block->isEmpty()) - { - object->setHasRenderMaterialParams(false); - } - else if (object->hasRenderMaterialParams()) - { - object->parameterChanged(LLNetworkData::PARAMS_RENDER_MATERIAL, true); - } - else - { - object->setHasRenderMaterialParams(true); - } - } - if (!mItem) { // 1 particle effect per object @@ -2209,14 +2184,13 @@ void LLSelectMgr::selectionRevertGLTFMaterials() { // Restore base material LLUUID asset_id = nodep->mSavedGLTFMaterialIds[te]; - objectp->setRenderMaterialID(te, asset_id, false /*wait for bulk update*/); + // Update material locally + objectp->setRenderMaterialID(te, asset_id, false /*wait for LLGLTFMaterialList update*/); + objectp->setTEGLTFMaterialOverride(te, nodep->mSavedGLTFOverrideMaterials[te]); - // todo: make sure this does not cause race condition with setRenderMaterialID - // when we are reverting from null id to non null plus override - if (te < (S32)nodep->mSavedGLTFOverrideMaterials.size() - && nodep->mSavedGLTFOverrideMaterials[te].notNull() - && asset_id.notNull()) + // Enqueue update to server + if (asset_id.notNull()) { // Restore overrides LLGLTFMaterialList::queueModify(objectp, te, nodep->mSavedGLTFOverrideMaterials[te]); @@ -2232,38 +2206,6 @@ void LLSelectMgr::selectionRevertGLTFMaterials() } } setfunc(mSelectedObjects); getSelection()->applyToTEs(&setfunc); - - struct g : public LLSelectedObjectFunctor - { - virtual bool apply(LLViewerObject* object) - { - if (object && !object->permModify()) - { - return false; - } - - LLRenderMaterialParams* param_block = (LLRenderMaterialParams*)object->getParameterEntry(LLNetworkData::PARAMS_RENDER_MATERIAL); - if (param_block) - { - if (param_block->isEmpty()) - { - object->setHasRenderMaterialParams(false); - } - else if (object->hasRenderMaterialParams()) - { - object->parameterChanged(LLNetworkData::PARAMS_RENDER_MATERIAL, true); - } - else - { - object->setHasRenderMaterialParams(true); - } - } - - object->sendTEUpdate(); - return true; - } - } sendfunc; - getSelection()->applyToObjects(&sendfunc); } void LLSelectMgr::selectionSetBumpmap(U8 bumpmap, const LLUUID &image_id) diff --git a/indra/newview/lltinygltfhelper.cpp b/indra/newview/lltinygltfhelper.cpp index 611911014a..1a8e868d11 100644 --- a/indra/newview/lltinygltfhelper.cpp +++ b/indra/newview/lltinygltfhelper.cpp @@ -309,48 +309,48 @@ bool LLTinyGLTFHelper::getMaterialFromFile( if (base_color_tex) { base_color_tex->addTextureStats(64.f * 64.f, TRUE); - material->mBaseColorId = base_color_tex->getID(); + material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR] = base_color_tex->getID(); material->mBaseColorTexture = base_color_tex; } else { - material->mBaseColorId = LLUUID::null; + material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR] = LLUUID::null; material->mBaseColorTexture = nullptr; } if (normal_tex) { normal_tex->addTextureStats(64.f * 64.f, TRUE); - material->mNormalId = normal_tex->getID(); + material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL] = normal_tex->getID(); material->mNormalTexture = normal_tex; } else { - material->mNormalId = LLUUID::null; + material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL] = LLUUID::null; material->mNormalTexture = nullptr; } if (mr_tex) { mr_tex->addTextureStats(64.f * 64.f, TRUE); - material->mMetallicRoughnessId = mr_tex->getID(); + material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS] = mr_tex->getID(); material->mMetallicRoughnessTexture = mr_tex; } else { - material->mMetallicRoughnessId = LLUUID::null; + material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS] = LLUUID::null; material->mMetallicRoughnessTexture = nullptr; } if (emissive_tex) { emissive_tex->addTextureStats(64.f * 64.f, TRUE); - material->mEmissiveId = emissive_tex->getID(); + material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE] = emissive_tex->getID(); material->mEmissiveTexture = emissive_tex; } else { - material->mEmissiveId = LLUUID::null; + material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE] = LLUUID::null; material->mEmissiveTexture = nullptr; } diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index 84b0010545..9743f00ab8 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -543,19 +543,19 @@ bool get_bulk_upload_expected_cost(const std::vector<std::string>& filenames, S3 // Todo: make it account for possibility of same texture in different // materials and even in scope of same material S32 texture_count = 0; - if (material->mBaseColorId.notNull()) + if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR].notNull()) { texture_count++; } - if (material->mMetallicRoughnessId.notNull()) + if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS].notNull()) { texture_count++; } - if (material->mNormalId.notNull()) + if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL].notNull()) { texture_count++; } - if (material->mEmissiveId.notNull()) + if (material->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE].notNull()) { texture_count++; } diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 3c0a08cee1..e217ede067 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -4992,10 +4992,10 @@ void LLViewerObject::updateTEMaterialTextures(U8 te) if (mat != nullptr) { - mat->mBaseColorTexture = fetch_texture(mat->mBaseColorId); - mat->mNormalTexture = fetch_texture(mat->mNormalId); - mat->mMetallicRoughnessTexture = fetch_texture(mat->mMetallicRoughnessId); - mat->mEmissiveTexture= fetch_texture(mat->mEmissiveId); + mat->mBaseColorTexture = fetch_texture(mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR]); + mat->mNormalTexture = fetch_texture(mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_NORMAL]); + mat->mMetallicRoughnessTexture = fetch_texture(mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS]); + mat->mEmissiveTexture= fetch_texture(mat->mTextureId[LLGLTFMaterial::GLTF_TEXTURE_INFO_EMISSIVE]); } } @@ -6289,6 +6289,11 @@ void LLViewerObject::parameterChanged(U16 param_type, LLNetworkData* data, BOOL { if (local_origin) { + // *NOTE: Do not send the render material ID in this way as it will get + // out-of-sync with other sent client data. + // See LLViewerObject::setRenderMaterialID and LLGLTFMaterialList + llassert(param_type != LLNetworkData::PARAMS_RENDER_MATERIAL); + LLViewerRegion* regionp = getRegion(); if(!regionp) return; @@ -7245,18 +7250,6 @@ void LLViewerObject::setRenderMaterialID(S32 te_in, const LLUUID& id, bool updat }); } - if (update_server) - { - // update via ModifyMaterialParams cap (server will echo back changes) - for (S32 te = start_idx; te < end_idx; ++te) - { - // This sends a cleared version of this object's current material - // override, but the override should already be cleared due to - // calling setBaseMaterial above. - LLGLTFMaterialList::queueApply(this, te, id); - } - } - // predictively update LLRenderMaterialParams (don't wait for server) if (param_block) { // update existing parameter block @@ -7264,17 +7257,17 @@ void LLViewerObject::setRenderMaterialID(S32 te_in, const LLUUID& id, bool updat { param_block->setMaterial(te, id); } + } - if (update_server) + if (update_server) + { + // update via ModifyMaterialParams cap (server will echo back changes) + for (S32 te = start_idx; te < end_idx; ++te) { - // If 'in use' changes, it will send an update itself. - bool in_use_changed = setParameterEntryInUse(LLNetworkData::PARAMS_RENDER_MATERIAL, !param_block->isEmpty(), true); - - if (!in_use_changed) - { - // In use didn't change, but the parameter did, send an update - parameterChanged(LLNetworkData::PARAMS_RENDER_MATERIAL, param_block, !param_block->isEmpty(), true); - } + // This sends a cleared version of this object's current material + // override, but the override should already be cleared due to + // calling setBaseMaterial above. + LLGLTFMaterialList::queueApply(this, te, id); } } } |