diff options
Diffstat (limited to 'indra')
-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; }; |