From 8701a86c9d474bc07c2eceec72074bda98a3b128 Mon Sep 17 00:00:00 2001 From: Jean-Louis Boudrand Date: Thu, 10 Dec 2020 23:47:54 +0100 Subject: [PATCH 01/11] Fixed a crash of the Gltf 2 exporter in the case of an animation without a translation, rotation or scale animation key. --- code/AssetLib/glTF2/glTF2Exporter.cpp | 36 +++++++++++++-------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index 637808877..5852dfc01 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -1258,9 +1258,6 @@ inline Ref GetSamplerInputRef(Asset& asset, std::string& animId, Ref& buffer, const aiNodeAnim* nodeChannel, float ticksPerSecond, Animation::Sampler& sampler) { const unsigned int numKeyframes = nodeChannel->mNumPositionKeys; - if (numKeyframes == 0) { - return; - } std::vector times(numKeyframes); std::vector values(numKeyframes * 3); @@ -1281,9 +1278,6 @@ inline void ExtractTranslationSampler(Asset& asset, std::string& animId, Ref& buffer, const aiNodeAnim* nodeChannel, float ticksPerSecond, Animation::Sampler& sampler) { const unsigned int numKeyframes = nodeChannel->mNumScalingKeys; - if (numKeyframes == 0) { - return; - } std::vector times(numKeyframes); std::vector values(numKeyframes * 3); @@ -1304,9 +1298,6 @@ inline void ExtractScaleSampler(Asset& asset, std::string& animId, Ref& inline void ExtractRotationSampler(Asset& asset, std::string& animId, Ref& buffer, const aiNodeAnim* nodeChannel, float ticksPerSecond, Animation::Sampler& sampler) { const unsigned int numKeyframes = nodeChannel->mNumRotationKeys; - if (numKeyframes == 0) { - return; - } std::vector times(numKeyframes); std::vector values(numKeyframes * 4); @@ -1359,17 +1350,26 @@ void glTF2Exporter::ExportAnimations() Ref animNode = mAsset->nodes.Get(nodeChannel->mNodeName.C_Str()); - Animation::Sampler translationSampler; - ExtractTranslationSampler(*mAsset, name, bufferRef, nodeChannel, ticksPerSecond, translationSampler); - AddSampler(animRef, animNode, translationSampler, AnimationPath_TRANSLATION); + if (nodeChannel->mNumPositionKeys > 0) + { + Animation::Sampler translationSampler; + ExtractTranslationSampler(*mAsset, name, bufferRef, nodeChannel, ticksPerSecond, translationSampler); + AddSampler(animRef, animNode, translationSampler, AnimationPath_TRANSLATION); + } - Animation::Sampler rotationSampler; - ExtractRotationSampler(*mAsset, name, bufferRef, nodeChannel, ticksPerSecond, rotationSampler); - AddSampler(animRef, animNode, rotationSampler, AnimationPath_ROTATION); + if (nodeChannel->mNumRotationKeys > 0) + { + Animation::Sampler rotationSampler; + ExtractRotationSampler(*mAsset, name, bufferRef, nodeChannel, ticksPerSecond, rotationSampler); + AddSampler(animRef, animNode, rotationSampler, AnimationPath_ROTATION); + } - Animation::Sampler scaleSampler; - ExtractScaleSampler(*mAsset, name, bufferRef, nodeChannel, ticksPerSecond, scaleSampler); - AddSampler(animRef, animNode, scaleSampler, AnimationPath_SCALE); + if (nodeChannel->mNumScalingKeys > 0) + { + Animation::Sampler scaleSampler; + ExtractScaleSampler(*mAsset, name, bufferRef, nodeChannel, ticksPerSecond, scaleSampler); + AddSampler(animRef, animNode, scaleSampler, AnimationPath_SCALE); + } } // Assimp documentation staes this is not used (not implemented) From e2af015a57a276e4bca23f03cc26e947a582e9d0 Mon Sep 17 00:00:00 2001 From: Biswapriyo Nath Date: Fri, 11 Dec 2020 21:43:09 +0530 Subject: [PATCH 02/11] Common: Fix GCC error invalid conversion in MINGW. --- code/CMakeLists.txt | 2 +- code/Common/ZipArchiveIOSystem.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index bb83a5f97..7a017cfa4 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1015,7 +1015,7 @@ ENDIF() # RT-extensions is used in "contrib/Open3DGC/o3dgcTimer.h" for collecting statistics. Pointed file # has implementation for different platforms: WIN32, __MACH__ and other ("else" block). FIND_PACKAGE(RT QUIET) -IF (NOT ASSIMP_HUNTER_ENABLED AND (RT_FOUND OR MSVC)) +IF (NOT ASSIMP_HUNTER_ENABLED AND (RT_FOUND OR WIN32)) SET( ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC 1 ) ADD_DEFINITIONS( -DASSIMP_IMPORTER_GLTF_USE_OPEN3DGC=1 ) ELSE () diff --git a/code/Common/ZipArchiveIOSystem.cpp b/code/Common/ZipArchiveIOSystem.cpp index f55f9ff53..6cd50739e 100644 --- a/code/Common/ZipArchiveIOSystem.cpp +++ b/code/Common/ZipArchiveIOSystem.cpp @@ -146,7 +146,7 @@ int IOSystem2Unzip::testerror(voidpf /*opaque*/, voidpf /*stream*/) { zlib_filefunc_def IOSystem2Unzip::get(IOSystem *pIOHandler) { zlib_filefunc_def mapping; -#ifdef ASSIMP_USE_HUNTER +#if defined (ASSIMP_USE_HUNTER) || defined (__MINGW32__) // GH#3144 mapping.zopen_file = (open_file_func)open; mapping.zread_file = (read_file_func)read; mapping.zwrite_file = (write_file_func)write; @@ -335,7 +335,7 @@ ZipArchiveIOSystem::Implement::Implement(IOSystem *pIOHandler, const char *pFile if (pFilename[0] == 0 || nullptr == pMode) { return; } - + zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler); m_ZipFileHandle = unzOpen2(pFilename, &mapping); } From c65f2cb3fbd7dd66474ea8821fba0080f144f33d Mon Sep 17 00:00:00 2001 From: Biswapriyo Nath Date: Sat, 12 Dec 2020 11:15:04 +0530 Subject: [PATCH 03/11] Remove extra semicolon while GCC being pedantic. --- code/AssetLib/Collada/ColladaHelper.cpp | 4 ++-- contrib/Open3DGC/o3dgcVector.inl | 4 ++-- .../SimpleTexturedOpenGL/src/model_loading.cpp | 2 +- tools/assimp_view/MeshRenderer.cpp | 2 +- tools/assimp_view/MessageProc.cpp | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/code/AssetLib/Collada/ColladaHelper.cpp b/code/AssetLib/Collada/ColladaHelper.cpp index 0a779e04e..1a4bed3b1 100644 --- a/code/AssetLib/Collada/ColladaHelper.cpp +++ b/code/AssetLib/Collada/ColladaHelper.cpp @@ -53,7 +53,7 @@ const MetaKeyPairVector MakeColladaAssimpMetaKeys() { result.emplace_back("authoring_tool", AI_METADATA_SOURCE_GENERATOR); result.emplace_back("copyright", AI_METADATA_SOURCE_COPYRIGHT); return result; -}; +} const MetaKeyPairVector &GetColladaAssimpMetaKeys() { static const MetaKeyPairVector result = MakeColladaAssimpMetaKeys(); @@ -66,7 +66,7 @@ const MetaKeyPairVector MakeColladaAssimpMetaKeysCamelCase() { ToCamelCase(val.first); } return result; -}; +} const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase() { static const MetaKeyPairVector result = MakeColladaAssimpMetaKeysCamelCase(); diff --git a/contrib/Open3DGC/o3dgcVector.inl b/contrib/Open3DGC/o3dgcVector.inl index 5549b00ce..de8dfd5f1 100644 --- a/contrib/Open3DGC/o3dgcVector.inl +++ b/contrib/Open3DGC/o3dgcVector.inl @@ -175,7 +175,7 @@ namespace o3dgc m_data[2] = rhs.m_data[2]; } template - inline Vec3::~Vec3(void){}; + inline Vec3::~Vec3(void){} template inline Vec3::Vec3() {} @@ -308,7 +308,7 @@ namespace o3dgc m_data[1] = rhs.m_data[1]; } template - inline Vec2::~Vec2(void){}; + inline Vec2::~Vec2(void){} template inline Vec2::Vec2() {} diff --git a/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp b/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp index a36c792d4..aa2344118 100644 --- a/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp +++ b/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp @@ -763,7 +763,7 @@ void cleanup() if (g_hWnd) KillGLWindow(); -}; +} LRESULT CALLBACK WndProc(HWND hWnd, // Handles for this Window UINT uMsg, // Message for this Window diff --git a/tools/assimp_view/MeshRenderer.cpp b/tools/assimp_view/MeshRenderer.cpp index d93bb4aea..972b3db24 100644 --- a/tools/assimp_view/MeshRenderer.cpp +++ b/tools/assimp_view/MeshRenderer.cpp @@ -161,4 +161,4 @@ int CMeshRenderer::DrawSorted(unsigned int iIndex,const aiMatrix4x4& mWorld) { return 1; } -}; +} diff --git a/tools/assimp_view/MessageProc.cpp b/tools/assimp_view/MessageProc.cpp index 80589e647..cebb78e22 100644 --- a/tools/assimp_view/MessageProc.cpp +++ b/tools/assimp_view/MessageProc.cpp @@ -2143,7 +2143,7 @@ INT_PTR CALLBACK AboutMessageProc(HWND hwndDlg,UINT uMsg, } return FALSE; } -}; +} using namespace AssimpView; From d18fce3f0695173c25f855c823d0e23701257f73 Mon Sep 17 00:00:00 2001 From: Jean-Louis Boudrand Date: Sun, 13 Dec 2020 17:02:50 +0100 Subject: [PATCH 04/11] Fix https://github.com/assimp/assimp/issues/3054 Corrected the animation of each bone of an animation were exported in different animations (+tabs fixes) --- code/AssetLib/glTF2/glTF2Exporter.cpp | 28 +++++++++++++-------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index 5852dfc01..6ebb54568 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -1338,38 +1338,36 @@ void glTF2Exporter::ExportAnimations() if (anim->mName.length > 0) { nameAnim = anim->mName.C_Str(); } + Ref animRef = mAsset->animations.Create(nameAnim); for (unsigned int channelIndex = 0; channelIndex < anim->mNumChannels; ++channelIndex) { const aiNodeAnim* nodeChannel = anim->mChannels[channelIndex]; - // It appears that assimp stores this type of animation as multiple animations. - // where each aiNodeAnim in mChannels animates a specific node. std::string name = nameAnim + "_" + to_string(channelIndex); name = mAsset->FindUniqueID(name, "animation"); - Ref animRef = mAsset->animations.Create(name); Ref animNode = mAsset->nodes.Get(nodeChannel->mNodeName.C_Str()); if (nodeChannel->mNumPositionKeys > 0) { - Animation::Sampler translationSampler; - ExtractTranslationSampler(*mAsset, name, bufferRef, nodeChannel, ticksPerSecond, translationSampler); - AddSampler(animRef, animNode, translationSampler, AnimationPath_TRANSLATION); - } + Animation::Sampler translationSampler; + ExtractTranslationSampler(*mAsset, name, bufferRef, nodeChannel, ticksPerSecond, translationSampler); + AddSampler(animRef, animNode, translationSampler, AnimationPath_TRANSLATION); + } if (nodeChannel->mNumRotationKeys > 0) { - Animation::Sampler rotationSampler; - ExtractRotationSampler(*mAsset, name, bufferRef, nodeChannel, ticksPerSecond, rotationSampler); - AddSampler(animRef, animNode, rotationSampler, AnimationPath_ROTATION); - } + Animation::Sampler rotationSampler; + ExtractRotationSampler(*mAsset, name, bufferRef, nodeChannel, ticksPerSecond, rotationSampler); + AddSampler(animRef, animNode, rotationSampler, AnimationPath_ROTATION); + } if (nodeChannel->mNumScalingKeys > 0) { - Animation::Sampler scaleSampler; - ExtractScaleSampler(*mAsset, name, bufferRef, nodeChannel, ticksPerSecond, scaleSampler); - AddSampler(animRef, animNode, scaleSampler, AnimationPath_SCALE); - } + Animation::Sampler scaleSampler; + ExtractScaleSampler(*mAsset, name, bufferRef, nodeChannel, ticksPerSecond, scaleSampler); + AddSampler(animRef, animNode, scaleSampler, AnimationPath_SCALE); + } } // Assimp documentation staes this is not used (not implemented) From 4e9176d2cdadc094228a5a24a5716340e25192b5 Mon Sep 17 00:00:00 2001 From: wasd845 <845073947@qq.com> Date: Mon, 14 Dec 2020 19:16:29 +0800 Subject: [PATCH 05/11] _dest may be destructed twice if _dest is not null in MergeScenes() --- code/Common/SceneCombiner.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/code/Common/SceneCombiner.cpp b/code/Common/SceneCombiner.cpp index bfc4899a1..193586a7c 100644 --- a/code/Common/SceneCombiner.cpp +++ b/code/Common/SceneCombiner.cpp @@ -183,9 +183,10 @@ void SceneCombiner::MergeScenes(aiScene **_dest, std::vector &src, un *_dest = src[0]; return; } - if (*_dest) + if (*_dest) { (*_dest)->~aiScene(); - else + new (*_dest) aiScene(); + } else *_dest = new aiScene(); // Create a dummy scene to serve as master for the others From 5436e1680278b2ca0f21091112b3597ec13d02c9 Mon Sep 17 00:00:00 2001 From: Max Vollmer Date: Mon, 14 Dec 2020 16:37:02 +0000 Subject: [PATCH 06/11] * Fix memory leak in GLTF2 Importer that occurs when an exception gets thrown while constructing a scene * Fix crash in GLTF2 Importer when a scene with dangling/uninitialized pointers gets deleted after an exception was thrown * Fix crash in GLTF2 Importer when channel sampler is not set (negative index) --- code/AssetLib/glTF2/glTF2Importer.cpp | 550 ++++++++++++++------------ 1 file changed, 292 insertions(+), 258 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index 672bac52d..d014e7ef1 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -229,59 +229,64 @@ 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); + } + + 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); - } - - return aimat; } void glTF2Importer::ImportMaterials(glTF2::Asset &r) { @@ -291,6 +296,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) { @@ -452,6 +458,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; @@ -699,6 +706,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]; @@ -735,6 +743,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]; @@ -898,129 +907,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) { @@ -1036,14 +1052,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"); } @@ -1064,135 +1082,147 @@ struct AnimationSamplers { Animation::Sampler *weight; }; -aiNodeAnim *CreateNodeAnim(glTF2::Asset&, Node &node, AnimationSamplers &samplers) { +aiNodeAnim *CreateNodeAnim(glTF2::Asset &r, 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; } @@ -1224,10 +1254,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; @@ -1249,6 +1282,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)) { @@ -1261,6 +1295,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) { @@ -1312,8 +1347,6 @@ void glTF2Importer::ImportAnimations(glTF2::Asset &r) { ai_anim->mDuration = maxDuration; ai_anim->mTicksPerSecond = 1000.0; - - mScene->mAnimations[i] = ai_anim; } } @@ -1333,6 +1366,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) { From 1db51503d87903211e830af8e79757f6b9c4d371 Mon Sep 17 00:00:00 2001 From: Max Vollmer Date: Mon, 14 Dec 2020 16:44:56 +0000 Subject: [PATCH 07/11] Throw instead of assert on invalid file input --- code/AssetLib/glTF2/glTF2Importer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index d014e7ef1..165e02935 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -517,7 +517,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: { From a15adc9fbcfb17689c204b476f7cf8bd8fa5eac1 Mon Sep 17 00:00:00 2001 From: Max Vollmer Date: Mon, 14 Dec 2020 17:01:42 +0000 Subject: [PATCH 08/11] Fixed copypaste error --- code/AssetLib/glTF2/glTF2Importer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index 165e02935..f609e36c7 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -1084,7 +1084,7 @@ struct AnimationSamplers { Animation::Sampler *weight; }; -aiNodeAnim *CreateNodeAnim(glTF2::Asset &r, Node &node, AnimationSamplers &samplers) { +aiNodeAnim *CreateNodeAnim(glTF2::Asset&, Node &node, AnimationSamplers &samplers) { aiNodeAnim *anim = new aiNodeAnim(); try { From b8bf1eac041f0bbb406019a28f310509dad51b86 Mon Sep 17 00:00:00 2001 From: Inho Lee Date: Mon, 7 Dec 2020 09:51:19 +0100 Subject: [PATCH 09/11] FBXConverter : Fix timescales of FBX animations FBX animations were recorded by framenumber, not by time. This patch will change it as a base of milliseconds. --- code/AssetLib/FBX/FBXConverter.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/code/AssetLib/FBX/FBXConverter.cpp b/code/AssetLib/FBX/FBXConverter.cpp index 1a484a38a..c27e48076 100644 --- a/code/AssetLib/FBX/FBXConverter.cpp +++ b/code/AssetLib/FBX/FBXConverter.cpp @@ -79,7 +79,7 @@ using namespace Util; #define MAGIC_NODE_TAG "_$AssimpFbx$" -#define CONVERT_FBX_TIME(time) static_cast(time) / 46186158000LL +#define CONVERT_FBX_TIME(time) (static_cast(time) * 1000.0 / 46186158000LL) FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBones) : defaultMaterialIndex(), @@ -2560,7 +2560,7 @@ void FBXConverter::ConvertAnimationStack(const AnimationStack &st) { meshMorphAnim->mKeys[j].mNumValuesAndWeights = numValuesAndWeights; meshMorphAnim->mKeys[j].mValues = new unsigned int[numValuesAndWeights]; meshMorphAnim->mKeys[j].mWeights = new double[numValuesAndWeights]; - meshMorphAnim->mKeys[j].mTime = CONVERT_FBX_TIME(animIt.first) * anim_fps; + meshMorphAnim->mKeys[j].mTime = CONVERT_FBX_TIME(animIt.first); for (unsigned int k = 0; k < numValuesAndWeights; k++) { meshMorphAnim->mKeys[j].mValues[k] = keyData->values.at(k); meshMorphAnim->mKeys[j].mWeights[k] = keyData->weights.at(k); @@ -2578,8 +2578,8 @@ void FBXConverter::ConvertAnimationStack(const AnimationStack &st) { return; } - double start_time_fps = has_local_startstop ? (CONVERT_FBX_TIME(start_time) * anim_fps) : min_time; - double stop_time_fps = has_local_startstop ? (CONVERT_FBX_TIME(stop_time) * anim_fps) : max_time; + double start_time_fps = has_local_startstop ? CONVERT_FBX_TIME(start_time) : min_time; + double stop_time_fps = has_local_startstop ? CONVERT_FBX_TIME(stop_time) : max_time; // adjust relative timing for animation for (unsigned int c = 0; c < anim->mNumChannels; c++) { @@ -3099,7 +3099,7 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name, InterpolateKeys(outTranslations, keytimes, keyframeLists[TransformationComp_Translation], defTranslate, maxTime, minTime); } else { for (size_t i = 0; i < keyCount; ++i) { - outTranslations[i].mTime = CONVERT_FBX_TIME(keytimes[i]) * anim_fps; + outTranslations[i].mTime = CONVERT_FBX_TIME(keytimes[i]); outTranslations[i].mValue = defTranslate; } } @@ -3108,7 +3108,7 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name, InterpolateKeys(outRotations, keytimes, keyframeLists[TransformationComp_Rotation], defRotation, maxTime, minTime, rotOrder); } else { for (size_t i = 0; i < keyCount; ++i) { - outRotations[i].mTime = CONVERT_FBX_TIME(keytimes[i]) * anim_fps; + outRotations[i].mTime = CONVERT_FBX_TIME(keytimes[i]); outRotations[i].mValue = defQuat; } } @@ -3117,7 +3117,7 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name, InterpolateKeys(outScales, keytimes, keyframeLists[TransformationComp_Scaling], defScale, maxTime, minTime); } else { for (size_t i = 0; i < keyCount; ++i) { - outScales[i].mTime = CONVERT_FBX_TIME(keytimes[i]) * anim_fps; + outScales[i].mTime = CONVERT_FBX_TIME(keytimes[i]); outScales[i].mValue = defScale; } } @@ -3306,7 +3306,7 @@ void FBXConverter::InterpolateKeys(aiVectorKey *valOut, const KeyTimeList &keys, } // magic value to convert fbx times to seconds - valOut->mTime = CONVERT_FBX_TIME(time) * anim_fps; + valOut->mTime = CONVERT_FBX_TIME(time); min_time = std::min(min_time, valOut->mTime); max_time = std::max(max_time, valOut->mTime); From 4e5b25cd81990003e2035d39e58e1df5629b403f Mon Sep 17 00:00:00 2001 From: Inho Lee Date: Wed, 16 Dec 2020 17:55:05 +0100 Subject: [PATCH 10/11] Keep AnimMesh data during the SortByPTypeProcess A Postprocessing step, SortByPTypeProcess, can rebuild Mesh data, but it does not handle AnimMesh. This patch helps to rebuild appropriate AnimMeshes for the Mesh. --- code/PostProcessing/SortByPTypeProcess.cpp | 64 ++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/code/PostProcessing/SortByPTypeProcess.cpp b/code/PostProcessing/SortByPTypeProcess.cpp index c4f9c7e4d..332d9d7ef 100644 --- a/code/PostProcessing/SortByPTypeProcess.cpp +++ b/code/PostProcessing/SortByPTypeProcess.cpp @@ -243,6 +243,45 @@ void SortByPTypeProcess::Execute(aiScene *pScene) { } } + if (mesh->mNumAnimMeshes > 0 && mesh->mAnimMeshes) { + out->mNumAnimMeshes = mesh->mNumAnimMeshes; + out->mAnimMeshes = new aiAnimMesh *[out->mNumAnimMeshes]; + } + + for (unsigned int j = 0; j < mesh->mNumAnimMeshes; ++j) { + aiAnimMesh *animMesh = mesh->mAnimMeshes[j]; + aiAnimMesh *outAnimMesh = out->mAnimMeshes[j] = new aiAnimMesh; + outAnimMesh->mNumVertices = out->mNumVertices; + if (animMesh->mVertices) + outAnimMesh->mVertices = new aiVector3D[out->mNumVertices]; + else + outAnimMesh->mVertices = nullptr; + if (animMesh->mNormals) + outAnimMesh->mNormals = new aiVector3D[out->mNumVertices]; + else + outAnimMesh->mNormals = nullptr; + if (animMesh->mTangents) + outAnimMesh->mTangents = new aiVector3D[out->mNumVertices]; + else + outAnimMesh->mTangents = nullptr; + if (animMesh->mBitangents) + outAnimMesh->mBitangents = new aiVector3D[out->mNumVertices]; + else + outAnimMesh->mBitangents = nullptr; + for (int jj = 0; jj < AI_MAX_NUMBER_OF_COLOR_SETS; ++jj) { + if (animMesh->mColors[jj]) + outAnimMesh->mColors[jj] = new aiColor4D[out->mNumVertices]; + else + outAnimMesh->mColors[jj] = nullptr; + } + for (int jj = 0; jj < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++jj) { + if (animMesh->mTextureCoords[jj]) + outAnimMesh->mTextureCoords[jj] = new aiVector3D[out->mNumVertices]; + else + outAnimMesh->mTextureCoords[jj] = nullptr; + } + } + typedef std::vector TempBoneInfo; std::vector tempBones(mesh->mNumBones); @@ -252,6 +291,7 @@ void SortByPTypeProcess::Execute(aiScene *pScene) { } unsigned int outIdx = 0; + unsigned int amIdx = 0; // AnimMesh index for (unsigned int m = 0; m < mesh->mNumFaces; ++m) { aiFace &in = mesh->mFaces[m]; if ((real == 3 && in.mNumIndices <= 3) || (real != 3 && in.mNumIndices != real + 1)) { @@ -293,6 +333,30 @@ void SortByPTypeProcess::Execute(aiScene *pScene) { *cols[pp]++ = mesh->mColors[pp][idx]; } + unsigned int pp = 0; + for (; pp < mesh->mNumAnimMeshes; ++pp) { + aiAnimMesh *animMesh = mesh->mAnimMeshes[pp]; + aiAnimMesh *outAnimMesh = out->mAnimMeshes[pp]; + if (animMesh->mVertices) + outAnimMesh->mVertices[amIdx] = animMesh->mVertices[idx]; + if (animMesh->mNormals) + outAnimMesh->mNormals[amIdx] = animMesh->mNormals[idx]; + if (animMesh->mTangents) + outAnimMesh->mTangents[amIdx] = animMesh->mTangents[idx]; + if (animMesh->mBitangents) + outAnimMesh->mBitangents[amIdx] = animMesh->mBitangents[idx]; + for (int jj = 0; jj < AI_MAX_NUMBER_OF_COLOR_SETS; ++jj) { + if (animMesh->mColors[jj]) + outAnimMesh->mColors[jj][amIdx] = animMesh->mColors[jj][idx]; + } + for (int jj = 0; jj < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++jj) { + if (animMesh->mTextureCoords[jj]) + outAnimMesh->mTextureCoords[jj][amIdx] = animMesh->mTextureCoords[jj][idx]; + } + } + if (pp == mesh->mNumAnimMeshes) + amIdx++; + in.mIndices[q] = outIdx++; } From 2873d862b0bfeb04a0b8f58ed516c51c2418366e Mon Sep 17 00:00:00 2001 From: Hugo Sales Date: Wed, 23 Dec 2020 15:44:37 +0000 Subject: [PATCH 11/11] Update CMakeLists.txt --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b739674af..e89e704f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #---------------------------------------------------------------------- +SET(CMAKE_POLICY_DEFAULT_CMP0012 NEW) SET(CMAKE_POLICY_DEFAULT_CMP0074 NEW) SET(CMAKE_POLICY_DEFAULT_CMP0092 NEW)