Implement prefab detection of skinned models

This commit is contained in:
alsed
2025-08-30 08:51:21 -04:00
parent 4ca399af71
commit 9a363e2882
2 changed files with 47 additions and 16 deletions

View File

@@ -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"
@@ -84,6 +85,7 @@ struct PrefabObject
int32 NodeIndex;
String Name;
String AssetPath;
bool IsSkinned = false;
};
void RepackMeshLightmapUVs(ModelData& data)
@@ -320,8 +322,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++)
{
@@ -331,7 +335,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()->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()))
{
@@ -594,8 +608,8 @@ CreateAssetResult ImportModel::Create(CreateAssetContext& context)
CreateAssetResult ImportModel::CreateModel(CreateAssetContext& context, const ModelData& modelData, const Options* options)
{
PROFILE_CPU();
IMPORT_SETUP(Model, Model::SerializedVersion);
static_assert(Model::SerializedVersion == 30, "Update code.");
IMPORT_SETUP(Model, Model::SerializedVersion);
static_assert(Model::SerializedVersion == 30, "Update code.");
// Save model header
MemoryWriteStream stream(4096);
@@ -722,22 +736,30 @@ CreateAssetResult ImportModel::CreatePrefab(CreateAssetContext& context, const M
{
if (e.NodeIndex == nodeIndex)
{
auto* actor = New<StaticModel>();
actor->SetName(e.Name);
if (auto* model = Content::LoadAsync<Model>(e.AssetPath))
if(e.IsSkinned)
{
actor->Model = model;
LOG(Info,"Model {0} is Animated", e.Name);
auto* actor = New<AnimatedModel>();
actor->SetName(e.Name);
if (auto* skinnedModel = Content::LoadAsync<SkinnedModel>(e.AssetPath))
actor->SkinnedModel = skinnedModel;
nodeActors.Add(actor);
}
else
{
auto* actor = New<StaticModel>();
actor->SetName(e.Name);
if (auto* model = Content::LoadAsync<Model>(e.AssetPath))
actor->Model = model;
nodeActors.Add(actor);
}
nodeActors.Add(actor);
}
}
Actor* nodeActor = nodeActors.Count() == 1 ? nodeActors[0] : New<EmptyActor>();
if (nodeActors.Count() > 1)
{
for (Actor* e : nodeActors)
{
e->SetParent(nodeActor);
}
}
if (nodeActors.Count() != 1)
{

View File

@@ -1131,7 +1131,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)
@@ -1157,6 +1157,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];
@@ -2111,12 +2114,13 @@ 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.Clear();
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];
//auto& dstBlendShape = dstMesh->BlendShapes[blendShapeIndex];
BlendShape dstBlendShape;
dstBlendShape.Name = srcBlendShape.Name;
dstBlendShape.Weight = srcBlendShape.Weight;
dstBlendShape.Vertices.EnsureCapacity(srcBlendShape.Vertices.Count());
@@ -2125,19 +2129,21 @@ 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);
}
}
if (dstBlendShape.Vertices.HasItems())
dstMesh->BlendShapes.Add(dstBlendShape);
}
/*
// Remove empty blend shapes
for (int32 blendShapeIndex = dstMesh->BlendShapes.Count() - 1; blendShapeIndex >= 0; blendShapeIndex--)
{
if (dstMesh->BlendShapes[blendShapeIndex].Vertices.IsEmpty())
dstMesh->BlendShapes.RemoveAt(blendShapeIndex);
}
*/
// Optimize generated LOD
meshopt_optimizeVertexCache(dstMesh->Indices.Get(), dstMesh->Indices.Get(), dstMeshIndexCount, dstMeshVertexCount);
meshopt_optimizeOverdraw(dstMesh->Indices.Get(), dstMesh->Indices.Get(), dstMeshIndexCount, (const float*)dstMesh->Positions.Get(), dstMeshVertexCount, sizeof(Float3), 1.05f);
@@ -2182,6 +2188,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