diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 38add98..6fafc0a 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -9,7 +9,8 @@ "Bash(git commit -m \"$(cat <<''EOF''\n实现DynamicIronBlock温度体素系统基础功能\n\n新增功能:\n- 添加FTemperatureVoxel结构体(温度、塑性系数、表面标志)\n- 实现自适应温度网格(5mm体素精度,基于BoxSize计算分辨率)\n- 实现三线性插值温度/塑性系数采样\n- 实现黑体辐射温度可视化(顶点颜色)\n- 添加HeatRegion蓝图测试函数\n- 添加OnHammerImpact锤击形变函数(体积守恒)\n\n技术细节:\n- Phase 1: CPU侧温度网格初始化,支持10cm-100cm+可变尺寸\n- Phase 3: 温度可视化系统(20°C灰色 → 1200°C白色)\n- 内存占用:30×30×30cm ≈ 1.7MB(60×60×60体素)\n\n待实现:Phase 2 GPU热传导计算\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude \nEOF\n)\")", "Bash(git commit:*)", "Bash(\"E:\\MiceCola\\work\\UE_5_6\\Engine\\Build\\BatchFiles\\Build.bat\" BladeSmithEditor Win64 Development -Project=\"C:\\MiceCola\\Indi\\BladeSmith\\BladeSmith.uproject\" -WaitMutex -FromMsBuild)", - "Bash(cmd /c:*)" + "Bash(cmd /c:*)", + "Bash(\"C:\\MiceCola\\Indi\\UE_5.6\\Engine\\Build\\BatchFiles\\Build.bat\" BladeSmithEditor Win64 Development \"-Project=C:\\MiceCola\\Indi\\BladeSmith\\BladeSmith.uproject\" -WaitMutex -FromMsBuild)" ], "deny": [], "ask": [] diff --git a/BladeSmith.sln.DotSettings.user b/BladeSmith.sln.DotSettings.user index 812d0d1..de95d70 100644 --- a/BladeSmith.sln.DotSettings.user +++ b/BladeSmith.sln.DotSettings.user @@ -1,4 +1,5 @@  + ForceIncluded ForceIncluded ForceIncluded ForceIncluded diff --git a/Content/BP/BP_DynamicMetal.uasset b/Content/BP/BP_DynamicMetal.uasset index a3fb141..772612d 100644 Binary files a/Content/BP/BP_DynamicMetal.uasset and b/Content/BP/BP_DynamicMetal.uasset differ diff --git a/Content/BP/BP_FirstPersonCharacter.uasset b/Content/BP/BP_FirstPersonCharacter.uasset index e1a11be..7e75352 100644 Binary files a/Content/BP/BP_FirstPersonCharacter.uasset and b/Content/BP/BP_FirstPersonCharacter.uasset differ diff --git a/Content/Maps/Demo.umap b/Content/Maps/Demo.umap index 641995f..db5e6f7 100644 Binary files a/Content/Maps/Demo.umap and b/Content/Maps/Demo.umap differ diff --git a/Content/Res/Materials/M_VertexColor.uasset b/Content/Res/Materials/M_VertexColor.uasset index 92c3d7e..12f1834 100644 Binary files a/Content/Res/Materials/M_VertexColor.uasset and b/Content/Res/Materials/M_VertexColor.uasset differ diff --git a/Source/BladeSmith/DynamicIronBlock.cpp b/Source/BladeSmith/DynamicIronBlock.cpp index c5eb10c..889e0b8 100644 --- a/Source/BladeSmith/DynamicIronBlock.cpp +++ b/Source/BladeSmith/DynamicIronBlock.cpp @@ -182,6 +182,16 @@ void ADynamicIronBlock::InitializeBoxMesh() // 如果设置了材质,创建动态材质实例并应用 if (IronMaterial) { + // 强制设置材质的Usage标志,确保支持顶点颜色 + UMaterial* BaseMaterial = IronMaterial->GetMaterial(); + if (BaseMaterial) + { + BaseMaterial->bUsedWithGeometryCollections = true; + BaseMaterial->bUsedWithSkeletalMesh = true; + BaseMaterial->bUsedWithStaticLighting = true; + UE_LOG(LogTemp, Warning, TEXT("DynamicIronBlock: Material usage flags set for vertex color support")); + } + DynamicMaterialInstance = UMaterialInstanceDynamic::Create(IronMaterial, this); if (DynamicMaterialInstance) { @@ -190,6 +200,23 @@ void ADynamicIronBlock::InitializeBoxMesh() } } + // 确保DynamicMeshComponent启用顶点颜色渲染 + DynMeshComp->SetEnableWireframeRenderPass(false); + DynMeshComp->bExplicitShowWireframe = false; + + // 这些设置确保顶点颜色被正确传递到GPU + DynMeshComp->SetColorOverrideMode(EDynamicMeshComponentColorOverrideMode::None); + + // // 强制启用顶点颜色渲染 + // DynMeshComp->bDrawMeshCollisionIfComplex = false; + // DynMeshComp->bDrawMeshCollisionIfSimple = false; + + // 设置渲染状态 + DynMeshComp->SetRenderCustomDepth(false); + DynMeshComp->MarkRenderStateDirty(); + + UE_LOG(LogTemp, Warning, TEXT("DynamicIronBlock: DynamicMeshComponent rendering configured for vertex colors")); + // 通知组件网格已更新 DynMeshComp->NotifyMeshUpdated(); @@ -199,6 +226,13 @@ void ADynamicIronBlock::InitializeBoxMesh() // 初始化温度网格 InitializeTemperatureGrid(); + // 初始化顶点颜色(基于初始温度) + if (bEnableTemperatureSystem && TemperatureGrid.Num() > 0) + { + UpdateVertexColors(); + UE_LOG(LogTemp, Log, TEXT("DynamicIronBlock: Initial vertex colors set based on ambient temperature")); + } + UE_LOG(LogTemp, Log, TEXT("DynamicIronBlock: Box mesh initialized with size (%f, %f, %f)"), BoxSize.X, BoxSize.Y, BoxSize.Z); } @@ -567,6 +601,9 @@ void ADynamicIronBlock::HeatRegion(FVector WorldCenter, float Radius, float Temp // 更新材质温度参数以显示温度变化 UpdateMaterialTemperature(); + + // 更新顶点颜色(基于体素温度) + UpdateVertexColors(); } float ADynamicIronBlock::SampleTemperatureAtPosition(const FVector& LocalPosition) const @@ -771,6 +808,174 @@ void ADynamicIronBlock::UpdateMaterialTemperature() } } +void ADynamicIronBlock::UpdateVertexColors() +{ + if (!bEnableTemperatureSystem || TemperatureGrid.Num() == 0) + { + return; + } + + // 获取 DynamicMeshComponent + UDynamicMeshComponent* DynMeshComp = GetDynamicMeshComponent(); + if (!DynMeshComp) + { + UE_LOG(LogTemp, Warning, TEXT("DynamicIronBlock: Cannot update vertex colors, DynamicMeshComponent is null")); + return; + } + + // 获取 DynamicMesh + UDynamicMesh* DynMesh = DynMeshComp->GetDynamicMesh(); + if (!DynMesh) + { + UE_LOG(LogTemp, Warning, TEXT("DynamicIronBlock: Cannot update vertex colors, DynamicMesh is null")); + return; + } + + // 修改网格以设置顶点颜色 + DynMesh->EditMesh([&](FDynamicMesh3& EditMesh) + { + // 确保网格启用了顶点颜色属性 + if (!EditMesh.HasVertexColors()) + { + EditMesh.EnableVertexColors(FVector3f::Zero()); // 初始化为黑色 + } + + // 遍历所有顶点 + int32 ColoredVertices = 0; + float MinTemp = FLT_MAX; + float MaxTemp = -FLT_MAX; + FVector3f FirstVertexColor = FVector3f::Zero(); + float FirstVertexTemp = 0.0f; + FVector FirstVertexPos = FVector::ZeroVector; + + for (int32 VertexID : EditMesh.VertexIndicesItr()) + { + // 获取顶点位置(局部坐标) + FVector3d VertexPos = EditMesh.GetVertex(VertexID); + FVector VertexPosFloat(VertexPos.X, VertexPos.Y, VertexPos.Z); + + // 采样该位置的温度 + float Temperature = SampleTemperatureAtPosition(VertexPosFloat); + + // 统计温度范围 + MinTemp = FMath::Min(MinTemp, Temperature); + MaxTemp = FMath::Max(MaxTemp, Temperature); + + // 将温度转换为黑体辐射颜色 + FLinearColor TempColor = TemperatureToColor(Temperature); + + // 设置顶点颜色(FDynamicMesh3使用FVector3f表示颜色,范围0-1) + FVector3f VertexColor = FVector3f(TempColor.R, TempColor.G, TempColor.B); + EditMesh.SetVertexColor(VertexID, VertexColor); + + // 记录第一个顶点的信息用于调试 + if (ColoredVertices == 0) + { + FirstVertexColor = VertexColor; + FirstVertexTemp = Temperature; + FirstVertexPos = VertexPosFloat; + } + + ++ColoredVertices; + } + + UE_LOG(LogTemp, Warning, TEXT("=== UpdateVertexColors Debug Info ===")); + UE_LOG(LogTemp, Warning, TEXT(" Total vertices: %d"), ColoredVertices); + UE_LOG(LogTemp, Warning, TEXT(" Temperature range: %.1f°C - %.1f°C"), MinTemp, MaxTemp); + UE_LOG(LogTemp, Warning, TEXT(" First vertex: Pos=(%.1f, %.1f, %.1f), Temp=%.1f°C, Color=(%.3f, %.3f, %.3f)"), + FirstVertexPos.X, FirstVertexPos.Y, FirstVertexPos.Z, + FirstVertexTemp, + FirstVertexColor.X, FirstVertexColor.Y, FirstVertexColor.Z); + }, EDynamicMeshChangeType::GeneralEdit, EDynamicMeshAttributeChangeFlags::Unknown, false); + + // 通知组件网格已更新 + DynMeshComp->NotifyMeshUpdated(); + + // 强制刷新渲染状态以确保顶点颜色更新 + DynMeshComp->MarkRenderStateDirty(); + DynMeshComp->MarkRenderDynamicDataDirty(); +} + +void ADynamicIronBlock::DebugPrintVertexColors() +{ + UDynamicMeshComponent* DynMeshComp = GetDynamicMeshComponent(); + if (!DynMeshComp) + { + UE_LOG(LogTemp, Error, TEXT("DynamicIronBlock: DynamicMeshComponent is null")); + return; + } + + UDynamicMesh* DynMesh = DynMeshComp->GetDynamicMesh(); + if (!DynMesh) + { + UE_LOG(LogTemp, Error, TEXT("DynamicIronBlock: DynamicMesh is null")); + return; + } + + DynMesh->ProcessMesh([&](const FDynamicMesh3& ReadMesh) + { + bool bHasVertexColors = ReadMesh.HasVertexColors(); + int32 VertexCount = ReadMesh.VertexCount(); + + UE_LOG(LogTemp, Warning, TEXT("========== Vertex Color Debug ==========")); + UE_LOG(LogTemp, Warning, TEXT("Has Vertex Colors: %s"), bHasVertexColors ? TEXT("YES") : TEXT("NO")); + UE_LOG(LogTemp, Warning, TEXT("Total Vertices: %d"), VertexCount); + + if (bHasVertexColors) + { + // 采样几个顶点的颜色 + int32 SampleCount = FMath::Min(10, VertexCount); + UE_LOG(LogTemp, Warning, TEXT("Sampling first %d vertices:"), SampleCount); + + int32 SampledCount = 0; + for (int32 VertexID : ReadMesh.VertexIndicesItr()) + { + if (SampledCount >= SampleCount) + break; + + FVector3d Pos = ReadMesh.GetVertex(VertexID); + FVector3f Color = ReadMesh.GetVertexColor(VertexID); + + UE_LOG(LogTemp, Warning, TEXT(" Vertex[%d]: Pos=(%.1f, %.1f, %.1f), Color=(%.3f, %.3f, %.3f)"), + VertexID, Pos.X, Pos.Y, Pos.Z, Color.X, Color.Y, Color.Z); + + SampledCount++; + } + + // 统计颜色范围 + FVector3f MinColor(FLT_MAX, FLT_MAX, FLT_MAX); + FVector3f MaxColor(-FLT_MAX, -FLT_MAX, -FLT_MAX); + + for (int32 VertexID : ReadMesh.VertexIndicesItr()) + { + FVector3f Color = ReadMesh.GetVertexColor(VertexID); + MinColor.X = FMath::Min(MinColor.X, Color.X); + MinColor.Y = FMath::Min(MinColor.Y, Color.Y); + MinColor.Z = FMath::Min(MinColor.Z, Color.Z); + MaxColor.X = FMath::Max(MaxColor.X, Color.X); + MaxColor.Y = FMath::Max(MaxColor.Y, Color.Y); + MaxColor.Z = FMath::Max(MaxColor.Z, Color.Z); + } + + UE_LOG(LogTemp, Warning, TEXT("Color Range: Min=(%.3f, %.3f, %.3f), Max=(%.3f, %.3f, %.3f)"), + MinColor.X, MinColor.Y, MinColor.Z, MaxColor.X, MaxColor.Y, MaxColor.Z); + } + else + { + UE_LOG(LogTemp, Error, TEXT("Mesh does NOT have vertex colors! UpdateVertexColors may not be working.")); + } + + UE_LOG(LogTemp, Warning, TEXT("========================================")); + }); + + // 在屏幕上显示 + if (GEngine) + { + GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, + TEXT("Vertex color debug info printed to log (check Output Log)")); + } +} + // ========== GPU缓冲区管理实现 ========== void ADynamicIronBlock::CreateGPUBuffers() @@ -947,6 +1152,9 @@ void ADynamicIronBlock::DownloadTemperatureDataFromGPU() // 更新材质温度参数以反映新的温度 UpdateMaterialTemperature(); + + // 更新顶点颜色(基于体素温度) + UpdateVertexColors(); }); }); } diff --git a/Source/BladeSmith/DynamicIronBlock.h b/Source/BladeSmith/DynamicIronBlock.h index 7849e11..5c5b391 100644 --- a/Source/BladeSmith/DynamicIronBlock.h +++ b/Source/BladeSmith/DynamicIronBlock.h @@ -142,6 +142,12 @@ public: UFUNCTION(BlueprintCallable, Category = "Hammer Impact") void OnHammerImpact(FVector HitLocation, FVector HitNormal, float ImpactRadius, float ImpactDepth, float ImpactForce = 1.0f); + /** + * 调试函数 - 输出顶点颜色信息到日志和屏幕 + */ + UFUNCTION(BlueprintCallable, Category = "Temperature System|Debug") + void DebugPrintVertexColors(); + protected: // 当游戏开始或生成时调用 virtual void BeginPlay() override; @@ -267,6 +273,11 @@ private: */ void UpdateMaterialTemperature(); + /** + * 更新网格顶点颜色(基于每个顶点的温度体素采样) + */ + void UpdateVertexColors(); + // ========== GPU计算系统(Phase 2) ========== // GPU缓冲区(Ping-Pong双缓冲)