Merge branch 'alsed-prefab_skinned'

This commit is contained in:
2026-03-25 17:12:35 +01:00
2 changed files with 57 additions and 25 deletions
+44 -12
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"
@@ -82,6 +83,11 @@ bool ImportModel::TryGetImportOptions(const StringView& path, Options& options)
struct PrefabObject
{
enum
{
Model,
SkinnedModel,
} Type;
int32 NodeIndex;
String Name;
String AssetPath;
@@ -280,7 +286,7 @@ CreateAssetResult ImportModel::Import(CreateAssetContext& context)
options.SplitObjects = false;
options.ObjectIndex = -1;
// Import all of the objects recursive but use current model data to skip loading file again
// Import all the objects recursive but use current model data to skip loading file again
options.Cached = &cached;
HashSet<String> objectNames;
Function<bool(Options& splitOptions, const StringView& objectName, String& outputPath, MeshData* meshData)> splitImport = [&context, &autoImportOutput, &objectNames](Options& splitOptions, const StringView& objectName, String& outputPath, MeshData* meshData)
@@ -335,12 +341,24 @@ CreateAssetResult ImportModel::Import(CreateAssetContext& context)
auto& group = meshesByName[groupIndex];
// Cache object options (nested sub-object import removes the meshes)
prefabObject.NodeIndex = group.First()->NodeIndex;
prefabObject.Name = group.First()->Name;
MeshData* firstMesh = group.First();
prefabObject.NodeIndex = firstMesh->NodeIndex;
prefabObject.Name = firstMesh->Name;
splitOptions.Type = ModelTool::ModelType::Model;
// Detect model type
if ((firstMesh->BlendIndices.HasItems() && firstMesh->BlendWeights.HasItems()) || firstMesh->BlendShapes.HasItems())
{
splitOptions.Type = ModelTool::ModelType::SkinnedModel;
prefabObject.Type = PrefabObject::SkinnedModel;
}
else
{
splitOptions.Type = ModelTool::ModelType::Model;
prefabObject.Type = PrefabObject::Model;
}
splitOptions.ObjectIndex = groupIndex;
if (!splitImport(splitOptions, group.GetKey(), prefabObject.AssetPath, group.First()))
if (!splitImport(splitOptions, group.GetKey(), prefabObject.AssetPath, firstMesh))
{
prefabObjects.Add(prefabObject);
}
@@ -734,24 +752,38 @@ CreateAssetResult ImportModel::CreatePrefab(CreateAssetContext& context, const M
nodeActors.Clear();
for (const PrefabObject& e : prefabObjects)
{
if (e.NodeIndex == nodeIndex)
if (e.NodeIndex != nodeIndex)
continue;
Actor* a = nullptr;
switch (e.Type)
{
case PrefabObject::Model:
{
auto* actor = New<StaticModel>();
actor->SetName(e.Name);
if (auto* model = Content::LoadAsync<Model>(e.AssetPath))
{
actor->Model = model;
}
nodeActors.Add(actor);
a = actor;
break;
}
case PrefabObject::SkinnedModel:
{
auto* actor = New<AnimatedModel>();
if (auto* skinnedModel = Content::LoadAsync<SkinnedModel>(e.AssetPath))
actor->SkinnedModel = skinnedModel;
a = actor;
break;
}
default:
continue;
}
a->SetName(e.Name);
nodeActors.Add(a);
}
Actor* nodeActor = nodeActors.Count() == 1 ? nodeActors[0] : New<EmptyActor>();
if (nodeActors.Count() > 1)
{
for (Actor* e : nodeActors)
{
e->SetParent(nodeActor);
}
}
if (nodeActors.Count() != 1)
{
+13 -13
View File
@@ -1024,7 +1024,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 +1050,8 @@ 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];
@@ -1214,7 +1216,9 @@ 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 imported mesh has skeleton but no indices or weights then need to setup those (except in Prefab mode when we conditionally import meshes based on type)
if ((mesh->BlendIndices.IsEmpty() || mesh->BlendWeights.IsEmpty()) && data.Skeleton.Bones.HasItems() && (options.Type != ModelType::Prefab))
{
auto indices = Int4::Zero;
auto weights = Float4::UnitX;
@@ -2024,12 +2028,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 +2041,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 +2093,8 @@ 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