温度到颜色处理

This commit is contained in:
zhangqing
2025-12-10 19:10:26 +08:00
parent bba161810a
commit 511f43f2c0
8 changed files with 222 additions and 1 deletions
+2 -1
View File
@@ -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 <noreply@anthropic.com>\nEOF\n)\")", "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 <noreply@anthropic.com>\nEOF\n)\")",
"Bash(git commit:*)", "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(\"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": [], "deny": [],
"ask": [] "ask": []
+1
View File
@@ -1,4 +1,5 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=657466D1_002D2409_002D3196_002D8BA9_002D4914CBD968CC_002Fdl_003ASource_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FUE_005F5_002E6_003FEngine_003FSource_002Fd_003ARuntime_002Fd_003AEngine_002Fd_003APublic_002Fd_003AMaterials_002Ff_003AMaterialExpressionBlackBody_002Eh/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADanyxuq_002Easm_002Fl_003AC_0021_003FUsers_003Fstarm_003FAppData_003FLocal_003FTemp_003FSandboxFiles_003FRewuwer_003FDanyxuq_002Easm/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADanyxuq_002Easm_002Fl_003AC_0021_003FUsers_003Fstarm_003FAppData_003FLocal_003FTemp_003FSandboxFiles_003FRewuwer_003FDanyxuq_002Easm/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADycuvaq_002Easm_002Fl_003AC_0021_003FUsers_003Fstarm_003FAppData_003FLocal_003FTemp_003FSandboxFiles_003FWoqosub_003FDycuvaq_002Easm/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADycuvaq_002Easm_002Fl_003AC_0021_003FUsers_003Fstarm_003FAppData_003FLocal_003FTemp_003FSandboxFiles_003FWoqosub_003FDycuvaq_002Easm/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFunction_002Eh_002Fl_003AD_0021_003FProgram_0020Files_003FEpic_0020Games_003FUE_005F5_002E6_003FEngine_003FSource_003FRuntime_003FCore_003FPublic_003FTemplates_003FFunction_002Eh/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFunction_002Eh_002Fl_003AD_0021_003FProgram_0020Files_003FEpic_0020Games_003FUE_005F5_002E6_003FEngine_003FSource_003FRuntime_003FCore_003FPublic_003FTemplates_003FFunction_002Eh/@EntryIndexedValue">ForceIncluded</s:String>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+208
View File
@@ -182,6 +182,16 @@ void ADynamicIronBlock::InitializeBoxMesh()
// 如果设置了材质,创建动态材质实例并应用 // 如果设置了材质,创建动态材质实例并应用
if (IronMaterial) 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); DynamicMaterialInstance = UMaterialInstanceDynamic::Create(IronMaterial, this);
if (DynamicMaterialInstance) 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(); DynMeshComp->NotifyMeshUpdated();
@@ -199,6 +226,13 @@ void ADynamicIronBlock::InitializeBoxMesh()
// 初始化温度网格 // 初始化温度网格
InitializeTemperatureGrid(); 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)"), UE_LOG(LogTemp, Log, TEXT("DynamicIronBlock: Box mesh initialized with size (%f, %f, %f)"),
BoxSize.X, BoxSize.Y, BoxSize.Z); BoxSize.X, BoxSize.Y, BoxSize.Z);
} }
@@ -567,6 +601,9 @@ void ADynamicIronBlock::HeatRegion(FVector WorldCenter, float Radius, float Temp
// 更新材质温度参数以显示温度变化 // 更新材质温度参数以显示温度变化
UpdateMaterialTemperature(); UpdateMaterialTemperature();
// 更新顶点颜色(基于体素温度)
UpdateVertexColors();
} }
float ADynamicIronBlock::SampleTemperatureAtPosition(const FVector& LocalPosition) const 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缓冲区管理实现 ========== // ========== GPU缓冲区管理实现 ==========
void ADynamicIronBlock::CreateGPUBuffers() void ADynamicIronBlock::CreateGPUBuffers()
@@ -947,6 +1152,9 @@ void ADynamicIronBlock::DownloadTemperatureDataFromGPU()
// 更新材质温度参数以反映新的温度 // 更新材质温度参数以反映新的温度
UpdateMaterialTemperature(); UpdateMaterialTemperature();
// 更新顶点颜色(基于体素温度)
UpdateVertexColors();
}); });
}); });
} }
+11
View File
@@ -142,6 +142,12 @@ public:
UFUNCTION(BlueprintCallable, Category = "Hammer Impact") UFUNCTION(BlueprintCallable, Category = "Hammer Impact")
void OnHammerImpact(FVector HitLocation, FVector HitNormal, float ImpactRadius, float ImpactDepth, float ImpactForce = 1.0f); void OnHammerImpact(FVector HitLocation, FVector HitNormal, float ImpactRadius, float ImpactDepth, float ImpactForce = 1.0f);
/**
* 调试函数 - 输出顶点颜色信息到日志和屏幕
*/
UFUNCTION(BlueprintCallable, Category = "Temperature System|Debug")
void DebugPrintVertexColors();
protected: protected:
// 当游戏开始或生成时调用 // 当游戏开始或生成时调用
virtual void BeginPlay() override; virtual void BeginPlay() override;
@@ -267,6 +273,11 @@ private:
*/ */
void UpdateMaterialTemperature(); void UpdateMaterialTemperature();
/**
* 更新网格顶点颜色(基于每个顶点的温度体素采样)
*/
void UpdateVertexColors();
// ========== GPU计算系统(Phase 2) ========== // ========== GPU计算系统(Phase 2) ==========
// GPU缓冲区(Ping-Pong双缓冲) // GPU缓冲区(Ping-Pong双缓冲)