Compare commits

..

5 Commits

Author SHA1 Message Date
zhangqing e647723a7a 调整细节 2025-12-08 18:24:10 +08:00
zhangqing dd16f0123a 实现温度系统CPU-GPU双向同步及调试功能
功能改进:
- HeatRegion后自动上传温度数据到GPU
- Tick中GPU计算后自动下载温度数据到CPU
- DownloadTemperatureDataFromGPU回调中自动更新顶点颜色

调试功能:
- HeatRegion后输出距离Hit点最近的4个体素温度
- 包含体素坐标、距离和温度信息,便于调试温度计算

配置优化:
- 温度更新间隔从0.1秒调整为1.0秒,降低性能开销

技术细节:
- 使用异步任务确保线程安全
- GPU数据上传前检查缓冲区就绪状态
- 完整的CPU↔GPU温度数据同步流程

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 18:15:19 +08:00
zhangqing 33d0ff62de 重构温度计算:使用正确的RDG API替代SkipTracking
重构内容:
- 移除SkipTracking标志,使用FRDGPooledBuffer包装外部RHI缓冲区
- 使用RegisterExternalBuffer正确注册外部缓冲区到RDG系统
- 简化lambda捕获列表,移除不需要的SRV/UAV引用
- 添加详细的日志输出以便调试

技术改进:
- RDG系统现在能正确追踪资源依赖和状态转换
- 自动处理内存屏障和资源同步
- 符合UE5最佳实践

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 16:46:42 +08:00
zhangqing 8bde527782 合并 2025-12-08 10:45:13 +08:00
zhangqing 08d12c4d47 调整灯光,调整材质 2025-12-02 19:08:32 +08:00
46 changed files with 108 additions and 39 deletions
+2 -1
View File
@@ -6,7 +6,8 @@
"Bash(\"E:\\MiceCola\\work\\UE_5_6\\Engine\\Build\\BatchFiles\\Build.bat\" BladeSmithEditor Win64 Development -Project=\"E:\\MiceCola\\work\\BladeSmith\\BladeSmith.uproject\" -WaitMutex -FromMsBuild)",
"Bash(dir:*)",
"Bash(git add:*)",
"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:*)"
],
"deny": [],
"ask": []
+1
View File
@@ -6,5 +6,6 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATedilij_002Easm_002Fl_003AC_0021_003FUsers_003Fstarm_003FAppData_003FLocal_003FTemp_003FSandboxFiles_003FKotyxod_003FTedilij_002Easm/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATextureDefines_002Eh_002Fl_003AD_0021_003FProgram_0020Files_003FEpic_0020Games_003FUE_005F5_002E6_003FEngine_003FSource_003FRuntime_003FEngine_003FClasses_003FEngine_003FTextureDefines_002Eh/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AShaderParameterStruct_002Eh_002Fl_003AD_0021_003FProgram_0020Files_003FEpic_0020Games_003FUE_005F5_002E6_003FEngine_003FSource_003FRuntime_003FRenderCore_003FPublic_003FShaderParameterStruct_002Eh/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATuvased_002Easm_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FUsers_003FAdministrator_003FAppData_003FLocal_003FTemp_003FSandboxFiles_003FKonywix_003FTuvased_002Easm/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AUnrealMathUtility_002Eh_002Fl_003AD_0021_003FProgram_0020Files_003FEpic_0020Games_003FUE_005F5_002E6_003FEngine_003FSource_003FRuntime_003FCore_003FPublic_003FMath_003FUnrealMathUtility_002Eh/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AArray_002Eh_002Fl_003AD_0021_003FProgram_0020Files_003FEpic_0020Games_003FUE_005F5_002E6_003FEngine_003FSource_003FRuntime_003FCore_003FPublic_003FContainers_003FArray_002Eh/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
+1
View File
@@ -38,6 +38,7 @@ r.DefaultFeature.LocalExposure.HighlightContrastScale=0.8
r.DefaultFeature.LocalExposure.ShadowContrastScale=0.8
r.DefaultFeature.AutoExposure=False
r.Lumen.TraceMeshSDFs=1
[/Script/WindowsTargetPlatform.WindowsTargetSettings]
DefaultGraphicsRHI=DefaultGraphicsRHI_DX12
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+102 -36
View File
@@ -78,9 +78,9 @@ void ADynamicIronBlock::Tick(float DeltaTime)
// 重置计时器
TimeSinceLastUpdate = 0.0f;
// 下载数据并更新顶点颜色(可选,性能开销较大)
// DownloadTemperatureDataFromGPU();
// UpdateVertexColors();
// 从GPU下载温度数据并更新顶点颜色
DownloadTemperatureDataFromGPU();
// 注意:UpdateVertexColors()会在DownloadTemperatureDataFromGPU的回调中异步调用
}
}
@@ -481,6 +481,61 @@ void ADynamicIronBlock::HeatRegion(FVector WorldCenter, float Radius, float Temp
UE_LOG(LogTemp, Log, TEXT("DynamicIronBlock: Heated %d voxels in region (center: %s, radius: %.2f)"),
AffectedVoxels, *LocalCenter.ToString(), Radius);
// 调试:输出距离Hit点最近的4个体素的温度
struct FVoxelDebugInfo
{
FIntVector Coord;
float Distance;
float Temperature;
};
TArray<FVoxelDebugInfo> NearestVoxels;
// 查找最近的体素
for (int32 Z = MinZ; Z <= MaxZ; ++Z)
{
for (int32 Y = MinY; Y <= MaxY; ++Y)
{
for (int32 X = MinX; X <= MaxX; ++X)
{
FVector VoxelCenter = GridOrigin + FVector(
(X + 0.5f) * VoxelSizeCM.X,
(Y + 0.5f) * VoxelSizeCM.Y,
(Z + 0.5f) * VoxelSizeCM.Z
);
float Distance = FVector::Dist(VoxelCenter, LocalCenter);
int32 Index = GetTemperatureIndex(X, Y, Z);
FVoxelDebugInfo Info;
Info.Coord = FIntVector(X, Y, Z);
Info.Distance = Distance;
Info.Temperature = TemperatureGrid[Index].Temperature;
NearestVoxels.Add(Info);
}
}
}
// 按距离排序
NearestVoxels.Sort([](const FVoxelDebugInfo& A, const FVoxelDebugInfo& B) {
return A.Distance < B.Distance;
});
// 输出最近的4个体素
UE_LOG(LogTemp, Warning, TEXT("=== Nearest 4 Voxels to Hit Point ==="));
for (int32 i = 0; i < FMath::Min(4, NearestVoxels.Num()); ++i)
{
const FVoxelDebugInfo& Info = NearestVoxels[i];
UE_LOG(LogTemp, Warning, TEXT(" Voxel[%d,%d,%d] Distance=%.2fcm Temperature=%.1f°C"),
Info.Coord.X, Info.Coord.Y, Info.Coord.Z, Info.Distance, Info.Temperature);
}
// 将更新后的温度数据上传到GPU
if (bGPUBuffersReady.load(std::memory_order_acquire))
{
UploadTemperatureDataToGPU();
UE_LOG(LogTemp, Log, TEXT("DynamicIronBlock: Temperature data uploaded to GPU after HeatRegion"));
}
// 更新顶点颜色以显示温度变化
UpdateVertexColors();
}
@@ -848,6 +903,9 @@ void ADynamicIronBlock::DownloadTemperatureDataFromGPU()
}
UE_LOG(LogTemp, Log, TEXT("DynamicIronBlock: Temperature data downloaded from GPU"));
// 更新顶点颜色以反映新的温度
UpdateVertexColors();
});
});
}
@@ -856,6 +914,8 @@ void ADynamicIronBlock::DispatchTemperatureCompute(float DeltaTime)
{
if (!TemperatureBufferA.IsValid() || !TemperatureBufferB.IsValid())
{
UE_LOG(LogTemp, Error, TEXT("DynamicIronBlock: Temperature buffers not valid! A=%d B=%d"),
TemperatureBufferA.IsValid(), TemperatureBufferB.IsValid());
return;
}
@@ -867,30 +927,22 @@ void ADynamicIronBlock::DispatchTemperatureCompute(float DeltaTime)
float ForgeMin = ForgeTemperatureMin;
float ForgeMax = ForgeTemperatureMax;
// Ping-Pong缓冲区引用
UE_LOG(LogTemp, Log, TEXT("DynamicIronBlock: Dispatching temperature compute - Resolution=(%d,%d,%d), DeltaTime=%.4f"),
Resolution.X, Resolution.Y, Resolution.Z, DeltaTime);
// Ping-Pong缓冲区引用(捕获到lambda传递给RDG)
FBufferRHIRef InputBuffer = bUseBufferA ? TemperatureBufferA : TemperatureBufferB;
FBufferRHIRef OutputBuffer = bUseBufferA ? TemperatureBufferB : TemperatureBufferA;
FBufferRHIRef FlagsBuffer = SurfaceVoxelFlagsBuffer;
FBufferRHIRef PlasticityBuf = PlasticityBuffer;
// 创建SRV/UAV(在游戏线程创建,捕获到lambda)
FShaderResourceViewRHIRef InputSRV = TemperatureSRV_A;
FShaderResourceViewRHIRef InputSRV_B = TemperatureSRV_B;
FShaderResourceViewRHIRef FlagsSRV = SurfaceVoxelSRV;
FUnorderedAccessViewRHIRef OutputUAV_A = TemperatureUAV_A;
FUnorderedAccessViewRHIRef OutputUAV_B = TemperatureUAV_B;
FUnorderedAccessViewRHIRef PlasticityUAV_Ref = PlasticityUAV;
bool bReadFromA = bUseBufferA;
// 切换缓冲区(下次Tick使用新的缓冲区)
bUseBufferA = !bUseBufferA;
// 调度GPU计算(直接使用RHI,不用RDG)
// 调度GPU计算(使用RDG正确的资源管理)
ENQUEUE_RENDER_COMMAND(DispatchTemperatureCS)(
[Resolution, Conductivity, Cooling, Ambient, ForgeMin, ForgeMax, DeltaTime,
InputBuffer, OutputBuffer, FlagsBuffer, PlasticityBuf,
InputSRV, InputSRV_B, FlagsSRV, OutputUAV_A, OutputUAV_B, PlasticityUAV_Ref, bReadFromA]
InputBuffer, OutputBuffer, FlagsBuffer, PlasticityBuf]
(FRHICommandListImmediate& RHICmdList)
{
// 检查ShaderMap是否有效
@@ -909,21 +961,30 @@ void ADynamicIronBlock::DispatchTemperatureCompute(float DeltaTime)
return;
}
// 使用RDG(简化版本 - 创建临时缓冲区)
UE_LOG(LogTemp, Log, TEXT("DynamicIronBlock [RenderThread]: Shader valid, creating RDG..."));
// 使用RDG
FRDGBuilder GraphBuilder(RHICmdList, RDG_EVENT_NAME("TemperatureConduction"));
// 创建RDG缓冲区描述
FRDGBufferDesc TempBufferDesc = FRDGBufferDesc::CreateBufferDesc(sizeof(float), InputBuffer->GetSize() / sizeof(float));
FRDGBufferDesc FlagsBufferDesc = FRDGBufferDesc::CreateBufferDesc(sizeof(uint32), FlagsBuffer->GetSize() / sizeof(uint32));
// 将外部RHI缓冲区正确注册到RDG系统
// 创建缓冲区描述符
const uint32 NumElements = InputBuffer->GetSize() / sizeof(float);
FRDGBufferDesc TempBufferDesc = FRDGBufferDesc::CreateBufferDesc(sizeof(float), NumElements);
FRDGBufferDesc FlagsBufferDesc = FRDGBufferDesc::CreateBufferDesc(sizeof(uint32), NumElements);
// 创建RDG缓冲区
FRDGBufferRef InputTempRDG = GraphBuilder.CreateBuffer(TempBufferDesc, TEXT("InputTemperatureBuffer"));
FRDGBufferRef OutputTempRDG = GraphBuilder.CreateBuffer(TempBufferDesc, TEXT("OutputTemperatureBuffer"));
FRDGBufferRef FlagsRDG = GraphBuilder.CreateBuffer(FlagsBufferDesc, TEXT("SurfaceVoxelFlagsBuffer"));
FRDGBufferRef PlasticityRDG = GraphBuilder.CreateBuffer(TempBufferDesc, TEXT("PlasticityBuffer"));
// 创建FRDGPooledBuffer并注册
TRefCountPtr<FRDGPooledBuffer> InputPooledBuffer = new FRDGPooledBuffer(RHICmdList, InputBuffer, TempBufferDesc, NumElements, TEXT("InputTemperatureBuffer"));
TRefCountPtr<FRDGPooledBuffer> OutputPooledBuffer = new FRDGPooledBuffer(RHICmdList, OutputBuffer, TempBufferDesc, NumElements, TEXT("OutputTemperatureBuffer"));
TRefCountPtr<FRDGPooledBuffer> FlagsPooledBuffer = new FRDGPooledBuffer(RHICmdList, FlagsBuffer, FlagsBufferDesc, NumElements, TEXT("SurfaceVoxelFlagsBuffer"));
TRefCountPtr<FRDGPooledBuffer> PlasticityPooledBuffer = new FRDGPooledBuffer(RHICmdList, PlasticityBuf, TempBufferDesc, NumElements, TEXT("PlasticityBuffer"));
// TODO: 添加数据复制Pass(从RHI到RDG)
// 暂时跳过,shader会处理未初始化数据
FRDGBufferRef InputTempRDG = GraphBuilder.RegisterExternalBuffer(InputPooledBuffer);
FRDGBufferRef OutputTempRDG = GraphBuilder.RegisterExternalBuffer(OutputPooledBuffer);
FRDGBufferRef FlagsRDG = GraphBuilder.RegisterExternalBuffer(FlagsPooledBuffer);
FRDGBufferRef PlasticityRDG = GraphBuilder.RegisterExternalBuffer(PlasticityPooledBuffer);
UE_LOG(LogTemp, Log, TEXT("DynamicIronBlock [RenderThread]: External RHI buffers registered to RDG, setting shader parameters..."));
// 设置Shader参数
FTemperatureComputeShader::FParameters* PassParameters = GraphBuilder.AllocParameters<FTemperatureComputeShader::FParameters>();
@@ -935,10 +996,13 @@ void ADynamicIronBlock::DispatchTemperatureCompute(float DeltaTime)
PassParameters->ForgeTemperatureMax = ForgeMax;
PassParameters->DeltaTime = DeltaTime;
PassParameters->InputTemperatureBuffer = GraphBuilder.CreateSRV(InputTempRDG, PF_R32_FLOAT);
PassParameters->SurfaceVoxelFlagsBuffer = GraphBuilder.CreateSRV(FlagsRDG, PF_R32_UINT);
PassParameters->OutputTemperatureBuffer = GraphBuilder.CreateUAV(OutputTempRDG, PF_R32_FLOAT);
PassParameters->OutputPlasticityBuffer = GraphBuilder.CreateUAV(PlasticityRDG, PF_R32_FLOAT);
// 创建SRV和UAV(使用正确注册的RDG资源)
PassParameters->InputTemperatureBuffer = GraphBuilder.CreateSRV(FRDGBufferSRVDesc(InputTempRDG, PF_R32_FLOAT));
PassParameters->SurfaceVoxelFlagsBuffer = GraphBuilder.CreateSRV(FRDGBufferSRVDesc(FlagsRDG, PF_R32_UINT));
PassParameters->OutputTemperatureBuffer = GraphBuilder.CreateUAV(FRDGBufferUAVDesc(OutputTempRDG, PF_R32_FLOAT));
PassParameters->OutputPlasticityBuffer = GraphBuilder.CreateUAV(FRDGBufferUAVDesc(PlasticityRDG, PF_R32_FLOAT));
UE_LOG(LogTemp, Log, TEXT("DynamicIronBlock [RenderThread]: Shader parameters set, calculating group count..."));
// 计算线程组数量
FIntVector GroupSize = FTemperatureComputeShader::GetGroupSize();
@@ -948,6 +1012,9 @@ void ADynamicIronBlock::DispatchTemperatureCompute(float DeltaTime)
FMath::DivideAndRoundUp(Resolution.Z, GroupSize.Z)
);
UE_LOG(LogTemp, Log, TEXT("DynamicIronBlock [RenderThread]: GroupCount=(%d,%d,%d), adding compute pass..."),
GroupCount.X, GroupCount.Y, GroupCount.Z);
// 添加计算Pass
FComputeShaderUtils::AddPass(
GraphBuilder,
@@ -957,13 +1024,12 @@ void ADynamicIronBlock::DispatchTemperatureCompute(float DeltaTime)
GroupCount
);
// TODO: 添加数据复制Pass(从RDG回RHI)
// 暂时跳过,需要实现正确的缓冲区提取
UE_LOG(LogTemp, Log, TEXT("DynamicIronBlock [RenderThread]: Compute pass added, executing RDG..."));
// 执行RDG
// 执行RDG,自动处理资源转换和同步
GraphBuilder.Execute();
UE_LOG(LogTemp, Warning, TEXT("DynamicIronBlock: Temperature compute dispatched (%d x %d x %d groups) - Data copy not yet implemented"),
UE_LOG(LogTemp, Log, TEXT("DynamicIronBlock: Temperature compute dispatched successfully (%d x %d x %d groups)"),
GroupCount.X, GroupCount.Y, GroupCount.Z);
});
}
+1 -1
View File
@@ -257,7 +257,7 @@ private:
bool bUseBufferA = true; // Ping-Pong标志
float TimeSinceLastUpdate = 0.0f; // 距离上次温度更新的时间
float TemperatureUpdateInterval = 0.1f; // 温度更新间隔(秒)
float TemperatureUpdateInterval = 1.0f; // 温度更新间隔(秒)
// GPU缓冲区是否已准备好(线程安全标志)
std::atomic<bool> bGPUBuffersReady{false};
+1 -1
View File
@@ -29,7 +29,7 @@ DynMaterial(nullptr), DynCalMaterial(nullptr)
PrimaryActorTick.bCanEverTick = true;
RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
StaticMeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMeshComponent"));
StaticMeshComp->AttachToComponent(RootComponent,FAttachmentTransformRules::SnapToTargetIncludingScale);
//StaticMeshComp->AttachToComponent(RootComponent,FAttachmentTransformRules::SnapToTargetIncludingScale);
//RootComponent = StaticMeshComp;
}
void AIronBlock::PostInitProperties()
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 290 KiB