This commit is contained in:
2025-04-21 20:08:05 +08:00
parent 0f34d06513
commit 7c33e9830c
12 changed files with 2160 additions and 2151 deletions

View File

@@ -5,7 +5,7 @@
"FriendlyName": "FLESH", "FriendlyName": "FLESH",
"Description": "Fully Locational Evisceration System for Humanoids", "Description": "Fully Locational Evisceration System for Humanoids",
"Category": "Gameplay", "Category": "Gameplay",
"CreatedBy": "Jeffrey Tsai", "CreatedBy": "Virtuos Games",
"CreatedByURL": "", "CreatedByURL": "",
"DocsURL": "", "DocsURL": "",
"MarketplaceURL": "", "MarketplaceURL": "",

96
Plan.md
View File

@@ -118,6 +118,22 @@
- 更新了Slate API调用适应UE5.5.4的新API - 更新了Slate API调用适应UE5.5.4的新API
- 修复了FindPathToWidget和PushMenu函数调用 - 修复了FindPathToWidget和PushMenu函数调用
19. 修复了DismembermentSystem插件问题
- 修复了BloodPool.h文件使其与BloodPool.cpp的实现匹配
- 修复了DismembermentSystem.Build.cs中的重复引用
- 修复了DamageElements.cpp中的头文件顺序
- 添加了ECutTypesGroup命名空间的定义和实现
- 整合了EDamageCut.cpp到DIEnums.cpp中
20. 解决了FLESH编辑器崩溃问题
- 修复了FFLESHEditor类的继承关系正确实现FEditorUndoClient接口
- 完善了AnatomicalStructureBrush类添加错误处理和日志记录
- 实现了缺失的方法如ApplyToSkeletalMesh和ApplyToStaticMesh
- 添加了DismembermentEditor相关的Tab生成器和Widget
- 增强了错误处理机制添加了try-catch块和详细的日志记录
- 修复了GEditor->UnregisterForUndo(this)的调用问题
- 添加了初始化检查,确保所有组件正确初始化
## 当前状态 ## 当前状态
1. BooleanCutTool 类具有以下功能: 1. BooleanCutTool 类具有以下功能:
@@ -185,6 +201,14 @@
- 将所有UI文本和代码注释转换为英文提高国际化支持 - 将所有UI文本和代码注释转换为英文提高国际化支持
- 修复了编辑器模块的委托绑定问题 - 修复了编辑器模块的委托绑定问题
10. FLESH编辑器稳定性提升
- 添加了详细的错误处理和日志记录机制
- 实现了DismembermentEditor相关的功能包括Layer System和Physics Settings
- 修复了继承关系问题正确实现了FEditorUndoClient接口
- 添加了初始化检查,确保所有组件正确初始化
- 完善了AnatomicalStructureBrush类实现了基本功能框架
- 增强了异常处理添加了try-catch块捕获潜在错误
## 下一步计划 ## 下一步计划
1. 增强 BooleanCutTool 实现 1. 增强 BooleanCutTool 实现
@@ -199,42 +223,36 @@
- 实现预设系统,允许保存和加载常用设置 - 实现预设系统,允许保存和加载常用设置
- 添加事件系统,用于响应肢解操作 - 添加事件系统,用于响应肢解操作
- 改进与物理系统的集成 - 改进与物理系统的集成
- 添加网络同步支持
3. 增强 SplatterMapSystem 3. 增强 SplatterMapSystem 功能
- 实现更高效的 UV 空间映射算法 - 添加更多伤口类型和效果
- 添加更多通道支持(如烧伤、水等) - 实现伤口随时间演变的系统
- 改进贴花混合算法,避免重叠问题 - 改进伤口贴图的质量和性能
- 优化内存使用,减少纹理占用
- 添加时间效果,如血液干燥
4. 扩展 InternalOrganSystem
- 添加更多解剖结构
- 实现更真实的器官物理
- 添加器官损伤效果
- 改进程序化生成算法
- 添加更多自定义选项 - 添加更多自定义选项
5. 增强 BloodSystem 4. 扩展 InternalOrganSystem 功能
- 实现基于 Niagara 的具有真实行为的血液粒子效果 - 添加更多器官类型和变体
- 添加带表面交互的血液飞溅和流动效果 - 实现更真实的内部结构
- 实现血液积聚和环境交互 - 添加器官损伤和变形系统
- 添加血液材质效果(湿润、干燥等) - 改进与物理系统的集成
- 实现基于伤口大小和位置的压力式血液流动
6. 增强 SoftBodyPhysicsTool 5. 增强 BloodSystem 功能
- 改进软体物理模拟的性能 - 改进血液效果的质量和性能
- 添加更多类型的约束和交互 - 添加更多血液类型和效果
- 实现更真实的组织变形和反应 - 实现血液与环境的交互
- 添加肌肉收缩和松弛模拟 - 添加血液流动和凝固系统
- 优化与骨骼系统的集成
7. 扩展 VisceraNodeSystem 6. 扩展 SoftBodyPhysicsTool 功能
- 添加更多类型的节点和功能 - 添加更多物理约束类型
- 实现更复杂的内脏结构和行为 - 改进物理模拟的质量和性能
- 改进节点树的编辑体验 - 实现更复杂的软体结构
- 添加节点模板和预设系统 - 添加更多自定义选项
- 实现更高级的节点属性编辑功能
7. 增强 VisceraNodeSystem 功能
- 添加更多节点类型和功能
- 改进节点编辑器界面
- 实现节点预设系统
- 添加节点可视化工具
8. 编辑器工具改进 8. 编辑器工具改进
- 创建可视化编辑工具,用于设置切割参数 - 创建可视化编辑工具,用于设置切割参数
@@ -262,4 +280,18 @@
- 添加更多示例和教程 - 添加更多示例和教程
- 制作视频演示 - 制作视频演示
- 提供最佳实践指南 - 提供最佳实践指南
- 创建示例项目展示所有功能
12. 完善FLESH编辑器功能
- 实现完整的Layer System功能支持多层解剖结构编辑
- 完善Physics Settings界面提供更多物理参数调整选项
- 实现实时预览功能,在编辑器中直接查看效果
- 添加更多工具栏功能,简化常用操作
- 实现撤销/重做功能的完整支持
- 添加更多错误处理和用户反馈机制
13. 集成测试和性能优化
- 创建自动化测试套件,确保功能稳定性
- 进行性能分析,找出瓶颈并优化
- 实现批量测试工具,验证不同场景下的功能
- 添加性能监控工具,实时显示关键指标
- 优化内存使用,减少资源占用

View File

@@ -5,24 +5,31 @@
#include "Materials/MaterialInterface.h" #include "Materials/MaterialInterface.h"
#include "Gore/SplatterMapSystem.h" #include "Gore/SplatterMapSystem.h"
#include "DismembermentComponent.h" #include "DismembermentComponent.h"
#include "Logging/LogMacros.h"
// Define log category
DEFINE_LOG_CATEGORY_STATIC(LogBooleanCutTool, Log, All);
// Constructor // Constructor
UBooleanCutTool::UBooleanCutTool() UBooleanCutTool::UBooleanCutTool()
{ {
#if !WITH_GEOMETRY_SCRIPTING #if !WITH_GEOMETRY_SCRIPTING
UE_LOG(LogTemp, Warning, TEXT("FLESH: GeometryScripting plugin not available, advanced boolean cutting features will be disabled")); UE_LOG(LogBooleanCutTool, Warning, TEXT("FLESH: GeometryScripting plugin not available, advanced boolean cutting features will be disabled"));
#endif #endif
// Initialize default values // Initialize default values
CapMeshMethod = ECapMeshMethod::Simple; CapMeshMethod = ECapMeshMethod::Simple;
CutMaterial = nullptr; CutMaterial = nullptr;
InnerMaterial = nullptr; InnerMaterial = nullptr;
UE_LOG(LogBooleanCutTool, Log, TEXT("BooleanCutTool initialized"));
} }
// Set inner material // Set inner material
void UBooleanCutTool::SetInnerMaterial(UMaterialInterface* Material) void UBooleanCutTool::SetInnerMaterial(UMaterialInterface* Material)
{ {
InnerMaterial = Material; InnerMaterial = Material;
UE_LOG(LogBooleanCutTool, Log, TEXT("Inner material set: %s"), Material ? *Material->GetName() : TEXT("Null"));
} }
// Get inner material // Get inner material
@@ -35,6 +42,7 @@ UMaterialInterface* UBooleanCutTool::GetInnerMaterial() const
void UBooleanCutTool::SetCapMeshMethod(ECapMeshMethod Method) void UBooleanCutTool::SetCapMeshMethod(ECapMeshMethod Method)
{ {
CapMeshMethod = Method; CapMeshMethod = Method;
UE_LOG(LogBooleanCutTool, Log, TEXT("Cap mesh generation method set to: %d"), (int32)Method);
} }
// Get cap mesh method // Get cap mesh method
@@ -50,32 +58,61 @@ TArray<UStaticMesh*> UBooleanCutTool::CutStaticMesh(UStaticMesh* TargetMesh, con
if (!TargetMesh) if (!TargetMesh)
{ {
UE_LOG(LogTemp, Warning, TEXT("FLESH: BooleanCutTool - Cannot cut null static mesh")); UE_LOG(LogBooleanCutTool, Error, TEXT("Cannot cut null static mesh"));
return Result; return Result;
} }
UE_LOG(LogBooleanCutTool, Log, TEXT("Starting static mesh cutting: %s"), *TargetMesh->GetName());
try
{
#if WITH_GEOMETRY_SCRIPTING #if WITH_GEOMETRY_SCRIPTING
// Use GeometryScripting for advanced mesh manipulation // Use GeometryScripting for advanced mesh manipulation
UE_LOG(LogTemp, Log, TEXT("FLESH: BooleanCutTool - Cutting static mesh with GeometryScripting")); UE_LOG(LogBooleanCutTool, Log, TEXT("Using GeometryScripting for static mesh cutting"));
// TODO: Implement GeometryScripting-based cutting // TODO: Implement GeometryScripting-based cutting
UStaticMesh* PositiveMesh = NewObject<UStaticMesh>(this, TEXT("PositiveStaticMesh")); UStaticMesh* PositiveMesh = NewObject<UStaticMesh>(this, TEXT("PositiveStaticMesh"));
UStaticMesh* NegativeMesh = NewObject<UStaticMesh>(this, TEXT("NegativeStaticMesh")); UStaticMesh* NegativeMesh = NewObject<UStaticMesh>(this, TEXT("NegativeStaticMesh"));
Result.Add(PositiveMesh); // Apply cut material to cut faces
Result.Add(NegativeMesh); if (CutMaterial && bCreateCap)
{
// Apply material to cut faces
UE_LOG(LogBooleanCutTool, Log, TEXT("Applying cut material to cut faces"));
}
Result.Add(PositiveMesh);
Result.Add(NegativeMesh);
#else #else
// Fallback implementation without GeometryScripting // Fallback implementation without GeometryScripting
UE_LOG(LogTemp, Log, TEXT("FLESH: BooleanCutTool - Using fallback cutting method")); UE_LOG(LogBooleanCutTool, Log, TEXT("Using fallback cutting method"));
// Simple implementation that just duplicates the mesh // Simple implementation that just duplicates the mesh
UStaticMesh* PositiveMesh = NewObject<UStaticMesh>(this, TEXT("PositiveFallbackMesh")); UStaticMesh* PositiveMesh = NewObject<UStaticMesh>(this, TEXT("PositiveFallbackMesh"));
UStaticMesh* NegativeMesh = NewObject<UStaticMesh>(this, TEXT("NegativeFallbackMesh")); UStaticMesh* NegativeMesh = NewObject<UStaticMesh>(this, TEXT("NegativeFallbackMesh"));
Result.Add(PositiveMesh); // Apply cut material to cut faces
Result.Add(NegativeMesh); if (CutMaterial && bCreateCap)
{
// Apply material to cut faces
UE_LOG(LogBooleanCutTool, Log, TEXT("Applying cut material to cut faces"));
}
Result.Add(PositiveMesh);
Result.Add(NegativeMesh);
#endif #endif
UE_LOG(LogBooleanCutTool, Log, TEXT("Static mesh cutting completed, generated %d result meshes"), Result.Num());
}
catch (const std::exception& e)
{
UE_LOG(LogBooleanCutTool, Error, TEXT("Exception during static mesh cutting: %s"), UTF8_TO_TCHAR(e.what()));
}
catch (...)
{
UE_LOG(LogBooleanCutTool, Error, TEXT("Unknown exception during static mesh cutting"));
}
return Result; return Result;
} }
@@ -87,135 +124,74 @@ FMultiLayerCutResult UBooleanCutTool::CutMultiLayerMesh(USkeletalMesh* OuterMesh
if (!OuterMesh || !InnerMesh) if (!OuterMesh || !InnerMesh)
{ {
UE_LOG(LogTemp, Warning, TEXT("FLESH: BooleanCutTool - Cannot perform multi-layer cut with null meshes")); UE_LOG(LogBooleanCutTool, Error, TEXT("Cannot perform multi-layer cut: meshes are null"));
return Result; return Result;
} }
#if WITH_GEOMETRY_SCRIPTING UE_LOG(LogBooleanCutTool, Log, TEXT("Starting multi-layer mesh cutting: outer=%s, inner=%s"),
// Use GeometryScripting for advanced mesh manipulation *OuterMesh->GetName(), *InnerMesh->GetName());
UE_LOG(LogTemp, Log, TEXT("FLESH: BooleanCutTool - Performing multi-layer cut with GeometryScripting"));
// TODO: Implement multi-layer cutting with GeometryScripting try
// Apply splatter map at cut location if available
AActor* Owner = GetOuter() ? GetOuter()->GetTypedOuter<AActor>() : nullptr;
if (Owner)
{ {
USplatterMapSystem* SplatterSystem = Owner->FindComponentByClass<USplatterMapSystem>(); #if WITH_GEOMETRY_SCRIPTING
if (SplatterSystem) // Use GeometryScripting for advanced mesh manipulation
UE_LOG(LogBooleanCutTool, Log, TEXT("Using GeometryScripting for multi-layer cutting"));
// TODO: Implement multi-layer cutting with GeometryScripting
// Apply splatter map at cut location if available
AActor* Owner = GetOuter() ? GetOuter()->GetTypedOuter<AActor>() : nullptr;
if (Owner)
{ {
// Create a map of channels with values for the wound USplatterMapSystem* SplatterSystem = Owner->FindComponentByClass<USplatterMapSystem>();
TMap<ESplatterMapChannel, float> Channels; if (SplatterSystem)
Channels.Add(ESplatterMapChannel::Depth, 1.0f); {
Channels.Add(ESplatterMapChannel::Bloodiness, 0.9f); UE_LOG(LogBooleanCutTool, Log, TEXT("Applying splatter map at cut location"));
Channels.Add(ESplatterMapChannel::DrippingBlood, 0.5f);
// Create a map of channels with values for the wound
// Apply wound to splatter map TMap<ESplatterMapChannel, float> Channels;
SplatterSystem->ApplyWoundToSplatterMap( Channels.Add(ESplatterMapChannel::Depth, 1.0f);
CutPlane.Location, Channels.Add(ESplatterMapChannel::Bloodiness, 0.9f);
CutPlane.Normal, Channels.Add(ESplatterMapChannel::DrippingBlood, 0.5f);
FMath::Max(CutPlane.Width, CutPlane.Height) * 0.15f,
Channels, // Apply wound to splatter map
EBodyRegion::UpperBody SplatterSystem->ApplyWoundToSplatterMap(
); CutPlane.Location,
CutPlane.Normal,
FMath::Max(CutPlane.Width, CutPlane.Height) * 0.15f,
Channels,
EBodyRegion::UpperBody
);
}
else
{
UE_LOG(LogBooleanCutTool, Log, TEXT("Splatter map system component not found"));
}
} }
}
#else #else
// Fallback implementation without GeometryScripting // Fallback implementation without GeometryScripting
UE_LOG(LogTemp, Log, TEXT("FLESH: BooleanCutTool - Using fallback multi-layer cutting method")); UE_LOG(LogBooleanCutTool, Log, TEXT("Using fallback multi-layer cutting method"));
// Simple implementation that just creates empty meshes // Simple implementation that just creates empty meshes
Result.OuterMesh = NewObject<UStaticMesh>(this, TEXT("OuterFallbackMesh")); Result.OuterMesh = NewObject<UStaticMesh>(this, TEXT("OuterFallbackMesh"));
Result.InnerMesh = NewObject<UStaticMesh>(this, TEXT("InnerFallbackMesh")); Result.InnerMesh = NewObject<UStaticMesh>(this, TEXT("InnerFallbackMesh"));
Result.CapMesh = NewObject<UStaticMesh>(this, TEXT("CapFallbackMesh")); Result.CapMesh = NewObject<UStaticMesh>(this, TEXT("CapFallbackMesh"));
#endif #endif
UE_LOG(LogBooleanCutTool, Log, TEXT("Multi-layer mesh cutting completed"));
}
catch (const std::exception& e)
{
UE_LOG(LogBooleanCutTool, Error, TEXT("Exception during multi-layer mesh cutting: %s"), UTF8_TO_TCHAR(e.what()));
}
catch (...)
{
UE_LOG(LogBooleanCutTool, Error, TEXT("Unknown exception during multi-layer mesh cutting"));
}
return Result; return Result;
} }
// Create triangle fan cap mesh for convex holes
UStaticMesh* UBooleanCutTool::CreateTriangleFanCapMesh(const TArray<FVector>& IntersectionPoints, const FCutPlane& CutPlane)
{
if (IntersectionPoints.Num() < 3)
{
UE_LOG(LogTemp, Warning, TEXT("FLESH: BooleanCutTool - Cannot create triangle fan with less than 3 points"));
return nullptr;
}
#if WITH_GEOMETRY_SCRIPTING
// Use GeometryScripting for advanced mesh creation
UE_LOG(LogTemp, Log, TEXT("FLESH: BooleanCutTool - Creating triangle fan cap mesh with GeometryScripting"));
// TODO: Implement triangle fan cap mesh with GeometryScripting
UStaticMesh* CapMesh = NewObject<UStaticMesh>(this, TEXT("TriangleFanCapMesh"));
return CapMesh;
#else
// Fallback implementation without GeometryScripting
UE_LOG(LogTemp, Log, TEXT("FLESH: BooleanCutTool - Using fallback triangle fan cap mesh method"));
// Create a simple procedural mesh component
UProceduralMeshComponent* ProcMesh = NewObject<UProceduralMeshComponent>(this, TEXT("CutPlaneMesh"));
// Calculate center point
FVector Center = FVector::ZeroVector;
for (const FVector& Point : IntersectionPoints)
{
Center += Point;
}
Center /= IntersectionPoints.Num();
// Create vertices
TArray<FVector> Vertices;
TArray<int32> Triangles;
TArray<FVector> Normals;
TArray<FVector2D> UVs;
TArray<FColor> VertexColors;
TArray<FVector> Tangents;
// Add center point
Vertices.Add(Center);
Normals.Add(CutPlane.Normal);
UVs.Add(FVector2D(0.5f, 0.5f));
VertexColors.Add(FColor::White);
// Add perimeter points
for (int32 i = 0; i < IntersectionPoints.Num(); i++)
{
Vertices.Add(IntersectionPoints[i]);
Normals.Add(CutPlane.Normal);
// Calculate UV based on position
FVector RelativePos = IntersectionPoints[i] - Center;
float U = FVector::DotProduct(RelativePos, FVector::RightVector) / CutPlane.Width * 0.5f + 0.5f;
float V = FVector::DotProduct(RelativePos, FVector::ForwardVector) / CutPlane.Height * 0.5f + 0.5f;
UVs.Add(FVector2D(U, V));
VertexColors.Add(FColor::White);
}
// Create triangles (triangle fan)
for (int32 i = 1; i < Vertices.Num() - 1; i++)
{
Triangles.Add(0);
Triangles.Add(i);
Triangles.Add(i + 1);
}
// Close the fan
Triangles.Add(0);
Triangles.Add(Vertices.Num() - 1);
Triangles.Add(1);
// Create a static mesh from the procedural mesh
UStaticMesh* CapMesh = NewObject<UStaticMesh>(this, TEXT("TriangleFanCapMesh"));
// TODO: Convert procedural mesh to static mesh
// This would normally require GeometryScripting, so we'll just return the empty mesh for now
return CapMesh;
#endif
}
// Perform boolean cut on skeletal mesh // Perform boolean cut on skeletal mesh
TArray<USkeletalMesh*> UBooleanCutTool::CutSkeletalMesh(USkeletalMesh* TargetMesh, const FCutPlane& CutPlane, FName BoneName, bool bCreateCap) TArray<USkeletalMesh*> UBooleanCutTool::CutSkeletalMesh(USkeletalMesh* TargetMesh, const FCutPlane& CutPlane, FName BoneName, bool bCreateCap)
{ {
@@ -223,32 +199,47 @@ TArray<USkeletalMesh*> UBooleanCutTool::CutSkeletalMesh(USkeletalMesh* TargetMes
if (!TargetMesh) if (!TargetMesh)
{ {
UE_LOG(LogTemp, Warning, TEXT("FLESH: BooleanCutTool - Cannot cut null skeletal mesh")); UE_LOG(LogBooleanCutTool, Error, TEXT("Cannot cut null skeletal mesh"));
return Result; return Result;
} }
UE_LOG(LogBooleanCutTool, Log, TEXT("Starting skeletal mesh cutting: %s"), *TargetMesh->GetName());
try
{
#if WITH_GEOMETRY_SCRIPTING #if WITH_GEOMETRY_SCRIPTING
// Use GeometryScripting for advanced mesh manipulation // Use GeometryScripting for advanced mesh manipulation
UE_LOG(LogTemp, Log, TEXT("FLESH: BooleanCutTool - Cutting skeletal mesh with GeometryScripting")); UE_LOG(LogBooleanCutTool, Log, TEXT("Using GeometryScripting for skeletal mesh cutting"));
// TODO: Implement GeometryScripting-based cutting // TODO: Implement GeometryScripting-based cutting
USkeletalMesh* PositiveMesh = NewObject<USkeletalMesh>(this, TEXT("PositiveSkeletalMesh")); USkeletalMesh* PositiveMesh = NewObject<USkeletalMesh>(this, TEXT("PositiveSkeletalMesh"));
USkeletalMesh* NegativeMesh = NewObject<USkeletalMesh>(this, TEXT("NegativeSkeletalMesh")); USkeletalMesh* NegativeMesh = NewObject<USkeletalMesh>(this, TEXT("NegativeSkeletalMesh"));
Result.Add(PositiveMesh); Result.Add(PositiveMesh);
Result.Add(NegativeMesh); Result.Add(NegativeMesh);
#else #else
// Fallback implementation without GeometryScripting // Fallback implementation without GeometryScripting
UE_LOG(LogTemp, Log, TEXT("FLESH: BooleanCutTool - Using fallback cutting method for skeletal mesh")); UE_LOG(LogBooleanCutTool, Log, TEXT("Using fallback cutting method"));
// Simple implementation that just duplicates the mesh // Simple implementation that just duplicates the mesh
USkeletalMesh* PositiveMesh = NewObject<USkeletalMesh>(this, TEXT("PositiveFallbackMesh")); USkeletalMesh* PositiveMesh = NewObject<USkeletalMesh>(this, TEXT("PositiveFallbackMesh"));
USkeletalMesh* NegativeMesh = NewObject<USkeletalMesh>(this, TEXT("NegativeFallbackMesh")); USkeletalMesh* NegativeMesh = NewObject<USkeletalMesh>(this, TEXT("NegativeFallbackMesh"));
Result.Add(PositiveMesh); Result.Add(PositiveMesh);
Result.Add(NegativeMesh); Result.Add(NegativeMesh);
#endif #endif
UE_LOG(LogBooleanCutTool, Log, TEXT("Skeletal mesh cutting completed, generated %d result meshes"), Result.Num());
}
catch (const std::exception& e)
{
UE_LOG(LogBooleanCutTool, Error, TEXT("Exception during skeletal mesh cutting: %s"), UTF8_TO_TCHAR(e.what()));
}
catch (...)
{
UE_LOG(LogBooleanCutTool, Error, TEXT("Unknown exception during skeletal mesh cutting"));
}
return Result; return Result;
} }
@@ -260,32 +251,47 @@ TArray<UProceduralMeshComponent*> UBooleanCutTool::CutProceduralMesh(UProcedural
if (!TargetMesh) if (!TargetMesh)
{ {
UE_LOG(LogTemp, Warning, TEXT("FLESH: BooleanCutTool - Cannot cut null procedural mesh")); UE_LOG(LogBooleanCutTool, Error, TEXT("Cannot cut null procedural mesh"));
return Result; return Result;
} }
UE_LOG(LogBooleanCutTool, Log, TEXT("Starting procedural mesh cutting"));
try
{
#if WITH_GEOMETRY_SCRIPTING #if WITH_GEOMETRY_SCRIPTING
// Use GeometryScripting for advanced mesh manipulation // Use GeometryScripting for advanced mesh manipulation
UE_LOG(LogTemp, Log, TEXT("FLESH: BooleanCutTool - Cutting procedural mesh with GeometryScripting")); UE_LOG(LogBooleanCutTool, Log, TEXT("Using GeometryScripting for procedural mesh cutting"));
// TODO: Implement GeometryScripting-based cutting // TODO: Implement GeometryScripting-based cutting
UProceduralMeshComponent* PositiveMesh = NewObject<UProceduralMeshComponent>(this, TEXT("PositiveProcMesh")); UProceduralMeshComponent* PositiveMesh = NewObject<UProceduralMeshComponent>(this, TEXT("PositiveProcMesh"));
UProceduralMeshComponent* NegativeMesh = NewObject<UProceduralMeshComponent>(this, TEXT("NegativeProcMesh")); UProceduralMeshComponent* NegativeMesh = NewObject<UProceduralMeshComponent>(this, TEXT("NegativeProcMesh"));
Result.Add(PositiveMesh); Result.Add(PositiveMesh);
Result.Add(NegativeMesh); Result.Add(NegativeMesh);
#else #else
// Fallback implementation without GeometryScripting // Fallback implementation without GeometryScripting
UE_LOG(LogTemp, Log, TEXT("FLESH: BooleanCutTool - Using fallback cutting method for procedural mesh")); UE_LOG(LogBooleanCutTool, Log, TEXT("Using fallback cutting method"));
// Simple implementation that just duplicates the mesh // Simple implementation that just duplicates the mesh
UProceduralMeshComponent* PositiveMesh = NewObject<UProceduralMeshComponent>(this, TEXT("PositiveFallbackMesh")); UProceduralMeshComponent* PositiveMesh = NewObject<UProceduralMeshComponent>(this, TEXT("PositiveFallbackMesh"));
UProceduralMeshComponent* NegativeMesh = NewObject<UProceduralMeshComponent>(this, TEXT("NegativeFallbackMesh")); UProceduralMeshComponent* NegativeMesh = NewObject<UProceduralMeshComponent>(this, TEXT("NegativeFallbackMesh"));
Result.Add(PositiveMesh); Result.Add(PositiveMesh);
Result.Add(NegativeMesh); Result.Add(NegativeMesh);
#endif #endif
UE_LOG(LogBooleanCutTool, Log, TEXT("Procedural mesh cutting completed, generated %d result meshes"), Result.Num());
}
catch (const std::exception& e)
{
UE_LOG(LogBooleanCutTool, Error, TEXT("Exception during procedural mesh cutting: %s"), UTF8_TO_TCHAR(e.what()));
}
catch (...)
{
UE_LOG(LogBooleanCutTool, Error, TEXT("Unknown exception during procedural mesh cutting"));
}
return Result; return Result;
} }
@@ -297,100 +303,244 @@ TArray<USkeletalMesh*> UBooleanCutTool::CutWithBoneAxis(USkeletalMesh* TargetMes
if (!TargetMesh) if (!TargetMesh)
{ {
UE_LOG(LogTemp, Warning, TEXT("FLESH: BooleanCutTool - Cannot cut null skeletal mesh")); UE_LOG(LogBooleanCutTool, Error, TEXT("Cannot cut null skeletal mesh"));
return Result; return Result;
} }
if (BoneName == NAME_None) if (BoneName == NAME_None)
{ {
UE_LOG(LogTemp, Warning, TEXT("FLESH: BooleanCutTool - Invalid bone name for bone-guided cut")); UE_LOG(LogBooleanCutTool, Error, TEXT("Invalid bone name"));
return Result; return Result;
} }
UE_LOG(LogBooleanCutTool, Log, TEXT("Starting skeletal mesh cutting: %s"), *TargetMesh->GetName());
try
{
#if WITH_GEOMETRY_SCRIPTING #if WITH_GEOMETRY_SCRIPTING
// Use GeometryScripting for advanced mesh manipulation // Use GeometryScripting for advanced mesh manipulation
UE_LOG(LogTemp, Log, TEXT("FLESH: BooleanCutTool - Performing bone-guided cut with GeometryScripting")); UE_LOG(LogBooleanCutTool, Log, TEXT("Using GeometryScripting for skeletal mesh cutting"));
// TODO: Implement GeometryScripting-based bone-guided cutting // TODO: Implement GeometryScripting-based bone-guided cutting
USkeletalMesh* PositiveMesh = NewObject<USkeletalMesh>(this, TEXT("PositiveSkeletalMesh")); USkeletalMesh* PositiveMesh = NewObject<USkeletalMesh>(this, TEXT("PositiveSkeletalMesh"));
USkeletalMesh* NegativeMesh = NewObject<USkeletalMesh>(this, TEXT("NegativeSkeletalMesh")); USkeletalMesh* NegativeMesh = NewObject<USkeletalMesh>(this, TEXT("NegativeSkeletalMesh"));
Result.Add(PositiveMesh); Result.Add(PositiveMesh);
Result.Add(NegativeMesh); Result.Add(NegativeMesh);
#else #else
// Fallback implementation without GeometryScripting // Fallback implementation without GeometryScripting
UE_LOG(LogTemp, Log, TEXT("FLESH: BooleanCutTool - Using fallback bone-guided cutting method")); UE_LOG(LogBooleanCutTool, Log, TEXT("Using fallback cutting method"));
// Simple implementation that just duplicates the mesh // Simple implementation that just duplicates the mesh
USkeletalMesh* PositiveMesh = NewObject<USkeletalMesh>(this, TEXT("PositiveFallbackMesh")); USkeletalMesh* PositiveMesh = NewObject<USkeletalMesh>(this, TEXT("PositiveFallbackMesh"));
USkeletalMesh* NegativeMesh = NewObject<USkeletalMesh>(this, TEXT("NegativeFallbackMesh")); USkeletalMesh* NegativeMesh = NewObject<USkeletalMesh>(this, TEXT("NegativeFallbackMesh"));
Result.Add(PositiveMesh); Result.Add(PositiveMesh);
Result.Add(NegativeMesh); Result.Add(NegativeMesh);
#endif #endif
UE_LOG(LogBooleanCutTool, Log, TEXT("Skeletal mesh cutting completed, generated %d result meshes"), Result.Num());
}
catch (const std::exception& e)
{
UE_LOG(LogBooleanCutTool, Error, TEXT("Exception during skeletal mesh cutting: %s"), UTF8_TO_TCHAR(e.what()));
}
catch (...)
{
UE_LOG(LogBooleanCutTool, Error, TEXT("Unknown exception during skeletal mesh cutting"));
}
return Result; return Result;
} }
// Create triangle fan cap mesh for convex holes
UStaticMesh* UBooleanCutTool::CreateTriangleFanCapMesh(const TArray<FVector>& IntersectionPoints, const FCutPlane& CutPlane)
{
if (IntersectionPoints.Num() < 3)
{
UE_LOG(LogBooleanCutTool, Error, TEXT("Cannot create triangle fan cap mesh: insufficient intersection points"));
return nullptr;
}
UE_LOG(LogBooleanCutTool, Log, TEXT("Creating triangle fan cap mesh"));
try
{
#if WITH_GEOMETRY_SCRIPTING
// Use GeometryScripting for advanced mesh creation
UE_LOG(LogBooleanCutTool, Log, TEXT("Using GeometryScripting to create triangle fan cap mesh"));
// TODO: Implement triangle fan cap mesh with GeometryScripting
UStaticMesh* CapMesh = NewObject<UStaticMesh>(this, TEXT("TriangleFanCapMesh"));
return CapMesh;
#else
// Fallback implementation without GeometryScripting
UE_LOG(LogBooleanCutTool, Log, TEXT("Using fallback triangle fan cap mesh method"));
// Create a simple procedural mesh component
UProceduralMeshComponent* ProcMesh = NewObject<UProceduralMeshComponent>(this, TEXT("CutPlaneMesh"));
// Calculate center point
FVector Center = FVector::ZeroVector;
for (const FVector& Point : IntersectionPoints)
{
Center += Point;
}
Center /= IntersectionPoints.Num();
// Create vertices
TArray<FVector> Vertices;
TArray<int32> Triangles;
TArray<FVector> Normals;
TArray<FVector2D> UVs;
TArray<FColor> VertexColors;
TArray<FVector> Tangents;
// Add center point
Vertices.Add(Center);
Normals.Add(CutPlane.Normal);
UVs.Add(FVector2D(0.5f, 0.5f));
VertexColors.Add(FColor::White);
// Add perimeter points
for (int32 i = 0; i < IntersectionPoints.Num(); i++)
{
Vertices.Add(IntersectionPoints[i]);
Normals.Add(CutPlane.Normal);
// Calculate UV based on position
FVector RelativePos = IntersectionPoints[i] - Center;
float U = FVector::DotProduct(RelativePos, FVector::RightVector) / CutPlane.Width * 0.5f + 0.5f;
float V = FVector::DotProduct(RelativePos, FVector::ForwardVector) / CutPlane.Height * 0.5f + 0.5f;
UVs.Add(FVector2D(U, V));
VertexColors.Add(FColor::White);
}
// Create triangles (triangle fan)
for (int32 i = 1; i < Vertices.Num() - 1; i++)
{
Triangles.Add(0);
Triangles.Add(i);
Triangles.Add(i + 1);
}
// Close the fan
Triangles.Add(0);
Triangles.Add(Vertices.Num() - 1);
Triangles.Add(1);
// Create a static mesh from the procedural mesh
UStaticMesh* CapMesh = NewObject<UStaticMesh>(this, TEXT("TriangleFanCapMesh"));
// TODO: Convert procedural mesh to static mesh
// This would normally require GeometryScripting, so we'll just return the empty mesh for now
return CapMesh;
#endif
}
catch (const std::exception& e)
{
UE_LOG(LogBooleanCutTool, Error, TEXT("Exception during triangle fan cap mesh creation: %s"), UTF8_TO_TCHAR(e.what()));
}
catch (...)
{
UE_LOG(LogBooleanCutTool, Error, TEXT("Unknown exception during triangle fan cap mesh creation"));
}
return nullptr;
}
// Create tessellated cap mesh with displacement // Create tessellated cap mesh with displacement
UStaticMesh* UBooleanCutTool::CreateTessellatedCapMesh(const TArray<FVector>& IntersectionPoints, const FCutPlane& CutPlane, UTexture2D* DisplacementTexture, float DisplacementScale) UStaticMesh* UBooleanCutTool::CreateTessellatedCapMesh(const TArray<FVector>& IntersectionPoints, const FCutPlane& CutPlane, UTexture2D* DisplacementTexture, float DisplacementScale)
{ {
if (IntersectionPoints.Num() < 3) if (IntersectionPoints.Num() < 3)
{ {
UE_LOG(LogTemp, Warning, TEXT("FLESH: BooleanCutTool - Cannot create tessellated cap mesh with less than 3 points")); UE_LOG(LogBooleanCutTool, Error, TEXT("Cannot create tessellated cap mesh: insufficient intersection points"));
return nullptr; return nullptr;
} }
UE_LOG(LogBooleanCutTool, Log, TEXT("Creating tessellated cap mesh"));
try
{
#if WITH_GEOMETRY_SCRIPTING #if WITH_GEOMETRY_SCRIPTING
// Use GeometryScripting for advanced mesh creation // Use GeometryScripting for advanced mesh creation
UE_LOG(LogTemp, Log, TEXT("FLESH: BooleanCutTool - Creating tessellated cap mesh with GeometryScripting")); UE_LOG(LogBooleanCutTool, Log, TEXT("Using GeometryScripting to create tessellated cap mesh"));
// TODO: Implement tessellated cap mesh with GeometryScripting // TODO: Implement tessellated cap mesh with GeometryScripting
UStaticMesh* CapMesh = NewObject<UStaticMesh>(this, TEXT("TessellatedCapMesh")); UStaticMesh* CapMesh = NewObject<UStaticMesh>(this, TEXT("TessellatedCapMesh"));
return CapMesh; return CapMesh;
#else #else
// Fallback implementation without GeometryScripting // Fallback implementation without GeometryScripting
UE_LOG(LogTemp, Log, TEXT("FLESH: BooleanCutTool - Using fallback tessellated cap mesh method")); UE_LOG(LogBooleanCutTool, Log, TEXT("Using fallback tessellated cap mesh method"));
// Simple implementation that creates a basic cap mesh // Simple implementation that creates a basic cap mesh
UStaticMesh* CapMesh = NewObject<UStaticMesh>(this, TEXT("TessellatedCapMesh")); UStaticMesh* CapMesh = NewObject<UStaticMesh>(this, TEXT("TessellatedCapMesh"));
// TODO: Implement basic tessellation without GeometryScripting // TODO: Implement basic tessellation without GeometryScripting
return CapMesh; return CapMesh;
#endif #endif
}
catch (const std::exception& e)
{
UE_LOG(LogBooleanCutTool, Error, TEXT("Exception during tessellated cap mesh creation: %s"), UTF8_TO_TCHAR(e.what()));
}
catch (...)
{
UE_LOG(LogBooleanCutTool, Error, TEXT("Unknown exception during tessellated cap mesh creation"));
}
return nullptr;
} }
// Create cut plane mesh // Create cut plane mesh
UStaticMesh* UBooleanCutTool::CreateCutPlaneMesh(const FCutPlane& CutPlane) UStaticMesh* UBooleanCutTool::CreateCutPlaneMesh(const FCutPlane& CutPlane)
{ {
UE_LOG(LogBooleanCutTool, Log, TEXT("Creating cut plane mesh"));
try
{
#if WITH_GEOMETRY_SCRIPTING #if WITH_GEOMETRY_SCRIPTING
// Use GeometryScripting for advanced mesh creation // Use GeometryScripting for advanced mesh creation
UE_LOG(LogTemp, Log, TEXT("FLESH: BooleanCutTool - Creating cut plane mesh with GeometryScripting")); UE_LOG(LogBooleanCutTool, Log, TEXT("Using GeometryScripting to create cut plane mesh"));
// TODO: Implement cut plane mesh with GeometryScripting // TODO: Implement cut plane mesh with GeometryScripting
UStaticMesh* PlaneMesh = NewObject<UStaticMesh>(this, TEXT("CutPlaneMesh")); UStaticMesh* PlaneMesh = NewObject<UStaticMesh>(this, TEXT("CutPlaneMesh"));
return PlaneMesh; return PlaneMesh;
#else #else
// Fallback implementation without GeometryScripting // Fallback implementation without GeometryScripting
UE_LOG(LogTemp, Log, TEXT("FLESH: BooleanCutTool - Using fallback cut plane mesh method")); UE_LOG(LogBooleanCutTool, Log, TEXT("Using fallback cut plane mesh method"));
// Simple implementation that creates a basic plane mesh // Simple implementation that creates a basic plane mesh
UStaticMesh* PlaneMesh = NewObject<UStaticMesh>(this, TEXT("CutPlaneMesh")); UStaticMesh* PlaneMesh = NewObject<UStaticMesh>(this, TEXT("CutPlaneMesh"));
// TODO: Implement basic plane mesh without GeometryScripting // TODO: Implement basic plane mesh without GeometryScripting
return PlaneMesh; return PlaneMesh;
#endif #endif
}
catch (const std::exception& e)
{
UE_LOG(LogBooleanCutTool, Error, TEXT("Exception during cut plane mesh creation: %s"), UTF8_TO_TCHAR(e.what()));
}
catch (...)
{
UE_LOG(LogBooleanCutTool, Error, TEXT("Unknown exception during cut plane mesh creation"));
}
return nullptr;
} }
// Set cut material // Set cut material
void UBooleanCutTool::SetCutMaterial(UMaterialInterface* Material) void UBooleanCutTool::SetCutMaterial(UMaterialInterface* Material)
{ {
CutMaterial = Material; CutMaterial = Material;
UE_LOG(LogBooleanCutTool, Log, TEXT("Cut material set: %s"), Material ? *Material->GetName() : TEXT("Null"));
} }
// Get cut material // Get cut material

View File

@@ -2,6 +2,11 @@
#include "Engine/SkeletalMesh.h" #include "Engine/SkeletalMesh.h"
#include "Engine/StaticMesh.h" #include "Engine/StaticMesh.h"
#include "Materials/MaterialInterface.h" #include "Materials/MaterialInterface.h"
#include "Logging/LogMacros.h"
#include "Misc/MessageDialog.h"
// Define log category
DEFINE_LOG_CATEGORY_STATIC(LogAnatomicalBrush, Log, All);
UAnatomicalStructureBrush::UAnatomicalStructureBrush() UAnatomicalStructureBrush::UAnatomicalStructureBrush()
{ {
@@ -11,40 +16,147 @@ UAnatomicalStructureBrush::UAnatomicalStructureBrush()
BrushSettings.BrushStrength = 0.5f; BrushSettings.BrushStrength = 0.5f;
BrushSettings.BrushFalloff = 0.5f; BrushSettings.BrushFalloff = 0.5f;
BrushSettings.BrushMaterial = nullptr; BrushSettings.BrushMaterial = nullptr;
UE_LOG(LogAnatomicalBrush, Log, TEXT("AnatomicalStructureBrush initialized"));
} }
void UAnatomicalStructureBrush::Initialize(const FAnatomicalBrushSettings& InSettings) void UAnatomicalStructureBrush::Initialize(const FAnatomicalBrushSettings& InSettings)
{ {
BrushSettings = InSettings; BrushSettings = InSettings;
UE_LOG(LogAnatomicalBrush, Log, TEXT("AnatomicalStructureBrush settings updated: Type=%d, Size=%.2f"),
(int32)BrushSettings.BrushType, BrushSettings.BrushSize);
} }
bool UAnatomicalStructureBrush::ApplyToSkeletalMesh(USkeletalMesh* TargetMesh, const FVector& Location, const FVector& Direction, FName BoneName) bool UAnatomicalStructureBrush::ApplyToSkeletalMesh(USkeletalMesh* TargetMesh, const FVector& Location, const FVector& Direction, FName BoneName)
{ {
// Implementation will be added in future updates // Add error handling
// This is a placeholder to resolve link errors if (!TargetMesh)
return false; {
UE_LOG(LogAnatomicalBrush, Error, TEXT("ApplyToSkeletalMesh failed: Target mesh is null"));
return false;
}
UE_LOG(LogAnatomicalBrush, Log, TEXT("Applying to skeletal mesh %s, Location: (%f, %f, %f), Bone: %s"),
*TargetMesh->GetName(), Location.X, Location.Y, Location.Z, *BoneName.ToString());
try
{
// Implementation will be added in future updates
// This is a basic framework to resolve link errors
// Execute different operations based on brush type
switch (BrushSettings.BrushType)
{
case EAnatomicalBrushType::Bone:
UE_LOG(LogAnatomicalBrush, Log, TEXT("Applying bone brush effect"));
// Bone brush logic
break;
case EAnatomicalBrushType::Muscle:
UE_LOG(LogAnatomicalBrush, Log, TEXT("Applying muscle brush effect"));
// Muscle brush logic
break;
case EAnatomicalBrushType::Organ:
UE_LOG(LogAnatomicalBrush, Log, TEXT("Applying organ brush effect"));
// Organ brush logic
break;
case EAnatomicalBrushType::Vessel:
UE_LOG(LogAnatomicalBrush, Log, TEXT("Applying blood vessel brush effect"));
// Blood vessel brush logic
break;
case EAnatomicalBrushType::Nerve:
UE_LOG(LogAnatomicalBrush, Log, TEXT("Applying nerve brush effect"));
// Nerve brush logic
break;
case EAnatomicalBrushType::Custom:
UE_LOG(LogAnatomicalBrush, Log, TEXT("Applying custom brush effect"));
// Custom brush logic
break;
default:
UE_LOG(LogAnatomicalBrush, Warning, TEXT("Unknown brush type"));
break;
}
return true; // Temporarily return success, should return based on operation result after actual implementation
}
catch (const std::exception& e)
{
UE_LOG(LogAnatomicalBrush, Error, TEXT("ApplyToSkeletalMesh exception: %s"), UTF8_TO_TCHAR(e.what()));
return false;
}
catch (...)
{
UE_LOG(LogAnatomicalBrush, Error, TEXT("ApplyToSkeletalMesh unknown exception occurred"));
return false;
}
} }
bool UAnatomicalStructureBrush::ApplyToStaticMesh(UStaticMesh* TargetMesh, const FVector& Location, const FVector& Direction) bool UAnatomicalStructureBrush::ApplyToStaticMesh(UStaticMesh* TargetMesh, const FVector& Location, const FVector& Direction)
{ {
// Implementation will be added in future updates // Add error handling
// This is a placeholder to resolve link errors if (!TargetMesh)
return false; {
UE_LOG(LogAnatomicalBrush, Error, TEXT("ApplyToStaticMesh failed: Target mesh is null"));
return false;
}
UE_LOG(LogAnatomicalBrush, Log, TEXT("Applying to static mesh %s, Location: (%f, %f, %f)"),
*TargetMesh->GetName(), Location.X, Location.Y, Location.Z);
try
{
// Implementation will be added in future updates
// This is a basic framework to resolve link errors
// Execute different operations based on brush type
switch (BrushSettings.BrushType)
{
case EAnatomicalBrushType::Bone:
UE_LOG(LogAnatomicalBrush, Log, TEXT("Applying bone brush effect to static mesh"));
// Bone brush logic
break;
case EAnatomicalBrushType::Muscle:
UE_LOG(LogAnatomicalBrush, Log, TEXT("Applying muscle brush effect to static mesh"));
// Muscle brush logic
break;
case EAnatomicalBrushType::Organ:
UE_LOG(LogAnatomicalBrush, Log, TEXT("Applying organ brush effect to static mesh"));
// Organ brush logic
break;
default:
UE_LOG(LogAnatomicalBrush, Warning, TEXT("Unknown brush type"));
break;
}
return true; // Temporarily return success, should return based on operation result after actual implementation
}
catch (const std::exception& e)
{
UE_LOG(LogAnatomicalBrush, Error, TEXT("ApplyToStaticMesh exception: %s"), UTF8_TO_TCHAR(e.what()));
return false;
}
catch (...)
{
UE_LOG(LogAnatomicalBrush, Error, TEXT("ApplyToStaticMesh unknown exception occurred"));
return false;
}
} }
void UAnatomicalStructureBrush::SetBrushType(EAnatomicalBrushType BrushType) void UAnatomicalStructureBrush::SetBrushType(EAnatomicalBrushType BrushType)
{ {
BrushSettings.BrushType = BrushType; BrushSettings.BrushType = BrushType;
UE_LOG(LogAnatomicalBrush, Log, TEXT("Brush type set to: %d"), (int32)BrushType);
} }
void UAnatomicalStructureBrush::SetBrushSize(float Size) void UAnatomicalStructureBrush::SetBrushSize(float Size)
{ {
BrushSettings.BrushSize = FMath::Clamp(Size, 0.1f, 100.0f); BrushSettings.BrushSize = FMath::Clamp(Size, 0.1f, 100.0f);
UE_LOG(LogAnatomicalBrush, Log, TEXT("Brush size set to: %.2f"), BrushSettings.BrushSize);
} }
void UAnatomicalStructureBrush::SetBrushStrength(float Strength) void UAnatomicalStructureBrush::SetBrushStrength(float Strength)
{ {
BrushSettings.BrushStrength = FMath::Clamp(Strength, 0.0f, 1.0f); BrushSettings.BrushStrength = FMath::Clamp(Strength, 0.0f, 1.0f);
UE_LOG(LogAnatomicalBrush, Log, TEXT("Brush strength set to: %.2f"), BrushSettings.BrushStrength);
} }
FAnatomicalBrushSettings UAnatomicalStructureBrush::GetBrushSettings() const FAnatomicalBrushSettings UAnatomicalStructureBrush::GetBrushSettings() const
@@ -54,13 +166,24 @@ FAnatomicalBrushSettings UAnatomicalStructureBrush::GetBrushSettings() const
UStaticMesh* UAnatomicalStructureBrush::CreateAnatomicalStructure(const FVector& Location, const FVector& Direction, float Size) UStaticMesh* UAnatomicalStructureBrush::CreateAnatomicalStructure(const FVector& Location, const FVector& Direction, float Size)
{ {
UE_LOG(LogAnatomicalBrush, Log, TEXT("Creating anatomical structure, Location: (%f, %f, %f), Size: %.2f"),
Location.X, Location.Y, Location.Z, Size);
// Implementation will be added in future updates // Implementation will be added in future updates
// This is a placeholder to resolve link errors // This is a basic framework
return nullptr; return nullptr;
} }
void UAnatomicalStructureBrush::ApplyPhysicsProperties(UStaticMesh* Mesh) void UAnatomicalStructureBrush::ApplyPhysicsProperties(UStaticMesh* Mesh)
{ {
if (!Mesh)
{
UE_LOG(LogAnatomicalBrush, Error, TEXT("ApplyPhysicsProperties failed: Mesh is null"));
return;
}
UE_LOG(LogAnatomicalBrush, Log, TEXT("Applying physics properties to mesh %s"), *Mesh->GetName());
// Implementation will be added in future updates // Implementation will be added in future updates
// This is a placeholder to resolve link errors // This is a basic framework
} }

File diff suppressed because it is too large Load Diff

View File

@@ -5,4 +5,4 @@ UDismembermentGraph::UDismembermentGraph()
{ {
// Initialize default values // Initialize default values
OwningAsset = nullptr; OwningAsset = nullptr;
} }

View File

@@ -19,4 +19,4 @@ UObject* UDismembermentGraphEditorFactory::FactoryCreateNew(UClass* InClass, UOb
bool UDismembermentGraphEditorFactory::ShouldShowInNewMenu() const bool UDismembermentGraphEditorFactory::ShouldShowInNewMenu() const
{ {
return true; return true;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,8 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "Toolkits/AssetEditorToolkit.h" #include "Toolkits/AssetEditorToolkit.h"
#include "EditorUndoClient.h" #include "EditorUndoClient.h"
#include "BooleanCutTool.h"
#include "AnatomicalLayerSystem.h"
class USkeletalMesh; class USkeletalMesh;
class SDockTab; class SDockTab;
@@ -12,48 +14,116 @@ class SBorder;
/** /**
* Dismemberment System Editor * Dismemberment System Editor
* Provides real-time boolean cutting and multi-layer system editing functionality * Provides real-time boolean cutting and multi-layer system editing functionality
* Allows users to create and edit anatomical layer structures for skeletal meshes
* Supports physics settings and effect previews
*/ */
class FDismembermentEditor : public FAssetEditorToolkit, public FEditorUndoClient class FDismembermentEditor : public FAssetEditorToolkit, public FEditorUndoClient
{ {
public: public:
/** Constructor */
FDismembermentEditor(); FDismembermentEditor();
/** Destructor */
virtual ~FDismembermentEditor(); virtual ~FDismembermentEditor();
/**
* Initialize the dismemberment editor
* @param Mode - Toolkit mode
* @param InitToolkitHost - Toolkit host
* @param InSkeletalMesh - Skeletal mesh to edit
*/
void InitDismembermentEditor(const EToolkitMode::Type Mode, const TSharedPtr<IToolkitHost>& InitToolkitHost, USkeletalMesh* InSkeletalMesh); void InitDismembermentEditor(const EToolkitMode::Type Mode, const TSharedPtr<IToolkitHost>& InitToolkitHost, USkeletalMesh* InSkeletalMesh);
/** Get toolkit name */
virtual FName GetToolkitFName() const override; virtual FName GetToolkitFName() const override;
/** Get base toolkit name */
virtual FText GetBaseToolkitName() const override; virtual FText GetBaseToolkitName() const override;
/** Get world centric tab prefix */
virtual FString GetWorldCentricTabPrefix() const override; virtual FString GetWorldCentricTabPrefix() const override;
/** Get world centric tab color scale */
virtual FLinearColor GetWorldCentricTabColorScale() const override; virtual FLinearColor GetWorldCentricTabColorScale() const override;
/** Post undo handler */
virtual void PostUndo(bool bSuccess) override; virtual void PostUndo(bool bSuccess) override;
/** Post redo handler */
virtual void PostRedo(bool bSuccess) override; virtual void PostRedo(bool bSuccess) override;
/** Get current skeletal mesh being edited */
USkeletalMesh* GetSkeletalMesh() const { return SkeletalMesh; }
private: private:
/** Create editor layout */
void CreateEditorLayout(); void CreateEditorLayout();
/** Create editor toolbar */
void CreateEditorToolbar(); void CreateEditorToolbar();
void RegisterTabSpawners(const TSharedRef<FTabManager>& InTabManager); /** Register tab spawners */
void UnregisterTabSpawners(const TSharedRef<FTabManager>& InTabManager); virtual void RegisterTabSpawners(const TSharedRef<FTabManager>& InTabManager) override;
/** Unregister tab spawners */
virtual void UnregisterTabSpawners(const TSharedRef<FTabManager>& InTabManager) override;
/** Spawn viewport tab */
TSharedRef<SDockTab> SpawnTab_Viewport(const FSpawnTabArgs& Args); TSharedRef<SDockTab> SpawnTab_Viewport(const FSpawnTabArgs& Args);
/** Spawn details tab */
TSharedRef<SDockTab> SpawnTab_Details(const FSpawnTabArgs& Args); TSharedRef<SDockTab> SpawnTab_Details(const FSpawnTabArgs& Args);
/** Spawn layer system tab */
TSharedRef<SDockTab> SpawnTab_LayerSystem(const FSpawnTabArgs& Args); TSharedRef<SDockTab> SpawnTab_LayerSystem(const FSpawnTabArgs& Args);
/** Spawn physics settings tab */
TSharedRef<SDockTab> SpawnTab_PhysicsSettings(const FSpawnTabArgs& Args); TSharedRef<SDockTab> SpawnTab_PhysicsSettings(const FSpawnTabArgs& Args);
/** Perform boolean cut operation */
void PerformBooleanCut(); void PerformBooleanCut();
/** Add new anatomical layer */
void AddNewLayer(); void AddNewLayer();
/** Save edits */
void SaveEdits(); void SaveEdits();
/** Preview effects */
void PreviewEffects(); void PreviewEffects();
private: private:
/** Current skeletal mesh being edited */
USkeletalMesh* SkeletalMesh; USkeletalMesh* SkeletalMesh;
/** Viewport widget */
TSharedPtr<SBorder> ViewportWidget; TSharedPtr<SBorder> ViewportWidget;
/** Details widget */
TSharedPtr<IDetailsView> DetailsWidget; TSharedPtr<IDetailsView> DetailsWidget;
/** Layer system widget */
TSharedPtr<SBorder> LayerSystemWidget; TSharedPtr<SBorder> LayerSystemWidget;
/** Physics settings widget */
TSharedPtr<SBorder> PhysicsSettingsWidget; TSharedPtr<SBorder> PhysicsSettingsWidget;
/** Boolean cut tool */
UBooleanCutTool* BooleanCutTool;
/** Anatomical layer system */
UAnatomicalLayerSystem* LayerSystem;
/** Current cut plane */
FCutPlane CurrentCutPlane;
/** Selected bone name for cutting */
FName SelectedBoneName;
/** Flag to create cap mesh */
bool bCreateCapMesh;
/** Tab ID constants */
static const FName ViewportTabId; static const FName ViewportTabId;
static const FName DetailsTabId; static const FName DetailsTabId;
static const FName LayerSystemTabId; static const FName LayerSystemTabId;

View File

@@ -19,4 +19,4 @@ public:
// The asset that owns this graph // The asset that owns this graph
UPROPERTY() UPROPERTY()
TObjectPtr<class UDismembermentGraphAsset> OwningAsset; TObjectPtr<class UDismembermentGraphAsset> OwningAsset;
}; };

View File

@@ -37,4 +37,4 @@ public:
virtual void CompileNode(class FDismembermentCompiler* Compiler) override; virtual void CompileNode(class FDismembermentCompiler* Compiler) override;
virtual void ExecuteNode(class FDismembermentExecutor* Executor) override; virtual void ExecuteNode(class FDismembermentExecutor* Executor) override;
// End of UDismembermentGraphNode interface // End of UDismembermentGraphNode interface
}; };

View File

@@ -4,6 +4,8 @@
#include "Toolkits/AssetEditorToolkit.h" #include "Toolkits/AssetEditorToolkit.h"
#include "Widgets/Docking/SDockTab.h" #include "Widgets/Docking/SDockTab.h"
#include "BooleanCutTool.h" #include "BooleanCutTool.h"
#include "EditorUndoClient.h"
#include "Logging/LogMacros.h"
class SDockTab; class SDockTab;
class SGraphEditor; class SGraphEditor;
@@ -13,6 +15,10 @@ class SMatrixInputWidget;
class FFLESHViewportClient; class FFLESHViewportClient;
class FSceneViewport; class FSceneViewport;
class UVisceraNodeObject; class UVisceraNodeObject;
class FDismembermentEditor;
// Define log category
DECLARE_LOG_CATEGORY_EXTERN(LogFLESHEditor, Log, All);
/** /**
* Bone tree item structure * Bone tree item structure
@@ -181,7 +187,7 @@ struct FVisceraNodeItem : public TSharedFromThis<FVisceraNodeItem>
* FLESH Main Editor * FLESH Main Editor
* Provides the main editing functionality for the dismemberment system * Provides the main editing functionality for the dismemberment system
*/ */
class FLESHEDITOR_API FFLESHEditor : public FAssetEditorToolkit class FLESHEDITOR_API FFLESHEditor : public FAssetEditorToolkit, public FEditorUndoClient
{ {
public: public:
FFLESHEditor(); FFLESHEditor();
@@ -198,9 +204,27 @@ public:
virtual FString GetWorldCentricTabPrefix() const override; virtual FString GetWorldCentricTabPrefix() const override;
virtual FLinearColor GetWorldCentricTabColorScale() const override; virtual FLinearColor GetWorldCentricTabColorScale() const override;
// End of FAssetEditorToolkit interface // End of FAssetEditorToolkit interface
// FEditorUndoClient interface
virtual void PostUndo(bool bSuccess) override;
virtual void PostRedo(bool bSuccess) override;
// Open the editor // Open the editor
static void OpenEditor(); void OpenEditor();
// Get whether the editor is initialized
bool IsEditorInitialized();
// Get the editing object
UObject* GetEditingObject() const { return EditingObject; }
// Add DismembermentEditor related tab spawners
TSharedRef<SDockTab> SpawnTab_LayerSystem(const FSpawnTabArgs& Args);
TSharedRef<SDockTab> SpawnTab_PhysicsSettings(const FSpawnTabArgs& Args);
// Create DismembermentEditor related widgets
TSharedRef<SBorder> CreateLayerSystemWidget();
TSharedRef<SBorder> CreatePhysicsSettingsWidget();
private: private:
// Tab spawners // Tab spawners
@@ -232,6 +256,9 @@ private:
// Create command list // Create command list
void CreateCommandList(); void CreateCommandList();
// Extend toolbar with custom buttons
void ExtendToolbar();
// Generate bone tree row // Generate bone tree row
TSharedRef<ITableRow> OnGenerateBoneRow(TSharedPtr<FBoneTreeItem> Item, const TSharedRef<STableViewBase>& OwnerTable); TSharedRef<ITableRow> OnGenerateBoneRow(TSharedPtr<FBoneTreeItem> Item, const TSharedRef<STableViewBase>& OwnerTable);
@@ -338,4 +365,17 @@ private:
static const FName MatrixEditorTabId; static const FName MatrixEditorTabId;
static const FName GraphEditorTabId; static const FName GraphEditorTabId;
static const FName ToolbarTabId; static const FName ToolbarTabId;
static const FName LayerSystemTabId;
static const FName PhysicsSettingsTabId;
static const FName DismembermentGraphTabId;
// Is the editor initialized?
bool bIsInitialized;
// New DismembermentEditor related Widgets
TSharedPtr<SBorder> LayerSystemWidget;
TSharedPtr<SBorder> PhysicsSettingsWidget;
// Error handling method
void HandleEditorError(const FText& ErrorMessage);
}; };