diff options
| author | Cosmic Linden <cosmic@lindenlab.com> | 2022-10-27 12:22:00 -0700 | 
|---|---|---|
| committer | Cosmic Linden <cosmic@lindenlab.com> | 2022-10-27 13:19:19 -0700 | 
| commit | 5364da4d8eae518b0a53fdbbf675c6bff1797fed (patch) | |
| tree | f6d8b02e0ee5d28a5d16a5ef777d311db23a62b6 | |
| parent | 414efe56bdf061edddd9026b015f6197c7615577 (diff) | |
SL-18411: GLTF material transform serialization, plus fix improper indexing not matching GLTF spec
| -rw-r--r-- | indra/llprimitive/llgltfmaterial.cpp | 266 | ||||
| -rw-r--r-- | indra/llprimitive/llgltfmaterial.h | 8 | 
2 files changed, 152 insertions, 122 deletions
diff --git a/indra/llprimitive/llgltfmaterial.cpp b/indra/llprimitive/llgltfmaterial.cpp index 7b6612b90a..6164234d6c 100644 --- a/indra/llprimitive/llgltfmaterial.cpp +++ b/indra/llprimitive/llgltfmaterial.cpp @@ -30,6 +30,11 @@  #include "tinygltf/tiny_gltf.h" +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"; +const char* GLTF_FILE_EXTENSION_TRANSFORM_ROTATION = "rotation"; +  LLGLTFMaterial::LLGLTFMaterial(const LLGLTFMaterial& rhs)  {      *this = rhs; @@ -82,6 +87,7 @@ std::string LLGLTFMaterial::asJSON(bool prettyprint) const  {  #if 1      tinygltf::TinyGLTF gltf; +      tinygltf::Model model_out;      std::ostringstream str; @@ -105,118 +111,131 @@ void LLGLTFMaterial::setFromModel(const tinygltf::Model& model, S32 mat_index)      const tinygltf::Material& material_in = model.materials[mat_index]; -    // get base color texture -    S32 tex_index = material_in.pbrMetallicRoughness.baseColorTexture.index; -    if (tex_index >= 0) -    { -        mBaseColorId.set(model.images[tex_index].uri); -    } -    else +    // Apply base color texture +    setFromTexture(model, material_in.pbrMetallicRoughness.baseColorTexture, GLTF_TEXTURE_INFO_BASE_COLOR, mBaseColorId); +    // Apply normal map +    setFromTexture(model, material_in.normalTexture, GLTF_TEXTURE_INFO_NORMAL, mNormalId); +    // Apply metallic-roughness texture +    setFromTexture(model, material_in.pbrMetallicRoughness.metallicRoughnessTexture, GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS, mMetallicRoughnessId); +    // Apply emissive texture +    setFromTexture(model, material_in.emissiveTexture, GLTF_TEXTURE_INFO_EMISSIVE, mEmissiveId); + +    setAlphaMode(material_in.alphaMode); +    mAlphaCutoff = llclamp((F32)material_in.alphaCutoff, 0.f, 1.f); + +    mBaseColor.set(material_in.pbrMetallicRoughness.baseColorFactor); +    mEmissiveColor.set(material_in.emissiveFactor); + +    mMetallicFactor = llclamp((F32)material_in.pbrMetallicRoughness.metallicFactor, 0.f, 1.f); +    mRoughnessFactor = llclamp((F32)material_in.pbrMetallicRoughness.roughnessFactor, 0.f, 1.f); + +    mDoubleSided = material_in.doubleSided; +} + +LLVector2 vec2_from_json(const tinygltf::Value::Object& object, const char* key, const LLVector2& default_value) +{ +    const auto it = object.find(key); +    if (it == object.end())      { -        mBaseColorId.setNull(); +        return default_value;      } - -    // get normal map -    tex_index = material_in.normalTexture.index; -    if (tex_index >= 0) +    const tinygltf::Value& vec2_json = std::get<1>(*it); +    if (!vec2_json.IsArray() || vec2_json.ArrayLen() < LENGTHOFVECTOR2)      { -        mNormalId.set(model.images[tex_index].uri); +        return default_value;      } -    else +    LLVector2 value; +    for (U32 i = 0; i < LENGTHOFVECTOR2; ++i)      { -        mNormalId.setNull(); +        const tinygltf::Value& real_json = vec2_json.Get(i); +        if (!real_json.IsReal()) +        { +            return default_value; +        } +        value.mV[i] = (F32)real_json.Get<double>();      } +    return value; +} -    // get metallic-roughness texture -    tex_index = material_in.pbrMetallicRoughness.metallicRoughnessTexture.index; -    if (tex_index >= 0) +F32 float_from_json(const tinygltf::Value::Object& object, const char* key, const F32 default_value) +{ +    const auto it = object.find(key); +    if (it == object.end())      { -        mMetallicRoughnessId.set(model.images[tex_index].uri); +        return default_value;      } -    else +    const tinygltf::Value& real_json = std::get<1>(*it); +    if (!real_json.IsReal())      { -        mMetallicRoughnessId.setNull(); +        return default_value;      } +    return (F32)real_json.GetNumberAsDouble(); +} -    // get emissive texture -    tex_index = material_in.emissiveTexture.index; -    if (tex_index >= 0) +template<typename T> +std::string gltf_get_texture_image(const tinygltf::Model& model, const T& texture_info) +{ +    const S32 texture_idx = texture_info.index; +    if (texture_idx < 0 || texture_idx >= model.textures.size())      { -        mEmissiveId.set(model.images[tex_index].uri); +        return "";      } -    else +    const tinygltf::Texture& texture = model.textures[texture_idx]; + +    // Ignore texture.sampler for now + +    const S32 image_idx = texture.source; +    if (image_idx < 0 || image_idx >= model.images.size())      { -        mEmissiveId.setNull(); +        return "";      } +    const tinygltf::Image& image = model.images[image_idx]; -    setAlphaMode(material_in.alphaMode); -    mAlphaCutoff = llclamp((F32)material_in.alphaCutoff, 0.f, 1.f); - -    mBaseColor.set(material_in.pbrMetallicRoughness.baseColorFactor); -    mEmissiveColor.set(material_in.emissiveFactor); +    return image.uri; +} -    mMetallicFactor = llclamp((F32)material_in.pbrMetallicRoughness.metallicFactor, 0.f, 1.f); -    mRoughnessFactor = llclamp((F32)material_in.pbrMetallicRoughness.roughnessFactor, 0.f, 1.f); +// *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) +{ +    const std::string uri = gltf_get_texture_image(model, texture_info); +    texture_id_out.set(uri); -    mDoubleSided = material_in.doubleSided; +    const tinygltf::Value::Object& extensions_object = texture_info.extensions; +    const auto transform_it = extensions_object.find(GLTF_FILE_EXTENSION_TRANSFORM); +    if (transform_it != extensions_object.end()) +    { +        const tinygltf::Value& transform_json = std::get<1>(*transform_it); +        if (transform_json.IsObject()) +        { +            const tinygltf::Value::Object& transform_object = transform_json.Get<tinygltf::Value::Object>(); +            TextureTransform& transform = mTextureTransform[texture_info_id]; +            transform.mOffset = vec2_from_json(transform_object, GLTF_FILE_EXTENSION_TRANSFORM_OFFSET, getDefaultTextureOffset()); +            transform.mScale = vec2_from_json(transform_object, GLTF_FILE_EXTENSION_TRANSFORM_SCALE, getDefaultTextureScale()); +            transform.mRotation = float_from_json(transform_object, GLTF_FILE_EXTENSION_TRANSFORM_ROTATION, getDefaultTextureRotation()); +        } +    }  }  void LLGLTFMaterial::writeToModel(tinygltf::Model& model, S32 mat_index) const  { -    if (model.materials.size() < mat_index + 1) +    if (model.materials.size() < mat_index+1)      {          model.materials.resize(mat_index + 1);      }      tinygltf::Material& material_out = model.materials[mat_index]; -    // set base color texture -    if (mBaseColorId.notNull()) -    { -        U32 idx = model.images.size(); -        model.images.resize(idx + 1); -        model.textures.resize(idx + 1); - -        material_out.pbrMetallicRoughness.baseColorTexture.index = idx; -        model.textures[idx].source = idx; -        model.images[idx].uri = mBaseColorId.asString(); -    } +    constexpr bool is_override = false; +    // set base color texture +    writeToTexture(model, material_out.pbrMetallicRoughness.baseColorTexture, GLTF_TEXTURE_INFO_BASE_COLOR, mBaseColorId, is_override, LLUUID());      // set normal texture -    if (mNormalId.notNull()) -    { -        U32 idx = model.images.size(); -        model.images.resize(idx + 1); -        model.textures.resize(idx + 1); - -        material_out.normalTexture.index = idx; -        model.textures[idx].source = idx; -        model.images[idx].uri = mNormalId.asString(); -    } - +    writeToTexture(model, material_out.normalTexture, GLTF_TEXTURE_INFO_NORMAL, mNormalId, is_override, LLUUID());      // set metallic-roughness texture -    if (mMetallicRoughnessId.notNull()) -    { -        U32 idx = model.images.size(); -        model.images.resize(idx + 1); -        model.textures.resize(idx + 1); - -        material_out.pbrMetallicRoughness.metallicRoughnessTexture.index = idx; -        model.textures[idx].source = idx; -        model.images[idx].uri = mMetallicRoughnessId.asString(); -    } - +    writeToTexture(model, material_out.pbrMetallicRoughness.metallicRoughnessTexture, GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS, mMetallicRoughnessId, is_override, LLUUID());      // set emissive texture -    if (mEmissiveId.notNull()) -    { -        U32 idx = model.images.size(); -        model.images.resize(idx + 1); -        model.textures.resize(idx + 1); - -        material_out.emissiveTexture.index = idx; -        model.textures[idx].source = idx; -        model.images[idx].uri = mEmissiveId.asString(); -    } +    writeToTexture(model, material_out.emissiveTexture, GLTF_TEXTURE_INFO_EMISSIVE, mEmissiveId, is_override, LLUUID());      material_out.alphaMode = getAlphaMode();      material_out.alphaCutoff = mAlphaCutoff; @@ -232,6 +251,46 @@ void LLGLTFMaterial::writeToModel(tinygltf::Model& model, S32 mat_index) const      model.asset.version = "2.0";  } +template<typename T> +void gltf_allocate_texture_image(tinygltf::Model& model, T& texture_info, const std::string& uri) +{ +    const S32 image_idx = model.images.size(); +    model.images.emplace_back(); +    model.images[image_idx].uri = uri; + +    // The texture, not to be confused with the texture info +    const S32 texture_idx = model.textures.size(); +    model.textures.emplace_back(); +    tinygltf::Texture& texture = model.textures[texture_idx]; +    texture.source = image_idx; + +    texture_info.index = texture_idx; +} + +template<typename T> +void LLGLTFMaterial::writeToTexture(tinygltf::Model& model, T& texture_info, TextureInfo texture_info_id, const LLUUID& texture_id, bool is_override, const LLUUID& base_texture_id) const +{ +    if (texture_id.isNull() || (is_override && texture_id == base_texture_id)) +    { +        return; +    } + +    gltf_allocate_texture_image(model, texture_info, texture_id.asString()); + +    tinygltf::Value::Object transform_map; +    const TextureTransform& transform = mTextureTransform[texture_info_id]; +    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::setBaseColorId(const LLUUID& id)  { @@ -390,53 +449,16 @@ void LLGLTFMaterial::writeOverridesToModel(tinygltf::Model& model, S32 mat_index      // TODO - fix handling of resetting to null/default values -    // set base color texture -    if (mBaseColorId.notNull() && mBaseColorId != base_material->mBaseColorId) -    { -        U32 idx = model.images.size(); -        model.images.resize(idx + 1); -        model.textures.resize(idx + 1); - -        material_out.pbrMetallicRoughness.baseColorTexture.index = idx; -        model.textures[idx].source = idx; -        model.images[idx].uri = mBaseColorId.asString(); -    } +    constexpr bool is_override = true; +    // set base color texture +    writeToTexture(model, material_out.pbrMetallicRoughness.baseColorTexture, GLTF_TEXTURE_INFO_BASE_COLOR, mBaseColorId, is_override, base_material->mBaseColorId);      // set normal texture -    if (mNormalId.notNull() && mNormalId != base_material->mNormalId) -    { -        U32 idx = model.images.size(); -        model.images.resize(idx + 1); -        model.textures.resize(idx + 1); - -        material_out.normalTexture.index = idx; -        model.textures[idx].source = idx; -        model.images[idx].uri = mNormalId.asString(); -    } - +    writeToTexture(model, material_out.normalTexture, GLTF_TEXTURE_INFO_NORMAL, mNormalId, is_override, base_material->mNormalId);      // set metallic-roughness texture -    if (mMetallicRoughnessId.notNull() && mMetallicRoughnessId != base_material->mMetallicRoughnessId) -    { -        U32 idx = model.images.size(); -        model.images.resize(idx + 1); -        model.textures.resize(idx + 1); - -        material_out.pbrMetallicRoughness.metallicRoughnessTexture.index = idx; -        model.textures[idx].source = idx; -        model.images[idx].uri = mMetallicRoughnessId.asString(); -    } - +    writeToTexture(model, material_out.pbrMetallicRoughness.metallicRoughnessTexture, GLTF_TEXTURE_INFO_METALLIC_ROUGHNESS, mMetallicRoughnessId, is_override, base_material->mMetallicRoughnessId);      // set emissive texture -    if (mEmissiveId.notNull() && mEmissiveId != base_material->mEmissiveId) -    { -        U32 idx = model.images.size(); -        model.images.resize(idx + 1); -        model.textures.resize(idx + 1); - -        material_out.emissiveTexture.index = idx; -        model.textures[idx].source = idx; -        model.images[idx].uri = mEmissiveId.asString(); -    } +    writeToTexture(model, material_out.emissiveTexture, GLTF_TEXTURE_INFO_EMISSIVE, mEmissiveId, is_override, base_material->mEmissiveId);      if (mAlphaMode != base_material->mAlphaMode)      { diff --git a/indra/llprimitive/llgltfmaterial.h b/indra/llprimitive/llgltfmaterial.h index ea7e402805..b0afb11bb5 100644 --- a/indra/llprimitive/llgltfmaterial.h +++ b/indra/llprimitive/llgltfmaterial.h @@ -118,6 +118,7 @@ public:      void setRoughnessFactor(F32 roughness);      void setAlphaMode(S32 mode);      void setDoubleSided(bool double_sided); +      void setTextureOffset(TextureInfo texture_info, const LLVector2& offset);      void setTextureScale(TextureInfo texture_info, const LLVector2& scale);      void setTextureRotation(TextureInfo texture_info, float rotation); @@ -189,5 +190,12 @@ public:      void applyOverride(const LLGLTFMaterial& override_mat); +private: + +    template<typename T> +    void setFromTexture(const tinygltf::Model& model, const T& texture_info, TextureInfo texture_info_id, LLUUID& texture_id_out); + +    template<typename T> +    void writeToTexture(tinygltf::Model& model, T& texture_info, TextureInfo texture_info_id, const LLUUID& texture_id, bool is_override, const LLUUID& base_texture_id) const;  };  | 
