feat: 添加调试可视化工具和性能优化
- Task 10: 添加调试可视化工具 - DebugDrawFlowDirections() - 可视化材料流动方向 - DebugDrawEdgeVertices() - 可视化边缘顶点 - DebugPrintVertexAttributes() - 输出顶点属性统计信息 - Task 12: 性能优化和参数调优 - 添加 bEnableAdaptiveOptimization 参数 - 添加 MinSmoothingInterval 参数 - 添加 LastHammerImpactTime 追踪 - 在OnHammerImpact中应用自适应优化逻辑 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -307,6 +307,9 @@ void ADynamicIronBlock::OnHammerImpact(FVector HitLocation, FVector HitNormal, f
|
|||||||
UE_LOG(LogTemp, Log, TEXT("DynamicIronBlock: Hammer impact at local position (%f, %f, %f), depth: %f, radius: %f, anisotropy: %f"),
|
UE_LOG(LogTemp, Log, TEXT("DynamicIronBlock: Hammer impact at local position (%f, %f, %f), depth: %f, radius: %f, anisotropy: %f"),
|
||||||
LocalHitLocation.X, LocalHitLocation.Y, LocalHitLocation.Z, ActualDepth, ImpactRadius, AnisotropyRatio);
|
LocalHitLocation.X, LocalHitLocation.Y, LocalHitLocation.Z, ActualDepth, ImpactRadius, AnisotropyRatio);
|
||||||
|
|
||||||
|
// 记录锤击时间
|
||||||
|
float CurrentTime = GetWorld()->GetTimeSeconds();
|
||||||
|
|
||||||
// 计算材料流动方向
|
// 计算材料流动方向
|
||||||
FVector BoxHalfSize = BoxSize * 0.5f;
|
FVector BoxHalfSize = BoxSize * 0.5f;
|
||||||
FVector ToNearestEdge = FindNearestFreeEdgeDirection(LocalHitLocation, BoxHalfSize);
|
FVector ToNearestEdge = FindNearestFreeEdgeDirection(LocalHitLocation, BoxHalfSize);
|
||||||
@@ -441,9 +444,18 @@ void ADynamicIronBlock::OnHammerImpact(FVector HitLocation, FVector HitNormal, f
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 应用Laplacian平滑(轻微,保持形状细节)
|
// 自适应优化:仅在锤击间隔足够大时执行完整平滑
|
||||||
float BulgeOuterRadius = ImpactRadius * (1.0f + BulgeRatio);
|
bool bShouldSmooth = !bEnableAdaptiveOptimization || (CurrentTime - LastHammerImpactTime > MinSmoothingInterval);
|
||||||
ApplyLaplacianSmoothing(EditMesh, LocalHitLocation, BulgeOuterRadius, 0.1f);
|
|
||||||
|
if (bShouldSmooth)
|
||||||
|
{
|
||||||
|
// 应用Laplacian平滑(轻微,保持形状细节)
|
||||||
|
float BulgeOuterRadius = ImpactRadius * (1.0f + BulgeRatio);
|
||||||
|
ApplyLaplacianSmoothing(EditMesh, LocalHitLocation, BulgeOuterRadius, 0.1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新上次锤击时间
|
||||||
|
LastHammerImpactTime = CurrentTime;
|
||||||
}, EDynamicMeshChangeType::GeneralEdit, EDynamicMeshAttributeChangeFlags::Unknown, false);
|
}, EDynamicMeshChangeType::GeneralEdit, EDynamicMeshAttributeChangeFlags::Unknown, false);
|
||||||
|
|
||||||
// 重新计算法线
|
// 重新计算法线
|
||||||
@@ -1616,3 +1628,158 @@ void ADynamicIronBlock::ApplyLaplacianSmoothing(FDynamicMesh3& Mesh, const FVect
|
|||||||
Mesh.SetVertex(Pair.Key, Pair.Value);
|
Mesh.SetVertex(Pair.Key, Pair.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========== 调试可视化工具实现 ==========
|
||||||
|
|
||||||
|
void ADynamicIronBlock::DebugDrawFlowDirections()
|
||||||
|
{
|
||||||
|
if (!GetWorld())
|
||||||
|
return;
|
||||||
|
|
||||||
|
UDynamicMeshComponent* DynMeshComp = GetDynamicMeshComponent();
|
||||||
|
if (!DynMeshComp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
UDynamicMesh* DynMesh = DynMeshComp->GetDynamicMesh();
|
||||||
|
if (!DynMesh)
|
||||||
|
return;
|
||||||
|
|
||||||
|
FVector BoxHalfSize = BoxSize * 0.5f;
|
||||||
|
|
||||||
|
// 在网格表面采样点
|
||||||
|
DynMesh->ProcessMesh([&](const FDynamicMesh3& ReadMesh)
|
||||||
|
{
|
||||||
|
int32 SampleCount = 0;
|
||||||
|
for (int32 VertexID : ReadMesh.VertexIndicesItr())
|
||||||
|
{
|
||||||
|
// 每100个顶点采样一次
|
||||||
|
if (SampleCount++ % 100 != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
FVector3d Pos3d = ReadMesh.GetVertex(VertexID);
|
||||||
|
FVector Pos(Pos3d.X, Pos3d.Y, Pos3d.Z);
|
||||||
|
|
||||||
|
// 计算流动方向
|
||||||
|
FVector ToNearestEdge = FindNearestFreeEdgeDirection(Pos, BoxHalfSize);
|
||||||
|
FVector PrimaryFlow = CalculatePrimaryFlowDirection(FVector::DownVector, ToNearestEdge);
|
||||||
|
|
||||||
|
// 转换到世界坐标
|
||||||
|
FVector WorldPos = GetActorTransform().TransformPosition(Pos);
|
||||||
|
FVector WorldDir = GetActorTransform().TransformVector(PrimaryFlow);
|
||||||
|
|
||||||
|
// 绘制方向箭头
|
||||||
|
DrawDebugDirectionalArrow(
|
||||||
|
GetWorld(),
|
||||||
|
WorldPos,
|
||||||
|
WorldPos + WorldDir * 5.0f,
|
||||||
|
100.0f, // 箭头大小
|
||||||
|
FColor::Cyan,
|
||||||
|
false, // 是否持久
|
||||||
|
5.0f, // 持续时间
|
||||||
|
0, // 深度优先级
|
||||||
|
0.5f // 箭头厚度
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
UE_LOG(LogTemp, Warning, TEXT("DynamicIronBlock: Flow direction debug visualization drawn"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ADynamicIronBlock::DebugDrawEdgeVertices()
|
||||||
|
{
|
||||||
|
if (!GetWorld())
|
||||||
|
return;
|
||||||
|
|
||||||
|
UDynamicMeshComponent* DynMeshComp = GetDynamicMeshComponent();
|
||||||
|
if (!DynMeshComp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
UDynamicMesh* DynMesh = DynMeshComp->GetDynamicMesh();
|
||||||
|
if (!DynMesh)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TSet<int32> EdgeVertices;
|
||||||
|
DynMesh->ProcessMesh([&](const FDynamicMesh3& ReadMesh)
|
||||||
|
{
|
||||||
|
MarkEdgeVertices(ReadMesh, EdgeVertices);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (int32 VID : EdgeVertices)
|
||||||
|
{
|
||||||
|
DynMesh->ProcessMesh([&](const FDynamicMesh3& ReadMesh)
|
||||||
|
{
|
||||||
|
if (!ReadMesh.IsVertex(VID))
|
||||||
|
return;
|
||||||
|
|
||||||
|
FVector3d Pos3d = ReadMesh.GetVertex(VID);
|
||||||
|
FVector WorldPos = GetActorTransform().TransformPosition(FVector(Pos3d.X, Pos3d.Y, Pos3d.Z));
|
||||||
|
|
||||||
|
DrawDebugPoint(GetWorld(), WorldPos, 8.0f, FColor::Red, false, 5.0f);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
UE_LOG(LogTemp, Warning, TEXT("DynamicIronBlock: Edge vertices debug visualization drawn (%d vertices)"), EdgeVertices.Num());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ADynamicIronBlock::DebugPrintVertexAttributes()
|
||||||
|
{
|
||||||
|
UDynamicMeshComponent* DynMeshComp = GetDynamicMeshComponent();
|
||||||
|
if (!DynMeshComp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
UDynamicMesh* DynMesh = DynMeshComp->GetDynamicMesh();
|
||||||
|
if (!DynMesh)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!bVertexAttributesInitialized)
|
||||||
|
{
|
||||||
|
UE_LOG(LogTemp, Warning, TEXT("DynamicIronBlock: Vertex attributes not initialized"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 统计信息
|
||||||
|
float MinStrain = FLT_MAX, MaxStrain = -FLT_MAX, AvgStrain = 0.0f;
|
||||||
|
float MinPolish = FLT_MAX, MaxPolish = -FLT_MAX, AvgPolish = 0.0f;
|
||||||
|
int32 Count = 0;
|
||||||
|
|
||||||
|
DynMesh->ProcessMesh([&](const FDynamicMesh3& ReadMesh)
|
||||||
|
{
|
||||||
|
for (int32 VertexID : ReadMesh.VertexIndicesItr())
|
||||||
|
{
|
||||||
|
if (!AccumulatedStrainArray.IsValidIndex(VertexID) || !PolishAmountArray.IsValidIndex(VertexID))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
float Strain = AccumulatedStrainArray[VertexID];
|
||||||
|
float Polish = PolishAmountArray[VertexID];
|
||||||
|
|
||||||
|
MinStrain = FMath::Min(MinStrain, Strain);
|
||||||
|
MaxStrain = FMath::Max(MaxStrain, Strain);
|
||||||
|
AvgStrain += Strain;
|
||||||
|
|
||||||
|
MinPolish = FMath::Min(MinPolish, Polish);
|
||||||
|
MaxPolish = FMath::Max(MaxPolish, Polish);
|
||||||
|
AvgPolish += Polish;
|
||||||
|
|
||||||
|
Count++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Count > 0)
|
||||||
|
{
|
||||||
|
AvgStrain /= Count;
|
||||||
|
AvgPolish /= Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
UE_LOG(LogTemp, Warning, TEXT("========== Vertex Attributes Debug =========="));
|
||||||
|
UE_LOG(LogTemp, Warning, TEXT("Vertices: %d"), Count);
|
||||||
|
UE_LOG(LogTemp, Warning, TEXT("Strain: Min=%.3f, Max=%.3f, Avg=%.3f"), MinStrain, MaxStrain, AvgStrain);
|
||||||
|
UE_LOG(LogTemp, Warning, TEXT("Polish: Min=%.3f, Max=%.3f, Avg=%.3f"), MinPolish, MaxPolish, AvgPolish);
|
||||||
|
UE_LOG(LogTemp, Warning, TEXT("==========================================="));
|
||||||
|
|
||||||
|
// 屏幕显示
|
||||||
|
if (GEngine)
|
||||||
|
{
|
||||||
|
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow,
|
||||||
|
FString::Printf(TEXT("Strain: Avg=%.2f | Polish: Avg=%.2f"), AvgStrain, AvgPolish));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -86,6 +86,16 @@ public:
|
|||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Iron Block|Material Properties", meta = (ClampMin = "0.1", ClampMax = "5.0"))
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Iron Block|Material Properties", meta = (ClampMin = "0.1", ClampMax = "5.0"))
|
||||||
float EdgeThreshold = 0.5f;
|
float EdgeThreshold = 0.5f;
|
||||||
|
|
||||||
|
// ========== 性能参数 ==========
|
||||||
|
|
||||||
|
// 是否启用自适应优化(仅在锤击间隔较长时执行完整优化)
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Iron Block|Performance")
|
||||||
|
bool bEnableAdaptiveOptimization = true;
|
||||||
|
|
||||||
|
// 最小平滑间隔(秒,低于此值跳过平滑)
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Iron Block|Performance", meta = (ClampMin = "0.0", ClampMax = "1.0"))
|
||||||
|
float MinSmoothingInterval = 0.1f;
|
||||||
|
|
||||||
// ========== 温度系统参数 ==========
|
// ========== 温度系统参数 ==========
|
||||||
|
|
||||||
// 温度体素大小(毫米)
|
// 温度体素大小(毫米)
|
||||||
@@ -160,6 +170,24 @@ public:
|
|||||||
UFUNCTION(BlueprintCallable, Category = "Temperature System|Debug")
|
UFUNCTION(BlueprintCallable, Category = "Temperature System|Debug")
|
||||||
void DebugPrintVertexColors();
|
void DebugPrintVertexColors();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调试函数 - 可视化材料流动方向
|
||||||
|
*/
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Hammer Impact|Debug")
|
||||||
|
void DebugDrawFlowDirections();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调试函数 - 可视化边缘顶点
|
||||||
|
*/
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Hammer Impact|Debug")
|
||||||
|
void DebugDrawEdgeVertices();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调试函数 - 输出顶点属性统计信息
|
||||||
|
*/
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "Hammer Impact|Debug")
|
||||||
|
void DebugPrintVertexAttributes();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// 当游戏开始或生成时调用
|
// 当游戏开始或生成时调用
|
||||||
virtual void BeginPlay() override;
|
virtual void BeginPlay() override;
|
||||||
@@ -302,6 +330,9 @@ private:
|
|||||||
// 标志位:顶点属性是否已初始化
|
// 标志位:顶点属性是否已初始化
|
||||||
bool bVertexAttributesInitialized = false;
|
bool bVertexAttributesInitialized = false;
|
||||||
|
|
||||||
|
// 上次锤击时间(用于自适应优化)
|
||||||
|
float LastHammerImpactTime = 0.0f;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化顶点属性层
|
* 初始化顶点属性层
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user