diff --git a/Source/Engine/ContentImporters/ImportModel.cpp b/Source/Engine/ContentImporters/ImportModel.cpp index f3548dc5c..5448fe8fb 100644 --- a/Source/Engine/ContentImporters/ImportModel.cpp +++ b/Source/Engine/ContentImporters/ImportModel.cpp @@ -19,6 +19,7 @@ #include "Engine/Animations/AnimEvent.h" #include "Engine/Level/Actors/EmptyActor.h" #include "Engine/Level/Actors/StaticModel.h" +#include "Engine/Level/Actors/AnimatedModel.h" #include "Engine/Level/Prefabs/Prefab.h" #include "Engine/Level/Prefabs/PrefabManager.h" #include "Engine/Level/Scripts/ModelPrefab.h" @@ -85,6 +86,7 @@ struct PrefabObject int32 NodeIndex; String Name; String AssetPath; + bool IsSkinned = false; }; void RepackMeshLightmapUVs(ModelData& data) @@ -327,8 +329,10 @@ CreateAssetResult ImportModel::Import(CreateAssetContext& context) return AssetsImportingManager::Import(context.InputPath, outputPath, &splitOptions); }; + auto splitOptions = options; LOG(Info, "Splitting imported {0} meshes", meshesByName.Count()); + PrefabObject prefabObject; for (int32 groupIndex = 0; groupIndex < meshesByName.Count(); groupIndex++) { @@ -338,7 +342,17 @@ CreateAssetResult ImportModel::Import(CreateAssetContext& context) prefabObject.NodeIndex = group.First()->NodeIndex; prefabObject.Name = group.First()->Name; + // Defaul value for ModelType splitOptions.Type = ModelTool::ModelType::Model; + + // Search for Skinned Model + if (group.First()->BlendWeights.HasItems() || group.First()->BlendShapes.HasItems() ) + { + LOG(Info, "Mesh {0} is Skinned", prefabObject.Name); + splitOptions.Type = ModelTool::ModelType::SkinnedModel; + prefabObject.IsSkinned = true; + } + splitOptions.ObjectIndex = groupIndex; if (!splitImport(splitOptions, group.GetKey(), prefabObject.AssetPath, group.First())) { @@ -736,22 +750,30 @@ CreateAssetResult ImportModel::CreatePrefab(CreateAssetContext& context, const M { if (e.NodeIndex == nodeIndex) { - auto* actor = New(); - actor->SetName(e.Name); - if (auto* model = Content::LoadAsync(e.AssetPath)) + if(e.IsSkinned) { - actor->Model = model; + LOG(Info,"Creating animated model prefab {0}.", e.Name); + auto* actor = New(); + actor->SetName(e.Name); + if (auto* skinnedModel = Content::LoadAsync(e.AssetPath)) + actor->SkinnedModel = skinnedModel; + nodeActors.Add(actor); + } + else + { + auto* actor = New(); + actor->SetName(e.Name); + if (auto* model = Content::LoadAsync(e.AssetPath)) + actor->Model = model; + nodeActors.Add(actor); } - nodeActors.Add(actor); } } Actor* nodeActor = nodeActors.Count() == 1 ? nodeActors[0] : New(); if (nodeActors.Count() > 1) { for (Actor* e : nodeActors) - { e->SetParent(nodeActor); - } } if (nodeActors.Count() != 1) { diff --git a/Source/Engine/Tools/ModelTool/ModelTool.Assimp.cpp b/Source/Engine/Tools/ModelTool/ModelTool.Assimp.cpp index b1340bfa7..b93220de4 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.Assimp.cpp +++ b/Source/Engine/Tools/ModelTool/ModelTool.Assimp.cpp @@ -786,7 +786,7 @@ bool ModelTool::ImportDataAssimp(const String& path, ModelData& data, Options& o } // Import skeleton - if (EnumHasAnyFlags(options.ImportTypes, ImportDataTypes::Skeleton)) + if (EnumHasAnyFlags(options.ImportTypes, ImportDataTypes::Skeleton) && context.Bones.HasItems()) { data.Skeleton.Nodes.Resize(context.Nodes.Count(), false); for (int32 i = 0; i < context.Nodes.Count(); i++) diff --git a/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp b/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp index 81ce46d6c..e530e7b7c 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp +++ b/Source/Engine/Tools/ModelTool/ModelTool.OpenFBX.cpp @@ -1404,7 +1404,7 @@ bool ModelTool::ImportDataOpenFBX(const String& path, ModelData& data, Options& } // Import skeleton - if (EnumHasAnyFlags(options.ImportTypes, ImportDataTypes::Skeleton)) + if (EnumHasAnyFlags(options.ImportTypes, ImportDataTypes::Skeleton) && context.Bones.HasItems()) { data.Skeleton.Nodes.Resize(context.Nodes.Count(), false); for (int32 i = 0; i < context.Nodes.Count(); i++) diff --git a/Source/Engine/Tools/ModelTool/ModelTool.cpp b/Source/Engine/Tools/ModelTool/ModelTool.cpp index 57afeb7a5..e15c45c5e 100644 --- a/Source/Engine/Tools/ModelTool/ModelTool.cpp +++ b/Source/Engine/Tools/ModelTool/ModelTool.cpp @@ -1012,6 +1012,12 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option options.ImportTypes |= ImportDataTypes::Textures; break; case ModelType::SkinnedModel: + if (!data.Skeleton.Bones.HasItems()) + { + LOG(Warning, "Model is not Skinned, it will be imported as Static"); + options.ImportTypes = ImportDataTypes::Geometry | ImportDataTypes::Nodes; + options.Type = ModelType::Model; + } options.ImportTypes = ImportDataTypes::Geometry | ImportDataTypes::Nodes | ImportDataTypes::Skeleton; if (options.ImportMaterials) options.ImportTypes |= ImportDataTypes::Materials; @@ -1024,7 +1030,7 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option options.ImportTypes |= ImportDataTypes::Skeleton; break; case ModelType::Prefab: - options.ImportTypes = ImportDataTypes::Geometry | ImportDataTypes::Nodes | ImportDataTypes::Animations; + options.ImportTypes = ImportDataTypes::Geometry | ImportDataTypes::Nodes | ImportDataTypes::Skeleton | ImportDataTypes::Animations; if (options.ImportMaterials) options.ImportTypes |= ImportDataTypes::Materials; if (options.ImportTextures) @@ -1050,6 +1056,9 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option { for (auto& mesh : lod.Meshes) { + if (mesh->BlendShapes.IsEmpty()) + continue; + for (int32 blendShapeIndex = mesh->BlendShapes.Count() - 1; blendShapeIndex >= 0; blendShapeIndex--) { auto& blendShape = mesh->BlendShapes[blendShapeIndex]; @@ -1074,7 +1083,8 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option } } } - if (EnumHasAnyFlags(options.ImportTypes, ImportDataTypes::Skeleton)) + if (EnumHasAnyFlags(options.ImportTypes, ImportDataTypes::Skeleton) + && (data.Skeleton.Bones.HasItems() || data.LODs[0].Meshes[0]->BlendShapes.HasItems())) { LOG(Info, "Imported skeleton has {0} bones and {1} nodes", data.Skeleton.Bones.Count(), data.Nodes.Count()); @@ -1214,7 +1224,7 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option for (int32 i = 0; i < meshesCount; i++) { const auto mesh = data.LODs[0].Meshes[i]; - if (mesh->BlendIndices.IsEmpty() || mesh->BlendWeights.IsEmpty()) + if ((mesh->BlendIndices.IsEmpty() || mesh->BlendWeights.IsEmpty()) && data.Skeleton.Bones.HasItems()) { auto indices = Int4::Zero; auto weights = Float4::UnitX; @@ -2024,12 +2034,11 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option #undef REMAP_VERTEX_BUFFER // Remap blend shapes - dstMesh->BlendShapes.Resize(srcMesh->BlendShapes.Count()); + dstMesh->BlendShapes.EnsureCapacity(srcMesh->BlendShapes.Count(), false); for (int32 blendShapeIndex = 0; blendShapeIndex < srcMesh->BlendShapes.Count(); blendShapeIndex++) { const auto& srcBlendShape = srcMesh->BlendShapes[blendShapeIndex]; - auto& dstBlendShape = dstMesh->BlendShapes[blendShapeIndex]; - + BlendShape dstBlendShape; dstBlendShape.Name = srcBlendShape.Name; dstBlendShape.Weight = srcBlendShape.Weight; dstBlendShape.Vertices.EnsureCapacity(srcBlendShape.Vertices.Count()); @@ -2038,17 +2047,12 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option auto v = srcBlendShape.Vertices[i]; v.VertexIndex = remap[v.VertexIndex]; if (v.VertexIndex != ~0u) - { dstBlendShape.Vertices.Add(v); - } } - } - // Remove empty blend shapes - for (int32 blendShapeIndex = dstMesh->BlendShapes.Count() - 1; blendShapeIndex >= 0; blendShapeIndex--) - { - if (dstMesh->BlendShapes[blendShapeIndex].Vertices.IsEmpty()) - dstMesh->BlendShapes.RemoveAt(blendShapeIndex); + // Add only valid blend shapes + if (dstBlendShape.Vertices.HasItems()) + dstMesh->BlendShapes.Add(dstBlendShape); } // Optimize generated LOD @@ -2095,6 +2099,9 @@ bool ModelTool::ImportModel(const String& path, ModelData& data, Options& option { for (auto& mesh : lod.Meshes) { + if (mesh->BlendShapes.IsEmpty()) + continue; + for (auto& blendShape : mesh->BlendShapes) { // Compute min/max for used vertex indices