From 63b0a97369fe6414dd76eadf8d12a7bf6cb61e67 Mon Sep 17 00:00:00 2001 From: Danny Kabrane Date: Sun, 20 Dec 2020 07:59:12 +0100 Subject: [PATCH 1/8] import KHR_materials_sheen --- code/AssetLib/glTF2/glTF2Asset.h | 16 ++++++++++++++++ code/AssetLib/glTF2/glTF2Asset.inl | 20 ++++++++++++++++++++ code/AssetLib/glTF2/glTF2Importer.cpp | 10 ++++++++++ include/assimp/pbrmaterial.h | 5 +++++ 4 files changed, 51 insertions(+) diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index be149f86e..c67f6b6bb 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * KHR_materials_pbrSpecularGlossiness full * KHR_materials_unlit full * KHR_lights_punctual full + * KHR_materials_sheen full */ #ifndef GLTF2ASSET_H_INC #define GLTF2ASSET_H_INC @@ -677,6 +678,7 @@ const vec4 defaultBaseColor = { 1, 1, 1, 1 }; const vec3 defaultEmissiveFactor = { 0, 0, 0 }; const vec4 defaultDiffuseFactor = { 1, 1, 1, 1 }; const vec3 defaultSpecularFactor = { 1, 1, 1 }; +const vec3 defaultSheenFactor = { 0, 0, 0 }; struct TextureInfo { Ref texture; @@ -718,6 +720,16 @@ struct PbrSpecularGlossiness { void SetDefaults(); }; +struct MaterialSheen { + vec3 sheenColorFactor; + float sheenRoughnessFactor; + TextureInfo sheenColorTexture; + TextureInfo sheenRoughnessTexture; + + MaterialSheen() { SetDefaults(); } + void SetDefaults(); +}; + //! The material appearance of a primitive. struct Material : public Object { //PBR metallic roughness properties @@ -735,6 +747,9 @@ struct Material : public Object { //extension: KHR_materials_pbrSpecularGlossiness Nullable pbrSpecularGlossiness; + //extension: KHR_materials_sheen + Nullable materialSheen; + //extension: KHR_materials_unlit bool unlit; @@ -1053,6 +1068,7 @@ public: bool KHR_materials_unlit; bool KHR_lights_punctual; bool KHR_texture_transform; + bool KHR_materials_sheen; } extensionsUsed; //! Keeps info about the required extensions diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index 8fc8bf24e..ecc2fd407 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -1042,6 +1042,19 @@ inline void Material::Read(Value &material, Asset &r) { if (r.extensionsUsed.KHR_texture_transform) { } + if (r.extensionsUsed.KHR_materials_sheen) { + if (Value *curMaterialSheen = FindObject(*extensions, "KHR_materials_sheen")) { + MaterialSheen sheen; + + ReadMember(*curMaterialSheen, "sheenColorFactor", sheen.sheenColorFactor); + ReadTextureProperty(r, *curMaterialSheen, "sheenColorTexture", sheen.sheenColorTexture); + ReadMember(*curMaterialSheen, "sheenRoughnessFactor", sheen.sheenRoughnessFactor); + ReadTextureProperty(r, *curMaterialSheen, "sheenRoughnessTexture", sheen.sheenRoughnessTexture); + + this->materialSheen = Nullable(sheen); + } + } + unlit = nullptr != FindObject(*extensions, "KHR_materials_unlit"); } } @@ -1081,6 +1094,12 @@ inline void PbrSpecularGlossiness::SetDefaults() { glossinessFactor = 1.0; } +inline void MaterialSheen::SetDefaults() { + //KHR_materials_sheen properties + SetVector(sheenColorFactor, defaultSheenFactor); + sheenRoughnessFactor = 0.f; +} + namespace { template @@ -1731,6 +1750,7 @@ inline void Asset::ReadExtensionsUsed(Document &doc) { CHECK_EXT(KHR_materials_unlit); CHECK_EXT(KHR_lights_punctual); CHECK_EXT(KHR_texture_transform); + CHECK_EXT(KHR_materials_sheen); #undef CHECK_EXT } diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index 672bac52d..08cf5050b 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -280,6 +280,16 @@ static aiMaterial *ImportMaterial(std::vector &embeddedTexIdxs, Asset &r, M if (mat.unlit) { aimat->AddProperty(&mat.unlit, 1, AI_MATKEY_GLTF_UNLIT); } + //KHR_materials_sheen + if (mat.materialSheen.isPresent) { + MaterialSheen &sheen = mat.materialSheen.value; + + aimat->AddProperty(&mat.materialSheen.isPresent, 1, AI_MATKEY_GLTF_MATERIALSHEEN); + SetMaterialColorProperty(r, sheen.sheenColorFactor, aimat, AI_MATKEY_GLTF_MATERIALSHEEN_COLOR_FACTOR); + aimat->AddProperty(&sheen.sheenRoughnessFactor, 1, AI_MATKEY_GLTF_MATERIALSHEEN_ROUGHNESS_FACTOR); + SetMaterialTextureProperty(embeddedTexIdxs, r, sheen.sheenColorTexture, aimat, AI_MATKEY_GLTF_MATERIALSHEEN_COLOR_TEXTURE); + SetMaterialTextureProperty(embeddedTexIdxs, r, sheen.sheenRoughnessTexture, aimat, AI_MATKEY_GLTF_MATERIALSHEEN_ROUGHNESS_TEXTURE); + } return aimat; } diff --git a/include/assimp/pbrmaterial.h b/include/assimp/pbrmaterial.h index cac4ab56b..3eaa1b09c 100644 --- a/include/assimp/pbrmaterial.h +++ b/include/assimp/pbrmaterial.h @@ -60,6 +60,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS "$mat.gltf.pbrSpecularGlossiness", 0, 0 #define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR "$mat.gltf.pbrMetallicRoughness.glossinessFactor", 0, 0 #define AI_MATKEY_GLTF_UNLIT "$mat.gltf.unlit", 0, 0 +#define AI_MATKEY_GLTF_MATERIALSHEEN "$mat.gltf.materialSheen", 0, 0 +#define AI_MATKEY_GLTF_MATERIALSHEEN_COLOR_FACTOR "$mat.gltf.materialSheen.sheenColorFactor", 0, 0 +#define AI_MATKEY_GLTF_MATERIALSHEEN_ROUGHNESS_FACTOR "$mat.gltf.materialSheen.sheenRoughnessFactor", 0, 0 +#define AI_MATKEY_GLTF_MATERIALSHEEN_COLOR_TEXTURE aiTextureType_UNKNOWN, 1 +#define AI_MATKEY_GLTF_MATERIALSHEEN_ROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 2 #define _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE "$tex.file.texCoord" #define _AI_MATKEY_GLTF_MAPPINGNAME_BASE "$tex.mappingname" From 0fdda99ea14b199dda42c3b5780aa37e30ecc123 Mon Sep 17 00:00:00 2001 From: Danny Kabrane Date: Mon, 21 Dec 2020 14:33:35 +0100 Subject: [PATCH 2/8] add underscore (MATERIAL_SHEEN instead of MATERIALSHEEN) --- code/AssetLib/glTF2/glTF2Importer.cpp | 10 +++++----- include/assimp/pbrmaterial.h | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index 08cf5050b..6dc6a072d 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -284,11 +284,11 @@ static aiMaterial *ImportMaterial(std::vector &embeddedTexIdxs, Asset &r, M if (mat.materialSheen.isPresent) { MaterialSheen &sheen = mat.materialSheen.value; - aimat->AddProperty(&mat.materialSheen.isPresent, 1, AI_MATKEY_GLTF_MATERIALSHEEN); - SetMaterialColorProperty(r, sheen.sheenColorFactor, aimat, AI_MATKEY_GLTF_MATERIALSHEEN_COLOR_FACTOR); - aimat->AddProperty(&sheen.sheenRoughnessFactor, 1, AI_MATKEY_GLTF_MATERIALSHEEN_ROUGHNESS_FACTOR); - SetMaterialTextureProperty(embeddedTexIdxs, r, sheen.sheenColorTexture, aimat, AI_MATKEY_GLTF_MATERIALSHEEN_COLOR_TEXTURE); - SetMaterialTextureProperty(embeddedTexIdxs, r, sheen.sheenRoughnessTexture, aimat, AI_MATKEY_GLTF_MATERIALSHEEN_ROUGHNESS_TEXTURE); + aimat->AddProperty(&mat.materialSheen.isPresent, 1, AI_MATKEY_GLTF_MATERIAL_SHEEN); + SetMaterialColorProperty(r, sheen.sheenColorFactor, aimat, AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_FACTOR); + aimat->AddProperty(&sheen.sheenRoughnessFactor, 1, AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_FACTOR); + SetMaterialTextureProperty(embeddedTexIdxs, r, sheen.sheenColorTexture, aimat, AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_TEXTURE); + SetMaterialTextureProperty(embeddedTexIdxs, r, sheen.sheenRoughnessTexture, aimat, AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_TEXTURE); } return aimat; diff --git a/include/assimp/pbrmaterial.h b/include/assimp/pbrmaterial.h index 3eaa1b09c..7f8441572 100644 --- a/include/assimp/pbrmaterial.h +++ b/include/assimp/pbrmaterial.h @@ -60,11 +60,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS "$mat.gltf.pbrSpecularGlossiness", 0, 0 #define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR "$mat.gltf.pbrMetallicRoughness.glossinessFactor", 0, 0 #define AI_MATKEY_GLTF_UNLIT "$mat.gltf.unlit", 0, 0 -#define AI_MATKEY_GLTF_MATERIALSHEEN "$mat.gltf.materialSheen", 0, 0 -#define AI_MATKEY_GLTF_MATERIALSHEEN_COLOR_FACTOR "$mat.gltf.materialSheen.sheenColorFactor", 0, 0 -#define AI_MATKEY_GLTF_MATERIALSHEEN_ROUGHNESS_FACTOR "$mat.gltf.materialSheen.sheenRoughnessFactor", 0, 0 -#define AI_MATKEY_GLTF_MATERIALSHEEN_COLOR_TEXTURE aiTextureType_UNKNOWN, 1 -#define AI_MATKEY_GLTF_MATERIALSHEEN_ROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 2 +#define AI_MATKEY_GLTF_MATERIAL_SHEEN "$mat.gltf.materialSheen", 0, 0 +#define AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_FACTOR "$mat.gltf.materialSheen.sheenColorFactor", 0, 0 +#define AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_FACTOR "$mat.gltf.materialSheen.sheenRoughnessFactor", 0, 0 +#define AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_TEXTURE aiTextureType_UNKNOWN, 1 +#define AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 2 #define _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE "$tex.file.texCoord" #define _AI_MATKEY_GLTF_MAPPINGNAME_BASE "$tex.mappingname" From aa9d6ce7b7474675e269d80bcd6bffd6d404d6fe Mon Sep 17 00:00:00 2001 From: Danny Kabrane Date: Mon, 21 Dec 2020 14:34:16 +0100 Subject: [PATCH 3/8] add support for khr_materials_sheen during export --- code/AssetLib/glTF2/glTF2AssetWriter.h | 1 + code/AssetLib/glTF2/glTF2AssetWriter.inl | 23 +++++++++++++++++++++++ code/AssetLib/glTF2/glTF2Exporter.cpp | 16 ++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.h b/code/AssetLib/glTF2/glTF2AssetWriter.h index ce58717f3..355fdfeed 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.h +++ b/code/AssetLib/glTF2/glTF2AssetWriter.h @@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * glTF Extensions Support: * KHR_materials_pbrSpecularGlossiness: full * KHR_materials_unlit: full + * KHR_materials_sheen: full */ #ifndef GLTF2ASSETWRITER_H_INC #define GLTF2ASSETWRITER_H_INC diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.inl b/code/AssetLib/glTF2/glTF2AssetWriter.inl index 786a1e7b8..3d1e6d263 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.inl +++ b/code/AssetLib/glTF2/glTF2AssetWriter.inl @@ -417,6 +417,25 @@ namespace glTF2 { exts.AddMember("KHR_materials_unlit", unlit, w.mAl); } + if (m.materialSheen.isPresent) { + Value materialSheen(rapidjson::Type::kObjectType); + + MaterialSheen &sheen = m.materialSheen.value; + + WriteVec(materialSheen, sheen.sheenColorFactor, "sheenColorFactor", defaultSheenFactor, w.mAl); + + if (sheen.sheenRoughnessFactor != 0.f) { + WriteFloat(materialSheen, sheen.sheenRoughnessFactor, "sheenRoughnessFactor", w.mAl); + } + + WriteTex(materialSheen, sheen.sheenColorTexture, "sheenColorTexture", w.mAl); + WriteTex(materialSheen, sheen.sheenRoughnessTexture, "sheenRoughnessTexture", w.mAl); + + if (!materialSheen.ObjectEmpty()) { + exts.AddMember("KHR_materials_sheen", materialSheen, w.mAl); + } + } + if (!exts.ObjectEmpty()) { obj.AddMember("extensions", exts, w.mAl); } @@ -808,6 +827,10 @@ namespace glTF2 { if (this->mAsset.extensionsUsed.KHR_materials_unlit) { exts.PushBack(StringRef("KHR_materials_unlit"), mAl); } + + if (this->mAsset.extensionsUsed.KHR_materials_sheen) { + exts.PushBack(StringRef("KHR_materials_sheen"), mAl); + } } if (!exts.Empty()) diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index 637808877..65309a66a 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -714,6 +714,22 @@ void glTF2Exporter::ExportMaterials() mAsset->extensionsUsed.KHR_materials_unlit = true; m->unlit = true; } + + bool hasMaterialSheen = false; + mat->Get(AI_MATKEY_GLTF_MATERIAL_SHEEN, hasMaterialSheen); + + if (hasMaterialSheen) { + mAsset->extensionsUsed.KHR_materials_sheen = true; + + MaterialSheen sheen; + + GetMatColor(mat, sheen.sheenColorFactor, AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_FACTOR); + mat->Get(AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_FACTOR, sheen.sheenRoughnessFactor); + GetMatTex(mat, sheen.sheenColorTexture, AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_TEXTURE); + GetMatTex(mat, sheen.sheenRoughnessTexture, AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_TEXTURE); + + m->materialSheen = Nullable(sheen); + } } } From f8c63d874b99751280553e1b36523e55d3370622 Mon Sep 17 00:00:00 2001 From: Danny Kabrane Date: Wed, 23 Dec 2020 08:12:09 +0100 Subject: [PATCH 4/8] support KHR_materials_clearcoat during import --- code/AssetLib/glTF2/glTF2Asset.h | 13 +++++++++++++ code/AssetLib/glTF2/glTF2Asset.inl | 15 +++++++++++++++ code/AssetLib/glTF2/glTF2Importer.cpp | 11 +++++++++++ include/assimp/pbrmaterial.h | 6 ++++++ 4 files changed, 45 insertions(+) diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index c67f6b6bb..3d439d622 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * KHR_materials_unlit full * KHR_lights_punctual full * KHR_materials_sheen full + * KHR_materials_clearcoat full */ #ifndef GLTF2ASSET_H_INC #define GLTF2ASSET_H_INC @@ -730,6 +731,14 @@ struct MaterialSheen { void SetDefaults(); }; +struct MaterialClearcoat { + float clearcoatFactor = 0.f; + float clearcoatRoughnessFactor = 0.f; + TextureInfo clearcoatTexture; + TextureInfo clearcoatRoughnessTexture; + NormalTextureInfo clearcoatNormalTexture; +}; + //! The material appearance of a primitive. struct Material : public Object { //PBR metallic roughness properties @@ -750,6 +759,9 @@ struct Material : public Object { //extension: KHR_materials_sheen Nullable materialSheen; + //extension: KHR_materials_clearcoat + Nullable materialClearcoat; + //extension: KHR_materials_unlit bool unlit; @@ -1069,6 +1081,7 @@ public: bool KHR_lights_punctual; bool KHR_texture_transform; bool KHR_materials_sheen; + bool KHR_materials_clearcoat; } extensionsUsed; //! Keeps info about the required extensions diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index ecc2fd407..8a5a697fa 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -1055,6 +1055,20 @@ inline void Material::Read(Value &material, Asset &r) { } } + if (r.extensionsUsed.KHR_materials_clearcoat) { + if (Value *curMaterialClearcoat = FindObject(*extensions, "KHR_materials_clearcoat")) { + MaterialClearcoat clearcoat; + + ReadMember(*curMaterialClearcoat, "clearcoatFactor", clearcoat.clearcoatFactor); + ReadTextureProperty(r, *curMaterialClearcoat, "clearcoatTexture", clearcoat.clearcoatTexture); + ReadMember(*curMaterialClearcoat, "clearcoatRoughnessFactor", clearcoat.clearcoatRoughnessFactor); + ReadTextureProperty(r, *curMaterialClearcoat, "clearcoatRoughnessTexture", clearcoat.clearcoatRoughnessTexture); + ReadTextureProperty(r, *curMaterialClearcoat, "clearcoatNormalTexture", clearcoat.clearcoatNormalTexture); + + this->materialClearcoat = Nullable(clearcoat); + } + } + unlit = nullptr != FindObject(*extensions, "KHR_materials_unlit"); } } @@ -1751,6 +1765,7 @@ inline void Asset::ReadExtensionsUsed(Document &doc) { CHECK_EXT(KHR_lights_punctual); CHECK_EXT(KHR_texture_transform); CHECK_EXT(KHR_materials_sheen); + CHECK_EXT(KHR_materials_clearcoat); #undef CHECK_EXT } diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index 6dc6a072d..180cedfab 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -290,6 +290,17 @@ static aiMaterial *ImportMaterial(std::vector &embeddedTexIdxs, Asset &r, M SetMaterialTextureProperty(embeddedTexIdxs, r, sheen.sheenColorTexture, aimat, AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_TEXTURE); SetMaterialTextureProperty(embeddedTexIdxs, r, sheen.sheenRoughnessTexture, aimat, AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_TEXTURE); } + //KHR_materials_clearcoat + if (mat.materialClearcoat.isPresent) { + MaterialClearcoat &clearcoat = mat.materialClearcoat.value; + + aimat->AddProperty(&mat.materialClearcoat.isPresent, 1, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT); + aimat->AddProperty(&clearcoat.clearcoatFactor, 1, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_FACTOR); + aimat->AddProperty(&clearcoat.clearcoatRoughnessFactor, 1, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_FACTOR); + SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatTexture, aimat, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_TEXTURE); + SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatRoughnessTexture, aimat, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_TEXTURE); + SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatNormalTexture, aimat, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_NORMAL_TEXTURE); + } return aimat; } diff --git a/include/assimp/pbrmaterial.h b/include/assimp/pbrmaterial.h index 7f8441572..d6ba34aef 100644 --- a/include/assimp/pbrmaterial.h +++ b/include/assimp/pbrmaterial.h @@ -65,6 +65,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_FACTOR "$mat.gltf.materialSheen.sheenRoughnessFactor", 0, 0 #define AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_TEXTURE aiTextureType_UNKNOWN, 1 #define AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 2 +#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT "$mat.gltf.materialClearcoat", 0, 0 +#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_FACTOR "$mat.gltf.materialClearcoat.clearcoatFactor", 0, 0 +#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_FACTOR "$mat.gltf.materialClearcoat.clearcoatRoughnessFactor", 0, 0 +#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_TEXTURE aiTextureType_UNKNOWN, 3 +#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 4 +#define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_NORMAL_TEXTURE aiTextureType_NORMALS, 1 #define _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE "$tex.file.texCoord" #define _AI_MATKEY_GLTF_MAPPINGNAME_BASE "$tex.mappingname" From 197bf1e61788063c9d1457d8b5e82cf94a130415 Mon Sep 17 00:00:00 2001 From: Danny Kabrane Date: Wed, 23 Dec 2020 09:56:15 +0100 Subject: [PATCH 5/8] Add KHR_materials_clearcoat during export --- code/AssetLib/glTF2/glTF2AssetWriter.h | 1 + code/AssetLib/glTF2/glTF2AssetWriter.inl | 26 ++++++++++++++++++++++++ code/AssetLib/glTF2/glTF2Exporter.cpp | 17 ++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.h b/code/AssetLib/glTF2/glTF2AssetWriter.h index 355fdfeed..a31d79312 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.h +++ b/code/AssetLib/glTF2/glTF2AssetWriter.h @@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * KHR_materials_pbrSpecularGlossiness: full * KHR_materials_unlit: full * KHR_materials_sheen: full + * KHR_materials_clearcoat: full */ #ifndef GLTF2ASSETWRITER_H_INC #define GLTF2ASSETWRITER_H_INC diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.inl b/code/AssetLib/glTF2/glTF2AssetWriter.inl index 3d1e6d263..81ce1fd6e 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.inl +++ b/code/AssetLib/glTF2/glTF2AssetWriter.inl @@ -436,6 +436,28 @@ namespace glTF2 { } } + if (m.materialClearcoat.isPresent) { + Value materialClearcoat(rapidjson::Type::kObjectType); + + MaterialClearcoat &clearcoat = m.materialClearcoat.value; + + if (clearcoat.clearcoatFactor != 0.f) { + WriteFloat(materialClearcoat, clearcoat.clearcoatFactor, "clearcoatFactor", w.mAl); + } + + if (clearcoat.clearcoatRoughnessFactor != 0.f) { + WriteFloat(materialClearcoat, clearcoat.clearcoatRoughnessFactor, "clearcoatRoughnessFactor", w.mAl); + } + + WriteTex(materialClearcoat, clearcoat.clearcoatTexture, "clearcoatTexture", w.mAl); + WriteTex(materialClearcoat, clearcoat.clearcoatRoughnessTexture, "clearcoatRoughnessTexture", w.mAl); + WriteTex(materialClearcoat, clearcoat.clearcoatNormalTexture, "clearcoatNormalTexture", w.mAl); + + if (!materialClearcoat.ObjectEmpty()) { + exts.AddMember("KHR_materials_clearcoat", materialClearcoat, w.mAl); + } + } + if (!exts.ObjectEmpty()) { obj.AddMember("extensions", exts, w.mAl); } @@ -831,6 +853,10 @@ namespace glTF2 { if (this->mAsset.extensionsUsed.KHR_materials_sheen) { exts.PushBack(StringRef("KHR_materials_sheen"), mAl); } + + if (this->mAsset.extensionsUsed.KHR_materials_clearcoat) { + exts.PushBack(StringRef("KHR_materials_clearcoat"), mAl); + } } if (!exts.Empty()) diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index 65309a66a..ba60be919 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -730,6 +730,23 @@ void glTF2Exporter::ExportMaterials() m->materialSheen = Nullable(sheen); } + + bool hasMaterialClearcoat = false; + mat->Get(AI_MATKEY_GLTF_MATERIAL_CLEARCOAT, hasMaterialClearcoat); + + if (hasMaterialClearcoat) { + mAsset->extensionsUsed.KHR_materials_clearcoat= true; + + MaterialClearcoat clearcoat; + + mat->Get(AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_FACTOR, clearcoat.clearcoatFactor); + mat->Get(AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_FACTOR, clearcoat.clearcoatRoughnessFactor); + GetMatTex(mat, clearcoat.clearcoatTexture, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_TEXTURE); + GetMatTex(mat, clearcoat.clearcoatRoughnessTexture, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_TEXTURE); + GetMatTex(mat, clearcoat.clearcoatNormalTexture, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_NORMAL_TEXTURE); + + m->materialClearcoat = Nullable(clearcoat); + } } } From 2b097c1e73e9ab1cb94c5b0079783d7892a93d00 Mon Sep 17 00:00:00 2001 From: Danny Kabrane Date: Wed, 23 Dec 2020 10:43:01 +0100 Subject: [PATCH 6/8] Add KHR_materials_transmission during import --- code/AssetLib/glTF2/glTF2Asset.h | 10 ++++++++++ code/AssetLib/glTF2/glTF2Asset.inl | 12 ++++++++++++ code/AssetLib/glTF2/glTF2Importer.cpp | 8 ++++++++ include/assimp/pbrmaterial.h | 3 +++ 4 files changed, 33 insertions(+) diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index 3d439d622..94cbef2cd 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -48,6 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * KHR_lights_punctual full * KHR_materials_sheen full * KHR_materials_clearcoat full + * KHR_materials_transmission full */ #ifndef GLTF2ASSET_H_INC #define GLTF2ASSET_H_INC @@ -739,6 +740,11 @@ struct MaterialClearcoat { NormalTextureInfo clearcoatNormalTexture; }; +struct MaterialTransmission { + TextureInfo transmissionTexture; + float transmissionFactor = 0.f; +}; + //! The material appearance of a primitive. struct Material : public Object { //PBR metallic roughness properties @@ -762,6 +768,9 @@ struct Material : public Object { //extension: KHR_materials_clearcoat Nullable materialClearcoat; + //extension: KHR_materials_transmission + Nullable materialTransmission; + //extension: KHR_materials_unlit bool unlit; @@ -1082,6 +1091,7 @@ public: bool KHR_texture_transform; bool KHR_materials_sheen; bool KHR_materials_clearcoat; + bool KHR_materials_transmission; } extensionsUsed; //! Keeps info about the required extensions diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index 8a5a697fa..20367c092 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -1069,6 +1069,17 @@ inline void Material::Read(Value &material, Asset &r) { } } + if (r.extensionsUsed.KHR_materials_transmission) { + if (Value *curMaterialTransmission = FindObject(*extensions, "KHR_materials_transmission")) { + MaterialTransmission transmission; + + ReadMember(*curMaterialTransmission, "transmissionFactor", transmission.transmissionFactor); + ReadTextureProperty(r, *curMaterialTransmission, "transmissionTexture", transmission.transmissionTexture); + + this->materialTransmission = Nullable(transmission); + } + } + unlit = nullptr != FindObject(*extensions, "KHR_materials_unlit"); } } @@ -1766,6 +1777,7 @@ inline void Asset::ReadExtensionsUsed(Document &doc) { CHECK_EXT(KHR_texture_transform); CHECK_EXT(KHR_materials_sheen); CHECK_EXT(KHR_materials_clearcoat); + CHECK_EXT(KHR_materials_transmission); #undef CHECK_EXT } diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index 180cedfab..57fcc953b 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -301,6 +301,14 @@ static aiMaterial *ImportMaterial(std::vector &embeddedTexIdxs, Asset &r, M SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatRoughnessTexture, aimat, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_TEXTURE); SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatNormalTexture, aimat, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_NORMAL_TEXTURE); } + //KHR_materials_transmission + if (mat.materialTransmission.isPresent) { + MaterialTransmission &transmission = mat.materialTransmission.value; + + aimat->AddProperty(&mat.materialTransmission.isPresent, 1, AI_MATKEY_GLTF_MATERIAL_TRANSMISSION); + aimat->AddProperty(&transmission.transmissionFactor, 1, AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_FACTOR); + SetMaterialTextureProperty(embeddedTexIdxs, r, transmission.transmissionTexture, aimat, AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_TEXTURE); + } return aimat; } diff --git a/include/assimp/pbrmaterial.h b/include/assimp/pbrmaterial.h index d6ba34aef..645986d95 100644 --- a/include/assimp/pbrmaterial.h +++ b/include/assimp/pbrmaterial.h @@ -71,6 +71,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_TEXTURE aiTextureType_UNKNOWN, 3 #define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 4 #define AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_NORMAL_TEXTURE aiTextureType_NORMALS, 1 +#define AI_MATKEY_GLTF_MATERIAL_TRANSMISSION "$mat.gltf.materialTransmission", 0, 0 +#define AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_FACTOR "$mat.gltf.materialTransmission.transmissionFactor", 0, 0 +#define AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_TEXTURE aiTextureType_UNKNOWN, 5 #define _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE "$tex.file.texCoord" #define _AI_MATKEY_GLTF_MAPPINGNAME_BASE "$tex.mappingname" From 383c97e380517303ef4755a8ba6039e4dbabe0fd Mon Sep 17 00:00:00 2001 From: Danny Kabrane Date: Wed, 23 Dec 2020 10:43:21 +0100 Subject: [PATCH 7/8] Add KHR_materials_transmission during export --- code/AssetLib/glTF2/glTF2AssetWriter.h | 1 + code/AssetLib/glTF2/glTF2AssetWriter.inl | 20 ++++++++++++++++++++ code/AssetLib/glTF2/glTF2Exporter.cpp | 14 ++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.h b/code/AssetLib/glTF2/glTF2AssetWriter.h index a31d79312..bf4f80dbe 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.h +++ b/code/AssetLib/glTF2/glTF2AssetWriter.h @@ -48,6 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * KHR_materials_unlit: full * KHR_materials_sheen: full * KHR_materials_clearcoat: full + * KHR_materials_transmission: full */ #ifndef GLTF2ASSETWRITER_H_INC #define GLTF2ASSETWRITER_H_INC diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.inl b/code/AssetLib/glTF2/glTF2AssetWriter.inl index 81ce1fd6e..65fddaec5 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.inl +++ b/code/AssetLib/glTF2/glTF2AssetWriter.inl @@ -458,6 +458,22 @@ namespace glTF2 { } } + if (m.materialTransmission.isPresent) { + Value materialTransmission(rapidjson::Type::kObjectType); + + MaterialTransmission &transmission = m.materialTransmission.value; + + if (transmission.transmissionFactor != 0.f) { + WriteFloat(materialTransmission, transmission.transmissionFactor, "transmissionFactor", w.mAl); + } + + WriteTex(materialTransmission, transmission.transmissionTexture, "transmissionTexture", w.mAl); + + if (!materialTransmission.ObjectEmpty()) { + exts.AddMember("KHR_materials_transmission", materialTransmission, w.mAl); + } + } + if (!exts.ObjectEmpty()) { obj.AddMember("extensions", exts, w.mAl); } @@ -857,6 +873,10 @@ namespace glTF2 { if (this->mAsset.extensionsUsed.KHR_materials_clearcoat) { exts.PushBack(StringRef("KHR_materials_clearcoat"), mAl); } + + if (this->mAsset.extensionsUsed.KHR_materials_transmission) { + exts.PushBack(StringRef("KHR_materials_transmission"), mAl); + } } if (!exts.Empty()) diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index ba60be919..596ea6d28 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -747,6 +747,20 @@ void glTF2Exporter::ExportMaterials() m->materialClearcoat = Nullable(clearcoat); } + + bool hasMaterialTransmission = false; + mat->Get(AI_MATKEY_GLTF_MATERIAL_TRANSMISSION, hasMaterialTransmission); + + if (hasMaterialTransmission) { + mAsset->extensionsUsed.KHR_materials_transmission = true; + + MaterialTransmission transmission; + + mat->Get(AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_FACTOR, transmission.transmissionFactor); + GetMatTex(mat, transmission.transmissionTexture, AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_TEXTURE); + + m->materialTransmission = Nullable(transmission); + } } } From 07b59f539d1e13db57740a4911a0bd0a2f9d6b52 Mon Sep 17 00:00:00 2001 From: Danny-Kint Date: Mon, 28 Dec 2020 08:48:54 +0100 Subject: [PATCH 8/8] Merge branch 'master' into dev/gltf-KHR_materials --- code/AssetLib/glTF2/glTF2Importer.cpp | 613 ++++++++++++++------------ 1 file changed, 326 insertions(+), 287 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index 57fcc953b..ac3b7144e 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -229,88 +229,96 @@ inline void SetMaterialTextureProperty(std::vector &embeddedTexIdxs, Asset static aiMaterial *ImportMaterial(std::vector &embeddedTexIdxs, Asset &r, Material &mat) { aiMaterial *aimat = new aiMaterial(); - if (!mat.name.empty()) { - aiString str(mat.name); + try { + if (!mat.name.empty()) { + aiString str(mat.name); - aimat->AddProperty(&str, AI_MATKEY_NAME); + aimat->AddProperty(&str, AI_MATKEY_NAME); + } + + SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_COLOR_DIFFUSE); + SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR); + + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, aiTextureType_DIFFUSE); + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE); + + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.metallicRoughnessTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE); + + aimat->AddProperty(&mat.pbrMetallicRoughness.metallicFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR); + aimat->AddProperty(&mat.pbrMetallicRoughness.roughnessFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR); + + float roughnessAsShininess = 1 - mat.pbrMetallicRoughness.roughnessFactor; + roughnessAsShininess *= roughnessAsShininess * 1000; + aimat->AddProperty(&roughnessAsShininess, 1, AI_MATKEY_SHININESS); + + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.normalTexture, aimat, aiTextureType_NORMALS); + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.occlusionTexture, aimat, aiTextureType_LIGHTMAP); + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.emissiveTexture, aimat, aiTextureType_EMISSIVE); + SetMaterialColorProperty(r, mat.emissiveFactor, aimat, AI_MATKEY_COLOR_EMISSIVE); + + aimat->AddProperty(&mat.doubleSided, 1, AI_MATKEY_TWOSIDED); + + aiString alphaMode(mat.alphaMode); + aimat->AddProperty(&alphaMode, AI_MATKEY_GLTF_ALPHAMODE); + aimat->AddProperty(&mat.alphaCutoff, 1, AI_MATKEY_GLTF_ALPHACUTOFF); + + //pbrSpecularGlossiness + if (mat.pbrSpecularGlossiness.isPresent) { + PbrSpecularGlossiness &pbrSG = mat.pbrSpecularGlossiness.value; + + aimat->AddProperty(&mat.pbrSpecularGlossiness.isPresent, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS); + SetMaterialColorProperty(r, pbrSG.diffuseFactor, aimat, AI_MATKEY_COLOR_DIFFUSE); + SetMaterialColorProperty(r, pbrSG.specularFactor, aimat, AI_MATKEY_COLOR_SPECULAR); + + float glossinessAsShininess = pbrSG.glossinessFactor * 1000.0f; + aimat->AddProperty(&glossinessAsShininess, 1, AI_MATKEY_SHININESS); + aimat->AddProperty(&pbrSG.glossinessFactor, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR); + + SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.diffuseTexture, aimat, aiTextureType_DIFFUSE); + + SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.specularGlossinessTexture, aimat, aiTextureType_SPECULAR); + } + if (mat.unlit) { + aimat->AddProperty(&mat.unlit, 1, AI_MATKEY_GLTF_UNLIT); + } + + //KHR_materials_sheen + if (mat.materialSheen.isPresent) { + MaterialSheen &sheen = mat.materialSheen.value; + + aimat->AddProperty(&mat.materialSheen.isPresent, 1, AI_MATKEY_GLTF_MATERIAL_SHEEN); + SetMaterialColorProperty(r, sheen.sheenColorFactor, aimat, AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_FACTOR); + aimat->AddProperty(&sheen.sheenRoughnessFactor, 1, AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_FACTOR); + SetMaterialTextureProperty(embeddedTexIdxs, r, sheen.sheenColorTexture, aimat, AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_TEXTURE); + SetMaterialTextureProperty(embeddedTexIdxs, r, sheen.sheenRoughnessTexture, aimat, AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_TEXTURE); + } + + //KHR_materials_clearcoat + if (mat.materialClearcoat.isPresent) { + MaterialClearcoat &clearcoat = mat.materialClearcoat.value; + + aimat->AddProperty(&mat.materialClearcoat.isPresent, 1, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT); + aimat->AddProperty(&clearcoat.clearcoatFactor, 1, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_FACTOR); + aimat->AddProperty(&clearcoat.clearcoatRoughnessFactor, 1, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_FACTOR); + SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatTexture, aimat, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_TEXTURE); + SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatRoughnessTexture, aimat, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_TEXTURE); + SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatNormalTexture, aimat, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_NORMAL_TEXTURE); + } + + //KHR_materials_transmission + if (mat.materialTransmission.isPresent) { + MaterialTransmission &transmission = mat.materialTransmission.value; + + aimat->AddProperty(&mat.materialTransmission.isPresent, 1, AI_MATKEY_GLTF_MATERIAL_TRANSMISSION); + aimat->AddProperty(&transmission.transmissionFactor, 1, AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_FACTOR); + SetMaterialTextureProperty(embeddedTexIdxs, r, transmission.transmissionTexture, aimat, AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_TEXTURE); + } + + return aimat; + } catch (...) { + delete aimat; + throw; } - - SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_COLOR_DIFFUSE); - SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR); - - SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, aiTextureType_DIFFUSE); - SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE); - - SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.metallicRoughnessTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE); - - aimat->AddProperty(&mat.pbrMetallicRoughness.metallicFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR); - aimat->AddProperty(&mat.pbrMetallicRoughness.roughnessFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR); - - float roughnessAsShininess = 1 - mat.pbrMetallicRoughness.roughnessFactor; - roughnessAsShininess *= roughnessAsShininess * 1000; - aimat->AddProperty(&roughnessAsShininess, 1, AI_MATKEY_SHININESS); - - SetMaterialTextureProperty(embeddedTexIdxs, r, mat.normalTexture, aimat, aiTextureType_NORMALS); - SetMaterialTextureProperty(embeddedTexIdxs, r, mat.occlusionTexture, aimat, aiTextureType_LIGHTMAP); - SetMaterialTextureProperty(embeddedTexIdxs, r, mat.emissiveTexture, aimat, aiTextureType_EMISSIVE); - SetMaterialColorProperty(r, mat.emissiveFactor, aimat, AI_MATKEY_COLOR_EMISSIVE); - - aimat->AddProperty(&mat.doubleSided, 1, AI_MATKEY_TWOSIDED); - - aiString alphaMode(mat.alphaMode); - aimat->AddProperty(&alphaMode, AI_MATKEY_GLTF_ALPHAMODE); - aimat->AddProperty(&mat.alphaCutoff, 1, AI_MATKEY_GLTF_ALPHACUTOFF); - - //pbrSpecularGlossiness - if (mat.pbrSpecularGlossiness.isPresent) { - PbrSpecularGlossiness &pbrSG = mat.pbrSpecularGlossiness.value; - - aimat->AddProperty(&mat.pbrSpecularGlossiness.isPresent, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS); - SetMaterialColorProperty(r, pbrSG.diffuseFactor, aimat, AI_MATKEY_COLOR_DIFFUSE); - SetMaterialColorProperty(r, pbrSG.specularFactor, aimat, AI_MATKEY_COLOR_SPECULAR); - - float glossinessAsShininess = pbrSG.glossinessFactor * 1000.0f; - aimat->AddProperty(&glossinessAsShininess, 1, AI_MATKEY_SHININESS); - aimat->AddProperty(&pbrSG.glossinessFactor, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR); - - SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.diffuseTexture, aimat, aiTextureType_DIFFUSE); - - SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.specularGlossinessTexture, aimat, aiTextureType_SPECULAR); - } - if (mat.unlit) { - aimat->AddProperty(&mat.unlit, 1, AI_MATKEY_GLTF_UNLIT); - } - //KHR_materials_sheen - if (mat.materialSheen.isPresent) { - MaterialSheen &sheen = mat.materialSheen.value; - - aimat->AddProperty(&mat.materialSheen.isPresent, 1, AI_MATKEY_GLTF_MATERIAL_SHEEN); - SetMaterialColorProperty(r, sheen.sheenColorFactor, aimat, AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_FACTOR); - aimat->AddProperty(&sheen.sheenRoughnessFactor, 1, AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_FACTOR); - SetMaterialTextureProperty(embeddedTexIdxs, r, sheen.sheenColorTexture, aimat, AI_MATKEY_GLTF_MATERIAL_SHEEN_COLOR_TEXTURE); - SetMaterialTextureProperty(embeddedTexIdxs, r, sheen.sheenRoughnessTexture, aimat, AI_MATKEY_GLTF_MATERIAL_SHEEN_ROUGHNESS_TEXTURE); - } - //KHR_materials_clearcoat - if (mat.materialClearcoat.isPresent) { - MaterialClearcoat &clearcoat = mat.materialClearcoat.value; - - aimat->AddProperty(&mat.materialClearcoat.isPresent, 1, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT); - aimat->AddProperty(&clearcoat.clearcoatFactor, 1, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_FACTOR); - aimat->AddProperty(&clearcoat.clearcoatRoughnessFactor, 1, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_FACTOR); - SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatTexture, aimat, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_TEXTURE); - SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatRoughnessTexture, aimat, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_ROUGHNESS_TEXTURE); - SetMaterialTextureProperty(embeddedTexIdxs, r, clearcoat.clearcoatNormalTexture, aimat, AI_MATKEY_GLTF_MATERIAL_CLEARCOAT_NORMAL_TEXTURE); - } - //KHR_materials_transmission - if (mat.materialTransmission.isPresent) { - MaterialTransmission &transmission = mat.materialTransmission.value; - - aimat->AddProperty(&mat.materialTransmission.isPresent, 1, AI_MATKEY_GLTF_MATERIAL_TRANSMISSION); - aimat->AddProperty(&transmission.transmissionFactor, 1, AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_FACTOR); - SetMaterialTextureProperty(embeddedTexIdxs, r, transmission.transmissionTexture, aimat, AI_MATKEY_GLTF_MATERIAL_TRANSMISSION_TEXTURE); - } - - return aimat; } void glTF2Importer::ImportMaterials(glTF2::Asset &r) { @@ -320,6 +328,7 @@ void glTF2Importer::ImportMaterials(glTF2::Asset &r) { mScene->mNumMaterials = numImportedMaterials + 1; mScene->mMaterials = new aiMaterial *[mScene->mNumMaterials]; + std::fill(mScene->mMaterials, mScene->mMaterials + mScene->mNumMaterials, nullptr); mScene->mMaterials[numImportedMaterials] = ImportMaterial(embeddedTexIdxs, r, defaultMaterial); for (unsigned int i = 0; i < numImportedMaterials; ++i) { @@ -481,6 +490,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) { if (targets.size() > 0) { aim->mNumAnimMeshes = (unsigned int)targets.size(); aim->mAnimMeshes = new aiAnimMesh *[aim->mNumAnimMeshes]; + std::fill(aim->mAnimMeshes, aim->mAnimMeshes + aim->mNumAnimMeshes, nullptr); for (size_t i = 0; i < targets.size(); i++) { bool needPositions = targets[i].position.size() > 0; bool needNormals = targets[i].normal.size() > 0; @@ -539,7 +549,9 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) { size_t count = prim.indices->count; Accessor::Indexer data = prim.indices->GetIndexer(); - ai_assert(data.IsValid()); + if (!data.IsValid()) { + throw DeadlyImportError("GLTF: Invalid accessor without data in mesh ", getContextForErrorMessages(mesh.id, mesh.name)); + } switch (prim.mode) { case PrimitiveMode_POINTS: { @@ -728,6 +740,7 @@ void glTF2Importer::ImportCameras(glTF2::Asset &r) { ASSIMP_LOG_DEBUG_F("Importing ", numCameras, " cameras"); mScene->mNumCameras = numCameras; mScene->mCameras = new aiCamera *[numCameras]; + std::fill(mScene->mCameras, mScene->mCameras + numCameras, nullptr); for (size_t i = 0; i < numCameras; ++i) { Camera &cam = r.cameras[i]; @@ -764,6 +777,7 @@ void glTF2Importer::ImportLights(glTF2::Asset &r) { ASSIMP_LOG_DEBUG_F("Importing ", numLights, " lights"); mScene->mNumLights = numLights; mScene->mLights = new aiLight *[numLights]; + std::fill(mScene->mLights, mScene->mLights + numLights, nullptr); for (size_t i = 0; i < numLights; ++i) { Light &light = r.lights[i]; @@ -927,129 +941,136 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector & aiNode *ainode = new aiNode(GetNodeName(node)); - if (!node.children.empty()) { - ainode->mNumChildren = unsigned(node.children.size()); - ainode->mChildren = new aiNode *[ainode->mNumChildren]; + try { + if (!node.children.empty()) { + ainode->mNumChildren = unsigned(node.children.size()); + ainode->mChildren = new aiNode *[ainode->mNumChildren]; + std::fill(ainode->mChildren, ainode->mChildren + ainode->mNumChildren, nullptr); - for (unsigned int i = 0; i < ainode->mNumChildren; ++i) { - aiNode *child = ImportNode(pScene, r, meshOffsets, node.children[i]); - child->mParent = ainode; - ainode->mChildren[i] = child; + for (unsigned int i = 0; i < ainode->mNumChildren; ++i) { + aiNode *child = ImportNode(pScene, r, meshOffsets, node.children[i]); + child->mParent = ainode; + ainode->mChildren[i] = child; + } } - } - if (node.extensions) { - ainode->mMetaData = new aiMetadata; - ParseExtensions(ainode->mMetaData, node.extensions); - } - - GetNodeTransform(ainode->mTransformation, node); - - if (!node.meshes.empty()) { - // GLTF files contain at most 1 mesh per node. - if (node.meshes.size() > 1) - { - throw DeadlyImportError("GLTF: Invalid input, found ", node.meshes.size(), " meshes in ", getContextForErrorMessages(node.id, node.name), ", but only 1 mesh per node allowed."); + if (node.extensions) { + ainode->mMetaData = new aiMetadata; + ParseExtensions(ainode->mMetaData, node.extensions); } - int mesh_idx = node.meshes[0].GetIndex(); - int count = meshOffsets[mesh_idx + 1] - meshOffsets[mesh_idx]; - ainode->mNumMeshes = count; - ainode->mMeshes = new unsigned int[count]; + GetNodeTransform(ainode->mTransformation, node); - if (node.skin) { - for (int primitiveNo = 0; primitiveNo < count; ++primitiveNo) { - aiMesh *mesh = pScene->mMeshes[meshOffsets[mesh_idx] + primitiveNo]; - unsigned int numBones =static_cast(node.skin->jointNames.size()); + if (!node.meshes.empty()) { + // GLTF files contain at most 1 mesh per node. + if (node.meshes.size() > 1) + { + throw DeadlyImportError("GLTF: Invalid input, found ", node.meshes.size(), " meshes in ", getContextForErrorMessages(node.id, node.name), ", but only 1 mesh per node allowed."); + } + int mesh_idx = node.meshes[0].GetIndex(); + int count = meshOffsets[mesh_idx + 1] - meshOffsets[mesh_idx]; - std::vector> weighting(numBones); - BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting); + ainode->mNumMeshes = count; + ainode->mMeshes = new unsigned int[count]; - mesh->mNumBones = static_cast(numBones); - mesh->mBones = new aiBone *[mesh->mNumBones]; + if (node.skin) { + for (int primitiveNo = 0; primitiveNo < count; ++primitiveNo) { + aiMesh *mesh = pScene->mMeshes[meshOffsets[mesh_idx] + primitiveNo]; + unsigned int numBones =static_cast(node.skin->jointNames.size()); - // GLTF and Assimp choose to store bone weights differently. - // GLTF has each vertex specify which bones influence the vertex. - // Assimp has each bone specify which vertices it has influence over. - // To convert this data, we first read over the vertex data and pull - // out the bone-to-vertex mapping. Then, when creating the aiBones, - // we copy the bone-to-vertex mapping into the bone. This is unfortunate - // both because it's somewhat slow and because, for many applications, - // we then need to reconvert the data back into the vertex-to-bone - // mapping which makes things doubly-slow. + std::vector> weighting(numBones); + BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting); - mat4 *pbindMatrices = nullptr; - node.skin->inverseBindMatrices->ExtractData(pbindMatrices); + mesh->mNumBones = static_cast(numBones); + mesh->mBones = new aiBone *[mesh->mNumBones]; + std::fill(mesh->mBones, mesh->mBones + mesh->mNumBones, nullptr); - for (uint32_t i = 0; i < numBones; ++i) { - const std::vector &weights = weighting[i]; - aiBone *bone = new aiBone(); + // GLTF and Assimp choose to store bone weights differently. + // GLTF has each vertex specify which bones influence the vertex. + // Assimp has each bone specify which vertices it has influence over. + // To convert this data, we first read over the vertex data and pull + // out the bone-to-vertex mapping. Then, when creating the aiBones, + // we copy the bone-to-vertex mapping into the bone. This is unfortunate + // both because it's somewhat slow and because, for many applications, + // we then need to reconvert the data back into the vertex-to-bone + // mapping which makes things doubly-slow. - Ref joint = node.skin->jointNames[i]; - if (!joint->name.empty()) { - bone->mName = joint->name; - } else { - // Assimp expects each bone to have a unique name. - static const std::string kDefaultName = "bone_"; - char postfix[10] = { 0 }; - ASSIMP_itoa10(postfix, i); - bone->mName = (kDefaultName + postfix); + mat4 *pbindMatrices = nullptr; + node.skin->inverseBindMatrices->ExtractData(pbindMatrices); + + for (uint32_t i = 0; i < numBones; ++i) { + const std::vector &weights = weighting[i]; + aiBone *bone = new aiBone(); + + Ref joint = node.skin->jointNames[i]; + if (!joint->name.empty()) { + bone->mName = joint->name; + } else { + // Assimp expects each bone to have a unique name. + static const std::string kDefaultName = "bone_"; + char postfix[10] = { 0 }; + ASSIMP_itoa10(postfix, i); + bone->mName = (kDefaultName + postfix); + } + GetNodeTransform(bone->mOffsetMatrix, *joint); + CopyValue(pbindMatrices[i], bone->mOffsetMatrix); + bone->mNumWeights = static_cast(weights.size()); + + if (bone->mNumWeights > 0) { + bone->mWeights = new aiVertexWeight[bone->mNumWeights]; + memcpy(bone->mWeights, weights.data(), bone->mNumWeights * sizeof(aiVertexWeight)); + } else { + // Assimp expects all bones to have at least 1 weight. + bone->mWeights = new aiVertexWeight[1]; + bone->mNumWeights = 1; + bone->mWeights->mVertexId = 0; + bone->mWeights->mWeight = 0.f; + } + mesh->mBones[i] = bone; } - GetNodeTransform(bone->mOffsetMatrix, *joint); - CopyValue(pbindMatrices[i], bone->mOffsetMatrix); - bone->mNumWeights = static_cast(weights.size()); - if (bone->mNumWeights > 0) { - bone->mWeights = new aiVertexWeight[bone->mNumWeights]; - memcpy(bone->mWeights, weights.data(), bone->mNumWeights * sizeof(aiVertexWeight)); - } else { - // Assimp expects all bones to have at least 1 weight. - bone->mWeights = new aiVertexWeight[1]; - bone->mNumWeights = 1; - bone->mWeights->mVertexId = 0; - bone->mWeights->mWeight = 0.f; + if (pbindMatrices) { + delete[] pbindMatrices; } - mesh->mBones[i] = bone; } + } - if (pbindMatrices) { - delete[] pbindMatrices; + int k = 0; + for (unsigned int j = meshOffsets[mesh_idx]; j < meshOffsets[mesh_idx + 1]; ++j, ++k) { + ainode->mMeshes[k] = j; + } + } + + if (node.camera) { + pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName; + if (node.translation.isPresent) { + aiVector3D trans; + CopyValue(node.translation.value, trans); + pScene->mCameras[node.camera.GetIndex()]->mPosition = trans; + } + } + + if (node.light) { + pScene->mLights[node.light.GetIndex()]->mName = ainode->mName; + + //range is optional - see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual + //it is added to meta data of parent node, because there is no other place to put it + if (node.light->range.isPresent) { + if (!ainode->mMetaData) { + ainode->mMetaData = aiMetadata::Alloc(1); + ainode->mMetaData->Set(0, "PBR_LightRange", node.light->range.value); + } + else { + ainode->mMetaData->Add("PBR_LightRange", node.light->range.value); } } } - int k = 0; - for (unsigned int j = meshOffsets[mesh_idx]; j < meshOffsets[mesh_idx + 1]; ++j, ++k) { - ainode->mMeshes[k] = j; - } + return ainode; + } catch (...) { + delete ainode; + throw; } - - if (node.camera) { - pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName; - if (node.translation.isPresent) { - aiVector3D trans; - CopyValue(node.translation.value, trans); - pScene->mCameras[node.camera.GetIndex()]->mPosition = trans; - } - } - - if (node.light) { - pScene->mLights[node.light.GetIndex()]->mName = ainode->mName; - - //range is optional - see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual - //it is added to meta data of parent node, because there is no other place to put it - if (node.light->range.isPresent) { - if (!ainode->mMetaData) { - ainode->mMetaData = aiMetadata::Alloc(1); - ainode->mMetaData->Set(0, "PBR_LightRange", node.light->range.value); - } - else { - ainode->mMetaData->Add("PBR_LightRange", node.light->range.value); - } - } - } - - return ainode; } void glTF2Importer::ImportNodes(glTF2::Asset &r) { @@ -1065,14 +1086,16 @@ void glTF2Importer::ImportNodes(glTF2::Asset &r) { if (numRootNodes == 1) { // a single root node: use it mScene->mRootNode = ImportNode(mScene, r, meshOffsets, rootNodes[0]); } else if (numRootNodes > 1) { // more than one root node: create a fake root - aiNode *root = new aiNode("ROOT"); + aiNode *root = mScene->mRootNode = new aiNode("ROOT"); + root->mChildren = new aiNode *[numRootNodes]; + std::fill(root->mChildren, root->mChildren + numRootNodes, nullptr); + for (unsigned int i = 0; i < numRootNodes; ++i) { aiNode *node = ImportNode(mScene, r, meshOffsets, rootNodes[i]); node->mParent = root; root->mChildren[root->mNumChildren++] = node; } - mScene->mRootNode = root; } else { mScene->mRootNode = new aiNode("ROOT"); } @@ -1095,133 +1118,145 @@ struct AnimationSamplers { aiNodeAnim *CreateNodeAnim(glTF2::Asset&, Node &node, AnimationSamplers &samplers) { aiNodeAnim *anim = new aiNodeAnim(); - anim->mNodeName = GetNodeName(node); - static const float kMillisecondsFromSeconds = 1000.f; + try { + anim->mNodeName = GetNodeName(node); - if (samplers.translation) { - float *times = nullptr; - samplers.translation->input->ExtractData(times); - aiVector3D *values = nullptr; - samplers.translation->output->ExtractData(values); - anim->mNumPositionKeys = static_cast(samplers.translation->input->count); - anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys]; - unsigned int ii = (samplers.translation->interpolation == Interpolation_CUBICSPLINE) ? 1 : 0; - for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) { - anim->mPositionKeys[i].mTime = times[i] * kMillisecondsFromSeconds; - anim->mPositionKeys[i].mValue = values[ii]; - ii += (samplers.translation->interpolation == Interpolation_CUBICSPLINE) ? 3 : 1; + static const float kMillisecondsFromSeconds = 1000.f; + + if (samplers.translation) { + float *times = nullptr; + samplers.translation->input->ExtractData(times); + aiVector3D *values = nullptr; + samplers.translation->output->ExtractData(values); + anim->mNumPositionKeys = static_cast(samplers.translation->input->count); + anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys]; + unsigned int ii = (samplers.translation->interpolation == Interpolation_CUBICSPLINE) ? 1 : 0; + for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) { + anim->mPositionKeys[i].mTime = times[i] * kMillisecondsFromSeconds; + anim->mPositionKeys[i].mValue = values[ii]; + ii += (samplers.translation->interpolation == Interpolation_CUBICSPLINE) ? 3 : 1; + } + delete[] times; + delete[] values; + } else if (node.translation.isPresent) { + anim->mNumPositionKeys = 1; + anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys]; + anim->mPositionKeys->mTime = 0.f; + anim->mPositionKeys->mValue.x = node.translation.value[0]; + anim->mPositionKeys->mValue.y = node.translation.value[1]; + anim->mPositionKeys->mValue.z = node.translation.value[2]; } - delete[] times; - delete[] values; - } else if (node.translation.isPresent) { - anim->mNumPositionKeys = 1; - anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys]; - anim->mPositionKeys->mTime = 0.f; - anim->mPositionKeys->mValue.x = node.translation.value[0]; - anim->mPositionKeys->mValue.y = node.translation.value[1]; - anim->mPositionKeys->mValue.z = node.translation.value[2]; - } - if (samplers.rotation) { - float *times = nullptr; - samplers.rotation->input->ExtractData(times); - aiQuaternion *values = nullptr; - samplers.rotation->output->ExtractData(values); - anim->mNumRotationKeys = static_cast(samplers.rotation->input->count); - anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys]; - unsigned int ii = (samplers.rotation->interpolation == Interpolation_CUBICSPLINE) ? 1 : 0; - for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) { - anim->mRotationKeys[i].mTime = times[i] * kMillisecondsFromSeconds; - anim->mRotationKeys[i].mValue.x = values[ii].w; - anim->mRotationKeys[i].mValue.y = values[ii].x; - anim->mRotationKeys[i].mValue.z = values[ii].y; - anim->mRotationKeys[i].mValue.w = values[ii].z; - ii += (samplers.rotation->interpolation == Interpolation_CUBICSPLINE) ? 3 : 1; + if (samplers.rotation) { + float *times = nullptr; + samplers.rotation->input->ExtractData(times); + aiQuaternion *values = nullptr; + samplers.rotation->output->ExtractData(values); + anim->mNumRotationKeys = static_cast(samplers.rotation->input->count); + anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys]; + unsigned int ii = (samplers.rotation->interpolation == Interpolation_CUBICSPLINE) ? 1 : 0; + for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) { + anim->mRotationKeys[i].mTime = times[i] * kMillisecondsFromSeconds; + anim->mRotationKeys[i].mValue.x = values[ii].w; + anim->mRotationKeys[i].mValue.y = values[ii].x; + anim->mRotationKeys[i].mValue.z = values[ii].y; + anim->mRotationKeys[i].mValue.w = values[ii].z; + ii += (samplers.rotation->interpolation == Interpolation_CUBICSPLINE) ? 3 : 1; + } + delete[] times; + delete[] values; + } else if (node.rotation.isPresent) { + anim->mNumRotationKeys = 1; + anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys]; + anim->mRotationKeys->mTime = 0.f; + anim->mRotationKeys->mValue.x = node.rotation.value[0]; + anim->mRotationKeys->mValue.y = node.rotation.value[1]; + anim->mRotationKeys->mValue.z = node.rotation.value[2]; + anim->mRotationKeys->mValue.w = node.rotation.value[3]; } - delete[] times; - delete[] values; - } else if (node.rotation.isPresent) { - anim->mNumRotationKeys = 1; - anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys]; - anim->mRotationKeys->mTime = 0.f; - anim->mRotationKeys->mValue.x = node.rotation.value[0]; - anim->mRotationKeys->mValue.y = node.rotation.value[1]; - anim->mRotationKeys->mValue.z = node.rotation.value[2]; - anim->mRotationKeys->mValue.w = node.rotation.value[3]; - } - if (samplers.scale) { - float *times = nullptr; - samplers.scale->input->ExtractData(times); - aiVector3D *values = nullptr; - samplers.scale->output->ExtractData(values); - anim->mNumScalingKeys = static_cast(samplers.scale->input->count); - anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys]; - unsigned int ii = (samplers.scale->interpolation == Interpolation_CUBICSPLINE) ? 1 : 0; - for (unsigned int i = 0; i < anim->mNumScalingKeys; ++i) { - anim->mScalingKeys[i].mTime = times[i] * kMillisecondsFromSeconds; - anim->mScalingKeys[i].mValue = values[ii]; - ii += (samplers.scale->interpolation == Interpolation_CUBICSPLINE) ? 3 : 1; + if (samplers.scale) { + float *times = nullptr; + samplers.scale->input->ExtractData(times); + aiVector3D *values = nullptr; + samplers.scale->output->ExtractData(values); + anim->mNumScalingKeys = static_cast(samplers.scale->input->count); + anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys]; + unsigned int ii = (samplers.scale->interpolation == Interpolation_CUBICSPLINE) ? 1 : 0; + for (unsigned int i = 0; i < anim->mNumScalingKeys; ++i) { + anim->mScalingKeys[i].mTime = times[i] * kMillisecondsFromSeconds; + anim->mScalingKeys[i].mValue = values[ii]; + ii += (samplers.scale->interpolation == Interpolation_CUBICSPLINE) ? 3 : 1; + } + delete[] times; + delete[] values; + } else if (node.scale.isPresent) { + anim->mNumScalingKeys = 1; + anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys]; + anim->mScalingKeys->mTime = 0.f; + anim->mScalingKeys->mValue.x = node.scale.value[0]; + anim->mScalingKeys->mValue.y = node.scale.value[1]; + anim->mScalingKeys->mValue.z = node.scale.value[2]; } - delete[] times; - delete[] values; - } else if (node.scale.isPresent) { - anim->mNumScalingKeys = 1; - anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys]; - anim->mScalingKeys->mTime = 0.f; - anim->mScalingKeys->mValue.x = node.scale.value[0]; - anim->mScalingKeys->mValue.y = node.scale.value[1]; - anim->mScalingKeys->mValue.z = node.scale.value[2]; - } - return anim; + return anim; + } catch (...) { + delete anim; + throw; + } } aiMeshMorphAnim *CreateMeshMorphAnim(glTF2::Asset&, Node &node, AnimationSamplers &samplers) { aiMeshMorphAnim *anim = new aiMeshMorphAnim(); - anim->mName = GetNodeName(node); - static const float kMillisecondsFromSeconds = 1000.f; + try { + anim->mName = GetNodeName(node); - if (nullptr != samplers.weight) { - float *times = nullptr; - samplers.weight->input->ExtractData(times); - float *values = nullptr; - samplers.weight->output->ExtractData(values); - anim->mNumKeys = static_cast(samplers.weight->input->count); + static const float kMillisecondsFromSeconds = 1000.f; - // for Interpolation_CUBICSPLINE can have more outputs - const unsigned int weightStride = (unsigned int)samplers.weight->output->count / anim->mNumKeys; - const unsigned int numMorphs = (samplers.weight->interpolation == Interpolation_CUBICSPLINE) ? weightStride - 2 : weightStride; + if (nullptr != samplers.weight) { + float *times = nullptr; + samplers.weight->input->ExtractData(times); + float *values = nullptr; + samplers.weight->output->ExtractData(values); + anim->mNumKeys = static_cast(samplers.weight->input->count); - anim->mKeys = new aiMeshMorphKey[anim->mNumKeys]; - unsigned int ii = (samplers.weight->interpolation == Interpolation_CUBICSPLINE) ? 1 : 0; - for (unsigned int i = 0u; i < anim->mNumKeys; ++i) { - unsigned int k = weightStride * i + ii; - anim->mKeys[i].mTime = times[i] * kMillisecondsFromSeconds; - anim->mKeys[i].mNumValuesAndWeights = numMorphs; - anim->mKeys[i].mValues = new unsigned int[numMorphs]; - anim->mKeys[i].mWeights = new double[numMorphs]; + // for Interpolation_CUBICSPLINE can have more outputs + const unsigned int weightStride = (unsigned int)samplers.weight->output->count / anim->mNumKeys; + const unsigned int numMorphs = (samplers.weight->interpolation == Interpolation_CUBICSPLINE) ? weightStride - 2 : weightStride; - for (unsigned int j = 0u; j < numMorphs; ++j, ++k) { - anim->mKeys[i].mValues[j] = j; - anim->mKeys[i].mWeights[j] = (0.f > values[k]) ? 0.f : values[k]; + anim->mKeys = new aiMeshMorphKey[anim->mNumKeys]; + unsigned int ii = (samplers.weight->interpolation == Interpolation_CUBICSPLINE) ? 1 : 0; + for (unsigned int i = 0u; i < anim->mNumKeys; ++i) { + unsigned int k = weightStride * i + ii; + anim->mKeys[i].mTime = times[i] * kMillisecondsFromSeconds; + anim->mKeys[i].mNumValuesAndWeights = numMorphs; + anim->mKeys[i].mValues = new unsigned int[numMorphs]; + anim->mKeys[i].mWeights = new double[numMorphs]; + + for (unsigned int j = 0u; j < numMorphs; ++j, ++k) { + anim->mKeys[i].mValues[j] = j; + anim->mKeys[i].mWeights[j] = (0.f > values[k]) ? 0.f : values[k]; + } } + + delete[] times; + delete[] values; } - delete[] times; - delete[] values; + return anim; + } catch (...) { + delete anim; + throw; } - - return anim; } std::unordered_map GatherSamplers(Animation &anim) { std::unordered_map samplers; for (unsigned int c = 0; c < anim.channels.size(); ++c) { Animation::Channel &channel = anim.channels[c]; - if (channel.sampler >= static_cast(anim.samplers.size())) { + if (channel.sampler < 0 || channel.sampler >= static_cast(anim.samplers.size())) { continue; } @@ -1253,10 +1288,13 @@ void glTF2Importer::ImportAnimations(glTF2::Asset &r) { } mScene->mAnimations = new aiAnimation *[numAnimations]; + std::fill(mScene->mAnimations, mScene->mAnimations + numAnimations, nullptr); + for (unsigned int i = 0; i < numAnimations; ++i) { + aiAnimation *ai_anim = mScene->mAnimations[i] = new aiAnimation(); + Animation &anim = r.animations[i]; - aiAnimation *ai_anim = new aiAnimation(); ai_anim->mName = anim.name; ai_anim->mDuration = 0; ai_anim->mTicksPerSecond = 0; @@ -1278,6 +1316,7 @@ void glTF2Importer::ImportAnimations(glTF2::Asset &r) { ai_anim->mNumChannels = numChannels; if (ai_anim->mNumChannels > 0) { ai_anim->mChannels = new aiNodeAnim *[ai_anim->mNumChannels]; + std::fill(ai_anim->mChannels, ai_anim->mChannels + ai_anim->mNumChannels, nullptr); int j = 0; for (auto &iter : samplers) { if ((nullptr != iter.second.rotation) || (nullptr != iter.second.scale) || (nullptr != iter.second.translation)) { @@ -1290,6 +1329,7 @@ void glTF2Importer::ImportAnimations(glTF2::Asset &r) { ai_anim->mNumMorphMeshChannels = numMorphMeshChannels; if (ai_anim->mNumMorphMeshChannels > 0) { ai_anim->mMorphMeshChannels = new aiMeshMorphAnim *[ai_anim->mNumMorphMeshChannels]; + std::fill(ai_anim->mMorphMeshChannels, ai_anim->mMorphMeshChannels + ai_anim->mNumMorphMeshChannels, nullptr); int j = 0; for (auto &iter : samplers) { if (nullptr != iter.second.weight) { @@ -1341,8 +1381,6 @@ void glTF2Importer::ImportAnimations(glTF2::Asset &r) { ai_anim->mDuration = maxDuration; ai_anim->mTicksPerSecond = 1000.0; - - mScene->mAnimations[i] = ai_anim; } } @@ -1362,6 +1400,7 @@ void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset &r) { ASSIMP_LOG_DEBUG_F("Importing ", numEmbeddedTexs, " embedded textures"); mScene->mTextures = new aiTexture *[numEmbeddedTexs]; + std::fill(mScene->mTextures, mScene->mTextures + numEmbeddedTexs, nullptr); // Add the embedded textures for (size_t i = 0; i < r.images.Size(); ++i) {