diff --git a/Source/BladeSmith/DynamicIronBlock.cpp b/Source/BladeSmith/DynamicIronBlock.cpp index b62b8de..17491bc 100644 --- a/Source/BladeSmith/DynamicIronBlock.cpp +++ b/Source/BladeSmith/DynamicIronBlock.cpp @@ -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"), LocalHitLocation.X, LocalHitLocation.Y, LocalHitLocation.Z, ActualDepth, ImpactRadius, AnisotropyRatio); + // 记录锤击时间 + float CurrentTime = GetWorld()->GetTimeSeconds(); + // 计算材料流动方向 FVector BoxHalfSize = BoxSize * 0.5f; FVector ToNearestEdge = FindNearestFreeEdgeDirection(LocalHitLocation, BoxHalfSize); @@ -441,9 +444,18 @@ void ADynamicIronBlock::OnHammerImpact(FVector HitLocation, FVector HitNormal, f } } - // 应用Laplacian平滑(轻微,保持形状细节) - float BulgeOuterRadius = ImpactRadius * (1.0f + BulgeRatio); - ApplyLaplacianSmoothing(EditMesh, LocalHitLocation, BulgeOuterRadius, 0.1f); + // 自适应优化:仅在锤击间隔足够大时执行完整平滑 + bool bShouldSmooth = !bEnableAdaptiveOptimization || (CurrentTime - LastHammerImpactTime > MinSmoothingInterval); + + if (bShouldSmooth) + { + // 应用Laplacian平滑(轻微,保持形状细节) + float BulgeOuterRadius = ImpactRadius * (1.0f + BulgeRatio); + ApplyLaplacianSmoothing(EditMesh, LocalHitLocation, BulgeOuterRadius, 0.1f); + } + + // 更新上次锤击时间 + LastHammerImpactTime = CurrentTime; }, EDynamicMeshChangeType::GeneralEdit, EDynamicMeshAttributeChangeFlags::Unknown, false); // 重新计算法线 @@ -1616,3 +1628,158 @@ void ADynamicIronBlock::ApplyLaplacianSmoothing(FDynamicMesh3& Mesh, const FVect 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 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)); + } +} diff --git a/Source/BladeSmith/DynamicIronBlock.h b/Source/BladeSmith/DynamicIronBlock.h index e69fb7a..a9f8659 100644 --- a/Source/BladeSmith/DynamicIronBlock.h +++ b/Source/BladeSmith/DynamicIronBlock.h @@ -86,6 +86,16 @@ public: UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Iron Block|Material Properties", meta = (ClampMin = "0.1", ClampMax = "5.0")) 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") 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: // 当游戏开始或生成时调用 virtual void BeginPlay() override; @@ -302,6 +330,9 @@ private: // 标志位:顶点属性是否已初始化 bool bVertexAttributesInitialized = false; + // 上次锤击时间(用于自适应优化) + float LastHammerImpactTime = 0.0f; + /** * 初始化顶点属性层 */