From 131b4ed32dd961f2b60b74960c096f0222c7eb30 Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Sat, 27 Jul 2019 18:46:51 +0900 Subject: [PATCH] Support KHR material extension as an explicit struct. Supported extensions are: KHR_materials_pbrSpecularGlossiness, KHR_texture_transform and KHR_materials_unlit. --- loader_example.cc | 83 +++++++++- tiny_gltf.h | 394 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 458 insertions(+), 19 deletions(-) diff --git a/loader_example.cc b/loader_example.cc index 93a6866..9c41017 100644 --- a/loader_example.cc +++ b/loader_example.cc @@ -346,11 +346,35 @@ static void DumpExtensions(const tinygltf::ExtensionMap &extension, } } +static void DumpKHRTextureTransform(const tinygltf::KHRTextureTransform &texform, + const int indent) { + assert(texform.offset.size() == 2); + + std::cout << Indent(indent) << "offset : [" << texform.offset[0] << ", " << texform.offset[1] << "]\n"; + std::cout << Indent(indent) << "rotation : " << texform.rotation << "\n"; + std::cout << Indent(indent) << "scale : [" << texform.scale[0] << ", " << texform.scale[1] << "]\n"; + if (texform.texCoord >= 0) { + std::cout << Indent(indent) << "texCoord : TEXCOORD_" << texform.texCoord << "\n"; + } + + std::cout << Indent(indent) << "extensions(items=" << texform.extensions.size() << ")" + << std::endl; + DumpExtensions(texform.extensions, indent + 1); + std::cout << PrintValue("extras", texform.extras, indent + 1) << "\n"; +} + static void DumpTextureInfo(const tinygltf::TextureInfo &texinfo, const int indent) { std::cout << Indent(indent) << "index : " << texinfo.index << "\n"; std::cout << Indent(indent) << "texCoord : TEXCOORD_" << texinfo.texCoord << "\n"; + if (texinfo.KHR_textureTransform.enabled) { + std::cout << Indent(indent) << "KHR_texture_transform\n"; + DumpKHRTextureTransform(texinfo.KHR_textureTransform, indent + 1); + } + + std::cout << Indent(indent) << "extensions(items=" << texinfo.extensions.size() << ")" + << std::endl; DumpExtensions(texinfo.extensions, indent + 1); std::cout << PrintValue("extras", texinfo.extras, indent + 1) << "\n"; } @@ -361,6 +385,14 @@ static void DumpNormalTextureInfo(const tinygltf::NormalTextureInfo &texinfo, std::cout << Indent(indent) << "texCoord : TEXCOORD_" << texinfo.texCoord << "\n"; std::cout << Indent(indent) << "scale : " << texinfo.scale << "\n"; + + if (texinfo.KHR_textureTransform.enabled) { + std::cout << Indent(indent) << "KHR_texture_transform\n"; + DumpKHRTextureTransform(texinfo.KHR_textureTransform, indent + 1); + } + + std::cout << Indent(indent) << "extensions(items=" << texinfo.extensions.size() << ")" + << std::endl; DumpExtensions(texinfo.extensions, indent + 1); std::cout << PrintValue("extras", texinfo.extras, indent + 1) << "\n"; } @@ -371,6 +403,9 @@ static void DumpOcclusionTextureInfo( std::cout << Indent(indent) << "texCoord : TEXCOORD_" << texinfo.texCoord << "\n"; std::cout << Indent(indent) << "strength : " << texinfo.strength << "\n"; + + std::cout << Indent(indent) << "extensions(items=" << texinfo.extensions.size() << ")" + << std::endl; DumpExtensions(texinfo.extensions, indent + 1); std::cout << PrintValue("extras", texinfo.extras, indent + 1) << "\n"; } @@ -390,10 +425,35 @@ static void DumpPbrMetallicRoughness(const tinygltf::PbrMetallicRoughness &pbr, std::cout << Indent(indent) << "metallicRoughnessTexture :\n"; DumpTextureInfo(pbr.metallicRoughnessTexture, indent + 1); + + std::cout << Indent(indent) << "extensions(items=" << pbr.extensions.size() << ")" + << std::endl; DumpExtensions(pbr.extensions, indent + 1); std::cout << PrintValue("extras", pbr.extras, indent + 1) << "\n"; } +static void DumpKHRPbrMetallicRoughness(const tinygltf::KHRPbrSpecularGlossiness &pbr, + const int indent) { + std::cout << Indent(indent) + << "diffuseFactor : " << PrintFloatArray(pbr.diffuseFactor) + << "\n"; + std::cout << Indent(indent) << "diffuseTexture :\n"; + DumpTextureInfo(pbr.diffuseTexture, indent + 1); + + std::cout << Indent(indent) << "specularFactor : " << PrintFloatArray(pbr.specularFactor) << "\n"; + std::cout << Indent(indent) << "glossinessFactor : " << pbr.glossinessFactor + << "\n"; + + std::cout << Indent(indent) << "specularGlossinessTexture :\n"; + DumpTextureInfo(pbr.specularGlossinessTexture, indent + 1); + + std::cout << Indent(indent) << "extensions(items=" << pbr.extensions.size() << ")" + << std::endl; + DumpExtensions(pbr.extensions, indent + 1); + std::cout << PrintValue("extras", pbr.extras, indent + 1) << "\n"; +} + + static void Dump(const tinygltf::Model &model) { std::cout << "=== Dump glTF ===" << std::endl; std::cout << "asset.copyright : " << model.asset.copyright @@ -414,6 +474,9 @@ static void Dump(const tinygltf::Model &model) { for (size_t i = 0; i < model.scenes.size(); i++) { std::cout << Indent(1) << "scene[" << i << "] name : " << model.scenes[i].name << std::endl; + + std::cout << Indent(1) << "extensions(items=" << model.scenes[i].extensions.size() << ")" + << std::endl; DumpExtensions(model.scenes[i].extensions, 1); } } @@ -589,6 +652,15 @@ static void Dump(const tinygltf::Model &model) { std::cout << Indent(1) << "emissiveTexture :\n"; DumpTextureInfo(material.emissiveTexture, 2); + if (material.KHR_materials_unlit) { + std::cout << Indent(1) << "KHR_materials_unlit : true\n"; + } + + if (material.KHR_pbrSpecularGlossiness.enabled) { + std::cout << Indent(1) << "KHR_materials_pbrSpecularGlossinesst\n"; + DumpKHRPbrMetallicRoughness(material.KHR_pbrSpecularGlossiness, 2); + } + std::cout << Indent(1) << "---- legacy material parameter ----\n"; std::cout << Indent(1) << "values(items=" << material.values.size() << ")" << std::endl; @@ -600,7 +672,9 @@ static void Dump(const tinygltf::Model &model) { } std::cout << Indent(1) << "-------------------------------------\n"; - DumpExtensions(material.extensions, 1); + std::cout << Indent(1) << "extensions(items=" << material.extensions.size() << ")" + << std::endl; + DumpExtensions(material.extensions, 2); std::cout << PrintValue("extras", material.extras, 2) << std::endl; } } @@ -624,6 +698,9 @@ static void Dump(const tinygltf::Model &model) { std::cout << Indent(2) << "width : " << image.width << std::endl; std::cout << Indent(2) << "height : " << image.height << std::endl; std::cout << Indent(2) << "component : " << image.component << std::endl; + + std::cout << Indent(1) << "extensions(items=" << image.extensions.size() << ")" + << std::endl; DumpExtensions(image.extensions, 1); } } @@ -636,7 +713,11 @@ static void Dump(const tinygltf::Model &model) { << std::endl; std::cout << Indent(1) << "source : " << texture.source << std::endl; + + std::cout << Indent(1) << "extensions(items=" << texture.extensions.size() << ")" + << std::endl; DumpExtensions(texture.extensions, 1); + std::cout << "\n"; } } diff --git a/tiny_gltf.h b/tiny_gltf.h index 54faf57..ea1c128 100644 --- a/tiny_gltf.h +++ b/tiny_gltf.h @@ -26,6 +26,8 @@ // THE SOFTWARE. // Version: +// - v2.3.1 Explicitly support KHR_materials_pbrSpecularGlossiness, +// KHR_materials_unlit and KHR_texture_transform // - v2.3.0 Modified Material representation according to glTF 2.0 schema // (and introduced TextureInfo class) // Change the behavior of `Value::IsNumber`. It return true either the @@ -592,11 +594,33 @@ struct Texture { bool operator==(const Texture &) const; }; +struct KHRTextureTransform { + bool enabled = false; // true if KHR_texture_transform extension exists in + // glTF model. also plese set this to true if you + // serialize this class to glTF. + + std::vector offset; // len = 2, default [0, 0] + double rotation = 0.0; // default 0.0 + std::vector scale; // len = 2, default [1, 1] + int texCoord = -1; // overwrites the textureInfo texCoord if this is not -1. + // textureInfo this extension belongs to have same + // texCoord value after parsing this extension. + + Value extras; + ExtensionMap extensions; + + KHRTextureTransform() : enabled(false), rotation(0.0), texCoord(-1) {} + bool operator==(const KHRTextureTransform &) const; +}; + struct TextureInfo { int index = -1; // required. int texCoord; // The set index of texture's TEXCOORD attribute used for // texture coordinate mapping. + KHRTextureTransform + KHR_textureTransform; // extensions["KHR_texture_transform"] + Value extras; ExtensionMap extensions; @@ -611,6 +635,9 @@ struct NormalTextureInfo { double scale; // scaledNormal = normalize(( // * 2.0 - 1.0) * vec3(, , 1.0)) + KHRTextureTransform + KHR_textureTransform; // extensions["KHR_texture_transform"] + Value extras; ExtensionMap extensions; @@ -625,6 +652,9 @@ struct OcclusionTextureInfo { double strength; // occludedColor = lerp(color, color * , ) + KHRTextureTransform + KHR_textureTransform; // extensions["KHR_texture_transform"] + Value extras; ExtensionMap extensions; @@ -647,6 +677,25 @@ struct PbrMetallicRoughness { bool operator==(const PbrMetallicRoughness &) const; }; +// KHR_materials_pbrSpecularGlossiness defined in glTF 2.0 KHR extension. +struct KHRPbrSpecularGlossiness { + bool enabled = false; // true if this KHR extension exists in glTF model. + // also plese set this to true if you serialize this + // class to glTF. + + std::vector diffuseFactor; // len = 4. default [1,1,1,1] + TextureInfo diffuseTexture; + std::vector specularFactor; // len = 3. default [1,1,1] + double glossinessFactor = 1.0; // default 1 + TextureInfo specularGlossinessTexture; + + Value extras; + ExtensionMap extensions; + + KHRPbrSpecularGlossiness() : glossinessFactor(1.0) {} + bool operator==(const KHRPbrSpecularGlossiness &) const; +}; + // Each extension should be stored in a ParameterMap. // members not in the values could be included in the ParameterMap // to keep a single material model @@ -664,6 +713,11 @@ struct Material { OcclusionTextureInfo occlusionTexture; TextureInfo emissiveTexture; + bool KHR_materials_unlit = + false; // shortcut to extensions.count("KHR_materials_unlit") + + KHRPbrSpecularGlossiness KHR_pbrSpecularGlossiness; + // For backward compatibility // TODO(syoyo): Remove `values` and `additionalValues` in the next release. ParameterMap values; @@ -672,7 +726,11 @@ struct Material { ExtensionMap extensions; Value extras; - Material() : alphaMode("OPAQUE"), alphaCutoff(0.5), doubleSided(false) {} + Material() + : alphaMode("OPAQUE"), + alphaCutoff(0.5), + doubleSided(false), + KHR_materials_unlit(false) {} bool operator==(const Material &) const; }; @@ -1570,20 +1628,33 @@ bool Texture::operator==(const Texture &other) const { this->name == other.name && this->sampler == other.sampler && this->source == other.source; } + +bool KHRTextureTransform::operator==(const KHRTextureTransform &other) const { + return this->extensions == other.extensions && this->extras == other.extras && + Equals(this->scale, other.scale) && + Equals(this->offset, other.offset) && + TINYGLTF_DOUBLE_EQUAL(this->rotation, other.rotation); +} + bool TextureInfo::operator==(const TextureInfo &other) const { return this->extensions == other.extensions && this->extras == other.extras && - this->index == other.index && this->texCoord == other.texCoord; + this->index == other.index && this->texCoord == other.texCoord && + (this->KHR_textureTransform == other.KHR_textureTransform); } + bool NormalTextureInfo::operator==(const NormalTextureInfo &other) const { return this->extensions == other.extensions && this->extras == other.extras && this->index == other.index && this->texCoord == other.texCoord && - TINYGLTF_DOUBLE_EQUAL(this->scale, other.scale); + TINYGLTF_DOUBLE_EQUAL(this->scale, other.scale) && + (this->KHR_textureTransform == other.KHR_textureTransform); } bool OcclusionTextureInfo::operator==(const OcclusionTextureInfo &other) const { return this->extensions == other.extensions && this->extras == other.extras && this->index == other.index && this->texCoord == other.texCoord && - TINYGLTF_DOUBLE_EQUAL(this->strength, other.strength); + TINYGLTF_DOUBLE_EQUAL(this->strength, other.strength) && + (this->KHR_textureTransform == other.KHR_textureTransform); } + bool PbrMetallicRoughness::operator==(const PbrMetallicRoughness &other) const { return this->extensions == other.extensions && this->extras == other.extras && (this->baseColorTexture == other.baseColorTexture) && @@ -1592,6 +1663,17 @@ bool PbrMetallicRoughness::operator==(const PbrMetallicRoughness &other) const { TINYGLTF_DOUBLE_EQUAL(this->metallicFactor, other.metallicFactor) && TINYGLTF_DOUBLE_EQUAL(this->roughnessFactor, other.roughnessFactor); } + +bool KHRPbrSpecularGlossiness::operator==( + const KHRPbrSpecularGlossiness &other) const { + return this->extensions == other.extensions && this->extras == other.extras && + Equals(this->diffuseFactor, other.diffuseFactor) && + Equals(this->specularFactor, other.specularFactor) && + (this->diffuseTexture == other.diffuseTexture) && + (this->specularGlossinessTexture == other.specularGlossinessTexture) && + TINYGLTF_DOUBLE_EQUAL(this->glossinessFactor, other.glossinessFactor); +} + bool Value::operator==(const Value &other) const { return Equals(*this, other); } @@ -3018,6 +3100,57 @@ static bool ParseTexture(Texture *texture, std::string *err, const json &o, return true; } +static bool ParseKHRTextureTransform(KHRTextureTransform *texform, + std::string *err, const json &o) { + if (texform == nullptr) { + return false; + } + + std::vector offset; + if (ParseNumberArrayProperty(&offset, err, o, "offset", + /* required */ false)) { + if (offset.size() != 2) { + if (err) { + (*err) += + "Array length of `offset` parameter in " + "KHR_texture_transform must be 2, but got " + + std::to_string(offset.size()) + "\n"; + } + return false; + } + } else { + offset = {0.0, 0.0}; + } + texform->offset = offset; + + std::vector scale; + if (ParseNumberArrayProperty(&scale, err, o, "scale", + /* required */ false)) { + if (scale.size() != 2) { + if (err) { + (*err) += + "Array length of `scale` parameter in " + "KHR_texture_transform must be 2, but got " + + std::to_string(scale.size()) + "\n"; + } + return false; + } + } else { + scale = {0.0, 0.0}; + } + texform->scale = scale; + + ParseNumberProperty(&texform->rotation, err, o, "rotation", + /* required */ false); + + ParseIntegerProperty(&texform->texCoord, err, o, "texCoord", + /* required */ false); + + texform->enabled = true; + + return true; +} + static bool ParseTextureInfo(TextureInfo *texinfo, std::string *err, const json &o) { if (texinfo == nullptr) { @@ -3034,7 +3167,19 @@ static bool ParseTextureInfo(TextureInfo *texinfo, std::string *err, ParseExtensionsProperty(&texinfo->extensions, err, o); ParseExtrasProperty(&texinfo->extras, o); - return true; + bool ret = true; + + if (texinfo->extensions.count("KHR_texture_transform")) { + ret &= ParseKHRTextureTransform(&texinfo->KHR_textureTransform, err, + o["extensions"]["KHR_texture_transform"]); + if (texinfo->KHR_textureTransform.enabled && + texinfo->KHR_textureTransform.texCoord >= 0) { + // As described in the specification, overwrite texCoord. + texinfo->texCoord = texinfo->KHR_textureTransform.texCoord; + } + } + + return ret; } static bool ParseNormalTextureInfo(NormalTextureInfo *texinfo, std::string *err, @@ -3054,7 +3199,18 @@ static bool ParseNormalTextureInfo(NormalTextureInfo *texinfo, std::string *err, ParseExtensionsProperty(&texinfo->extensions, err, o); ParseExtrasProperty(&texinfo->extras, o); - return true; + bool ret = true; + if (texinfo->extensions.count("KHR_texture_transform")) { + ret &= ParseKHRTextureTransform(&texinfo->KHR_textureTransform, err, + o["extensions"]["KHR_texture_transform"]); + if (texinfo->KHR_textureTransform.enabled && + texinfo->KHR_textureTransform.texCoord >= 0) { + // As described in the specification, overwrite texCoord. + texinfo->texCoord = texinfo->KHR_textureTransform.texCoord; + } + } + + return ret; } static bool ParseOcclusionTextureInfo(OcclusionTextureInfo *texinfo, @@ -3074,7 +3230,18 @@ static bool ParseOcclusionTextureInfo(OcclusionTextureInfo *texinfo, ParseExtensionsProperty(&texinfo->extensions, err, o); ParseExtrasProperty(&texinfo->extras, o); - return true; + bool ret = true; + if (texinfo->extensions.count("KHR_texture_transform")) { + ret &= ParseKHRTextureTransform(&texinfo->KHR_textureTransform, err, + o["extensions"]["KHR_texture_transform"]); + if (texinfo->KHR_textureTransform.enabled && + texinfo->KHR_textureTransform.texCoord >= 0) { + // As described in the specification, overwrite texCoord. + texinfo->texCoord = texinfo->KHR_textureTransform.texCoord; + } + } + + return ret; } static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o, @@ -3703,17 +3870,18 @@ static bool ParsePbrMetallicRoughness(PbrMetallicRoughness *pbr, } pbr->baseColorFactor = baseColorFactor; + bool ret = true; { json::const_iterator it = o.find("baseColorTexture"); if (it != o.end()) { - ParseTextureInfo(&pbr->baseColorTexture, err, it.value()); + ret &= ParseTextureInfo(&pbr->baseColorTexture, err, it.value()); } } { json::const_iterator it = o.find("metallicRoughnessTexture"); if (it != o.end()) { - ParseTextureInfo(&pbr->metallicRoughnessTexture, err, it.value()); + ret &= ParseTextureInfo(&pbr->metallicRoughnessTexture, err, it.value()); } } @@ -3726,7 +3894,78 @@ static bool ParsePbrMetallicRoughness(PbrMetallicRoughness *pbr, return true; } +static bool ParseKHRPbrSpecularGlossiness(KHRPbrSpecularGlossiness *pbr, + std::string *err, const json &o) { + if (pbr == nullptr) { + return false; + } + + std::vector diffuseFactor; + if (ParseNumberArrayProperty(&diffuseFactor, err, o, "diffuseFactor", + /* required */ false)) { + if (diffuseFactor.size() != 4) { + if (err) { + (*err) += + "Array length of `diffuseFactor` parameter in " + "KHR_materials_pbrMetallicRoughness must be 4, but got " + + std::to_string(diffuseFactor.size()) + "\n"; + } + return false; + } + } else { + // fill with default values + diffuseFactor = {1.0, 1.0, 1.0, 1.0}; + } + pbr->diffuseFactor = diffuseFactor; + + bool ret = true; + + { + json::const_iterator it = o.find("diffuseTexture"); + if (it != o.end()) { + ret &= ParseTextureInfo(&pbr->diffuseTexture, err, it.value()); + } + } + + { + json::const_iterator it = o.find("specularGlossinessTexture"); + if (it != o.end()) { + ret &= ParseTextureInfo(&pbr->specularGlossinessTexture, err, it.value()); + } + } + + std::vector specularFactor; + if (ParseNumberArrayProperty(&specularFactor, err, o, "specularFactor", + /* required */ false)) { + if (specularFactor.size() != 3) { + if (err) { + (*err) += + "Array length of `specularFactor` parameter in " + "KHR_materials_pbrMetallicRoughness must be 3, but got " + + std::to_string(diffuseFactor.size()) + "\n"; + } + return false; + } + } else { + // fill with default values + specularFactor = {1.0, 1.0, 1.0}; + } + pbr->specularFactor = specularFactor; + + ParseNumberProperty(&pbr->glossinessFactor, err, o, "glossinessFactor", + false); + + ParseExtensionsProperty(&pbr->extensions, err, o); + ParseExtrasProperty(&pbr->extras, o); + + pbr->enabled = true; + + return ret; +} + static bool ParseMaterial(Material *material, std::string *err, const json &o) { + bool ret = true; + ParseStringProperty(&material->name, err, o, "name", /* required */ false); ParseNumberArrayProperty(&material->emissiveFactor, err, o, "emissiveFactor", @@ -3742,29 +3981,30 @@ static bool ParseMaterial(Material *material, std::string *err, const json &o) { { json::const_iterator it = o.find("pbrMetallicRoughness"); if (it != o.end()) { - ParsePbrMetallicRoughness(&material->pbrMetallicRoughness, err, - it.value()); + ret &= ParsePbrMetallicRoughness(&material->pbrMetallicRoughness, err, + it.value()); } } { json::const_iterator it = o.find("normalTexture"); if (it != o.end()) { - ParseNormalTextureInfo(&material->normalTexture, err, it.value()); + ret &= ParseNormalTextureInfo(&material->normalTexture, err, it.value()); } } { json::const_iterator it = o.find("occlusionTexture"); if (it != o.end()) { - ParseOcclusionTextureInfo(&material->occlusionTexture, err, it.value()); + ret &= ParseOcclusionTextureInfo(&material->occlusionTexture, err, + it.value()); } } { json::const_iterator it = o.find("emissiveTexture"); if (it != o.end()) { - ParseTextureInfo(&material->emissiveTexture, err, it.value()); + ret &= ParseTextureInfo(&material->emissiveTexture, err, it.value()); } } @@ -3812,7 +4052,25 @@ static bool ParseMaterial(Material *material, std::string *err, const json &o) { ParseExtensionsProperty(&material->extensions, err, o); ParseExtrasProperty(&(material->extras), o); - return true; + // + // Materialize some KHR material extensions. + // KHR material extensions still exists in `exntensions` as Value(opaque) + // variable. + // + if (material->extensions.count("KHR_materials_unlit")) { + material->KHR_materials_unlit = true; + } + + const std::string kKHR_materials_pbrSpecularGlossiness = + "KHR_materials_pbrSpecularGlossiness"; + if (material->extensions.count(kKHR_materials_pbrSpecularGlossiness)) { + // Use JSON + ret &= ParseKHRPbrSpecularGlossiness( + &material->KHR_pbrSpecularGlossiness, err, + o["extensions"][kKHR_materials_pbrSpecularGlossiness]); + } + + return ret; } static bool ParseAnimationChannel(AnimationChannel *channel, std::string *err, @@ -5314,10 +5572,39 @@ static void SerializeGltfImage(Image &image, json &o) { SerializeExtensionMap(image.extensions, o); } +static void SerializeKHRTextureTransform(KHRTextureTransform &texform, + json &o) { + SerializeNumberProperty("rotation", texform.rotation, o); + + if (texform.texCoord >= 0) { + SerializeNumberProperty("texCoord", texform.texCoord, o); + } + + { + std::vector default_offset = {0.0, 0.0}; + if (!Equals(texform.offset, default_offset)) { + SerializeNumberArrayProperty("offset", texform.offset, o); + } + } + + { + std::vector default_scale = {1.0, 1.0}; + if (!Equals(texform.offset, default_scale)) { + SerializeNumberArrayProperty("scale", texform.scale, o); + } + } + + if (texform.extras.Type() != NULL_TYPE) { + SerializeValue("extras", texform.extras, o); + } + + SerializeExtensionMap(texform.extensions, o); +} + static void SerializeGltfTextureInfo(TextureInfo &texinfo, json &o) { SerializeNumberProperty("index", texinfo.index, o); - if (texinfo.texCoord != 0) { + if (texinfo.texCoord >= 0) { SerializeNumberProperty("texCoord", texinfo.texCoord, o); } @@ -5326,13 +5613,20 @@ static void SerializeGltfTextureInfo(TextureInfo &texinfo, json &o) { } SerializeExtensionMap(texinfo.extensions, o); + + // Overwite KHR_texture_transform + if (texinfo.KHR_textureTransform.enabled) { + json texform; + SerializeKHRTextureTransform(texinfo.KHR_textureTransform, texform); + o["extensions"]["KHR_texture_transform"] = texform; + } } static void SerializeGltfNormalTextureInfo(NormalTextureInfo &texinfo, json &o) { SerializeNumberProperty("index", texinfo.index, o); - if (texinfo.texCoord != 0) { + if (texinfo.texCoord >= 0) { SerializeNumberProperty("texCoord", texinfo.texCoord, o); } @@ -5345,13 +5639,20 @@ static void SerializeGltfNormalTextureInfo(NormalTextureInfo &texinfo, } SerializeExtensionMap(texinfo.extensions, o); + + // Overwite KHR_texture_transform + if (texinfo.KHR_textureTransform.enabled) { + json texform; + SerializeKHRTextureTransform(texinfo.KHR_textureTransform, texform); + o["extensions"]["KHR_texture_transform"] = texform; + } } static void SerializeGltfOcclusionTextureInfo(OcclusionTextureInfo &texinfo, json &o) { SerializeNumberProperty("index", texinfo.index, o); - if (texinfo.texCoord != 0) { + if (texinfo.texCoord >= 0) { SerializeNumberProperty("texCoord", texinfo.texCoord, o); } @@ -5364,6 +5665,13 @@ static void SerializeGltfOcclusionTextureInfo(OcclusionTextureInfo &texinfo, } SerializeExtensionMap(texinfo.extensions, o); + + // Overwite KHR_texture_transform + if (texinfo.KHR_textureTransform.enabled) { + json texform; + SerializeKHRTextureTransform(texinfo.KHR_textureTransform, texform); + o["extensions"]["KHR_texture_transform"] = texform; + } } static void SerializeGltfPbrMetallicRoughness(PbrMetallicRoughness &pbr, @@ -5401,6 +5709,41 @@ static void SerializeGltfPbrMetallicRoughness(PbrMetallicRoughness &pbr, } } +static void SerializeGltfKHRMaterialsPbrSpecularGlossiness( + KHRPbrSpecularGlossiness &pbr, json &o) { + std::vector default_diffuseFactor = {1.0, 1.0, 1.0, 1.0}; + if (!Equals(pbr.diffuseFactor, default_diffuseFactor)) { + SerializeNumberArrayProperty("diffuseFactor", pbr.diffuseFactor, o); + } + std::vector default_specularFactor = {1.0, 1.0, 1.0}; + if (!Equals(pbr.specularFactor, default_specularFactor)) { + SerializeNumberArrayProperty("specularFactor", pbr.specularFactor, + o); + } + + if (!TINYGLTF_DOUBLE_EQUAL(pbr.glossinessFactor, 1.0)) { + SerializeNumberProperty("glossinessFactor", pbr.glossinessFactor, o); + } + + if (pbr.diffuseTexture.index >= -1) { + json texinfo; + SerializeGltfTextureInfo(pbr.diffuseTexture, texinfo); + o["diffuseTexture"] = texinfo; + } + + if (pbr.specularGlossinessTexture.index >= -1) { + json texinfo; + SerializeGltfTextureInfo(pbr.specularGlossinessTexture, texinfo); + o["specularGlossinessTexture"] = texinfo; + } + + SerializeExtensionMap(pbr.extensions, o); + + if (pbr.extras.Type() != NULL_TYPE) { + SerializeValue("extras", pbr.extras, o); + } +} + static void SerializeGltfMaterial(Material &material, json &o) { if (material.name.size()) { SerializeStringProperty("name", material.name, o); @@ -5467,6 +5810,21 @@ static void SerializeGltfMaterial(Material &material, json &o) { SerializeExtensionMap(material.extensions, o); + // Overwrite KHR_materials_unlit + if (material.KHR_materials_unlit) { + o["extensions"]["KHR_materials_unlit"] = true; + } + + // Overwrite KHR_materials_pbrSpecularGlossiness + if (material.KHR_pbrSpecularGlossiness.enabled) { + json pbr; + + SerializeGltfKHRMaterialsPbrSpecularGlossiness( + material.KHR_pbrSpecularGlossiness, pbr); + + o["extensions"]["KHR_materials_pbrSpecularGlossiness"] = pbr; + } + if (material.extras.Type() != NULL_TYPE) { SerializeValue("extras", material.extras, o); }