调试shader

This commit is contained in:
2025-11-11 00:19:51 +08:00
parent d2b4a90251
commit f12fef4edd
9 changed files with 205 additions and 177 deletions
+2
View File
@@ -2,4 +2,6 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAdpcmAudioDecoder_002EBuild_002Ecs_002Fl_003AD_0021_003FProgram_0020Files_003FEpic_0020Games_003FUE_005F5_002E5_003FEngine_003FSource_003FRuntime_003FAdpcmAudioDecoder_003FModule_003FAdpcmAudioDecoder_002EBuild_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AGajuzad_002Easm_002Fl_003AC_0021_003FUsers_003Fstarm_003FAppData_003FLocal_003FTemp_003FSandboxFiles_003FXexaveh_003FGajuzad_002Easm/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AJicekul_002Easm_002Fl_003AC_0021_003FUsers_003Fstarm_003FAppData_003FLocal_003FTemp_003FSandboxFiles_003FLeqybub_003FJicekul_002Easm/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATemuhyh_002Easm_002Fl_003AC_0021_003FUsers_003Fstarm_003FAppData_003FLocal_003FTemp_003FSandboxFiles_003FCyfibag_003FTemuhyh_002Easm/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AWorujoq_002Easm_002Fl_003AC_0021_003FUsers_003Fstarm_003FAppData_003FLocal_003FTemp_003FSandboxFiles_003FJakoqel_003FWorujoq_002Easm/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AZilegoz_002Easm_002Fl_003AC_0021_003FUsers_003Fstarm_003FAppData_003FLocal_003FTemp_003FSandboxFiles_003FZucifip_003FZilegoz_002Easm/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
Binary file not shown.
+90
View File
@@ -0,0 +1,90 @@
// DeformationCS.usf
#include "/Engine/Public/Platform.ush"
// -----------------------------------------------------------------------------
// 1. 输入输出定义
// -----------------------------------------------------------------------------
// 必须与 C++ 的 SHADER_PARAMETER_RDG_TEXTURE_SRV 匹配
Texture2D<float4> InputTexture;
// 必须与 C++ 的 SHADER_PARAMETER_RDG_TEXTURE_UAV 匹配
RWTexture2D<float4> OutputTexture;
// -----------------------------------------------------------------------------
// 2. 参数缓冲区 (必须与 C++ FParameters 结构体严格匹配)
// -----------------------------------------------------------------------------
cbuffer Parameters
{
float3 ImpactPoint;
float ImpactForce;
float3 ImpactNormal;
float DeformationRadius;
float Plasticity;
int3 TextureSize;
// 修正后的参数:对应 C++ 的 FIntVector4 UpdateRegionParam
// 分量顺序: (Min.X, Min.Y, Max.X, Max.Y)
int4 UpdateRegionParam;
};
// -----------------------------------------------------------------------------
// 3. 线程组大小和入口点
// -----------------------------------------------------------------------------
#define THREADGROUP_SIZE_X 8
#define THREADGROUP_SIZE_Y 8
[numthreads(THREADGROUP_SIZE_X, THREADGROUP_SIZE_Y, 1)]
void MainCompute( // 注意: 建议使用 MainCompute,如果 C++ 注册的是 MainCompute
uint3 GroupID : SV_GroupID,
uint3 GroupThreadID : SV_GroupThreadID,
uint3 DispatchThreadID : SV_DispatchThreadID // 全局线程 ID
)
{
// -------------------------------------------------------------------------
// 4. 坐标计算与边界检查
// -------------------------------------------------------------------------
// DispatchThreadID 从 0 开始,代表在调度区域内的偏移量。
// 我们将其加上 UpdateRegionParam.xy (Min.X, Min.Y) 得到全局像素坐标。
int2 PixelCoord = DispatchThreadID.xy + int2(UpdateRegionParam.x, UpdateRegionParam.y);
// 边界检查:检查是否超出 UpdateRegionParam.zw (Max.X, Max.Y)
if (PixelCoord.x < UpdateRegionParam.x || PixelCoord.x >= UpdateRegionParam.z ||
PixelCoord.y < UpdateRegionParam.y || PixelCoord.y >= UpdateRegionParam.w)
{
// 虽然我们调度时已经只调度了需要的区域,但为了安全起见,保留检查。
// 理论上,如果 C++ 端调度正确,这个检查应该很少触发。
return;
}
// -------------------------------------------------------------------------
// 5. 变形计算逻辑 (与之前相同)
// -------------------------------------------------------------------------
// 从输入纹理读取位置
// Load 需要 int3,第三个分量 (MipLevel) 设为 0
float4 OriginalPos = InputTexture.Load(int3(PixelCoord, 0));
// 计算到碰撞点的距离
float dist = distance(OriginalPos.xyz, ImpactPoint);
// 在变形半径内处理
if (dist < DeformationRadius)
{
// 计算变形衰减 (高斯衰减)
float falloff = exp(-(dist * dist) / (2.0 * DeformationRadius * DeformationRadius));
// 计算变形量 (考虑法线方向)
float3 deformation = ImpactNormal * ImpactForce * falloff * 0.01;
// 应用塑性变形
float3 newPos = OriginalPos.xyz + deformation * Plasticity;
// 写入新位置
OutputTexture[PixelCoord] = float4(newPos, OriginalPos.w);
}
else
{
// 保持原位置
OutputTexture[PixelCoord] = OriginalPos;
}
}
-64
View File
@@ -1,64 +0,0 @@
// DeformationCS.usf
#include "/Engine/Public/Platform.ush"
// 输入输出定义
Texture2D<float4> InputTexture;
RWTexture2D<float4> OutputTexture;
// 参数缓冲区
cbuffer Parameters
{
float3 ImpactPoint;
float ImpactForce;
float3 ImpactNormal;
float DeformationRadius;
float Plasticity;
int3 TextureSize;
int3 UpdateRegionMin;
int3 UpdateRegionSize;
};
// 线程组大小
#define THREADGROUP_SIZE_X 8
#define THREADGROUP_SIZE_Y 8
[numthreads(THREADGROUP_SIZE_X, THREADGROUP_SIZE_Y, 1)]
void MainCS(
uint3 GroupID : SV_GroupID,
uint3 GroupThreadID : SV_GroupThreadID,
uint3 DispatchThreadID : SV_DispatchThreadID
)
{
// 计算全局像素坐标
int2 PixelCoord = DispatchThreadID.xy + int2(UpdateRegionMin.xy);
// 检查是否在有效区域内
if (PixelCoord.x >= UpdateRegionMin.x + UpdateRegionSize.x ||
PixelCoord.y >= UpdateRegionMin.y + UpdateRegionSize.y)
{
return;
}
// 从输入纹理读取位置
float4 OriginalPos = InputTexture.Load(int3(PixelCoord, 0));
// 计算到碰撞点的距离
float dist = distance(OriginalPos.xyz, ImpactPoint);
// 在变形半径内处理
if (dist < DeformationRadius)
{
// 计算变形衰减 (高斯衰减)
float falloff = exp(-(dist * dist) / (2.0 * DeformationRadius * DeformationRadius));
// 计算变形量 (考虑法线方向)
float3 deformation = ImpactNormal * ImpactForce * falloff * 0.01;
// 应用塑性变形
float3 newPos = OriginalPos.xyz + deformation * Plasticity;
// 写入新位置
OutputTexture[PixelCoord] = float4(newPos, OriginalPos.w);
}
else
{
// 保持原位置
OutputTexture[PixelCoord] = OriginalPos;
}
}
+4
View File
@@ -8,6 +8,8 @@ public class BladeSmith : ModuleRules
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
// 如果你的模块类型是 Runtime 或 Gameplay 相关的,则添加这行:
// bFasterWithoutUnity = false; // 确保非 Unity 构建也能正确加载
PublicDependencyModuleNames.AddRange(new string[] {
"Core",
"CoreUObject",
@@ -16,11 +18,13 @@ public class BladeSmith : ModuleRules
"EnhancedInput",
"RenderCore",
"RHI",
"RenderCore",
"Renderer",
"PhysicsCore",
"AudioExtensions",
"AudioMixer",
"AudioPlatformConfiguration"
});
}
}
+1 -35
View File
@@ -12,41 +12,7 @@
FThreadSafeDeformationParams GDeformationParams;
// 实现Compute Shader
IMPLEMENT_GLOBAL_SHADER(FDeformationCS, "/Shaders/Private/DeformationCS.usf", "MainCS", SF_Compute);
// 分派函数实现
void FDeformationCS::Dispatch(
FRHICommandListImmediate& RHICmdList,
const FDeformationCSDispatchParams& Params)
{
// 创建参数结构
FParameters Parameters;
Parameters.ImpactPoint = FVector3f(Params.ImpactPoint);
Parameters.ImpactNormal = FVector3f(Params.ImpactNormal);
Parameters.ImpactForce = Params.ImpactForce;
Parameters.DeformationRadius = Params.DeformationRadius;
Parameters.Plasticity = Params.Plasticity;
Parameters.InputTexture = Params.InputTexture;
Parameters.OutputTexture = Params.OutputTexture;
Parameters.TextureSize = Params.TextureSize;
Parameters.UpdateRegionMin = FIntVector(Params.UpdateRegion.Min.X, Params.UpdateRegion.Min.Y, 0);
Parameters.UpdateRegionSize = FIntVector(Params.UpdateRegion.Width(), Params.UpdateRegion.Height(), 1);
// 计算线程组数量
const int32 ThreadGroupSizeX = 8;
const int32 ThreadGroupSizeY = 8;
const int32 ThreadGroupSizeZ = 1;
const int32 GroupCountX = FMath::DivideAndRoundUp(Params.UpdateRegion.Width(), ThreadGroupSizeX);
const int32 GroupCountY = FMath::DivideAndRoundUp(Params.UpdateRegion.Height(), ThreadGroupSizeY);
const int32 GroupCountZ = 1;
// 分派Compute Shader
TShaderMapRef<FDeformationCS> ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel));
SetComputePipelineState(RHICmdList, ComputeShader.GetComputeShader());
SetShaderParameters(RHICmdList, ComputeShader, ComputeShader.GetComputeShader(), Parameters);
RHICmdList.DispatchComputeShader(GroupCountX, GroupCountY, GroupCountZ);
}
IMPLEMENT_GLOBAL_SHADER(FDeformComputeShader, "/Engine/Private/MiceCola/DeformationCS.usf", "MainCompute", SF_Compute);
// 线程安全参数管理
void FThreadSafeDeformationParams::AddParams(const FDeformationCSDispatchParams& NewParams)
+30 -20
View File
@@ -1,13 +1,8 @@
#pragma once
#include "GlobalShader.h"
// DeformComputeShader.h
// DeformationCS.h
#pragma once
#include "CoreMinimal.h"
#include "RHI.h"
#include "RHIResources.h"
#include "GlobalShader.h"
#include "ShaderParameterStruct.h"
#include "RenderGraphUtils.h" // 必须包含
// Compute Shader参数结构体
struct FDeformationCSDispatchParams
@@ -52,32 +47,51 @@ extern FThreadSafeDeformationParams GDeformationParams;
// DeformationCS.h (续)
// Compute Shader类
class FDeformationCS : public FGlobalShader
class FDeformComputeShader : public FGlobalShader
{
DECLARE_GLOBAL_SHADER(FDeformationCS);
SHADER_USE_PARAMETER_STRUCT(FDeformationCS, FGlobalShader);
DECLARE_GLOBAL_SHADER(FDeformComputeShader);
SHADER_USE_PARAMETER_STRUCT(FDeformComputeShader, FGlobalShader);
BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
// 碰撞参数
SHADER_PARAMETER(FVector3f, ImpactPoint)
SHADER_PARAMETER(FVector3f, ImpactNormal)
SHADER_PARAMETER(float, ImpactForce)
SHADER_PARAMETER(FVector3f, ImpactNormal)
SHADER_PARAMETER(float, DeformationRadius)
SHADER_PARAMETER(float, Plasticity)
// 纹理参数
SHADER_PARAMETER_TEXTURE(Texture2D, InputTexture)
SHADER_PARAMETER_UAV(RWTexture2D<float4>, OutputTexture)
SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, InputTexture)
SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float4>, OutputTexture)
// 更新区域
SHADER_PARAMETER(FIntVector, TextureSize)
SHADER_PARAMETER(FIntVector, UpdateRegionMin)
SHADER_PARAMETER(FIntVector, UpdateRegionSize)
SHADER_PARAMETER(FIntVector4, UpdateRegionParam)
END_SHADER_PARAMETER_STRUCT()
static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5);
return GetMaxSupportedFeatureLevel(Parameters.Platform) >= ERHIFeatureLevel::SM5;
}
// 2. ✨ 修复 Precache 错误的关键:实现 ShouldPrecachePermutation
// 我们告诉引擎:在开发模式下,请始终预缓存这个着色器。
static EShaderPermutationPrecacheRequest ShouldPrecachePermutation(const FGlobalShaderPermutationParameters& Parameters)
{
// 如果你的着色器没有使用任何模板或标志,只需返回 E_DEVELOPMENT 或 E_ALL。
return EShaderPermutationPrecacheRequest::Precached;
}
static bool ShouldCache(EShaderPlatform Platform)
{
return true;
}
// (假设你的 .usf 文件中线程组大小为 8x8x1)
static FIntVector GetGroupSize()
{
return FIntVector(8, 8, 1);
}
static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
@@ -87,8 +101,4 @@ class FDeformationCS : public FGlobalShader
OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE_Y"), 8);
}
// 分派函数
static void Dispatch(
FRHICommandListImmediate& RHICmdList,
const FDeformationCSDispatchParams& Params);
};
+76 -56
View File
@@ -2,7 +2,9 @@
#include "IronBlock.h"
// 确保包含了 RDG 所需的头文件
#include "RenderGraphBuilder.h"
#include "RenderGraphUtils.h" // FComputeShaderUtils::AddPass
#include "FDeformComputeShader.h" // 确保这个头文件存在且包含了 FDeformationCSDispatchParams
#include "StaticMeshResources.h"
#include "TextureResource.h"
@@ -12,7 +14,6 @@
#include "Materials/MaterialInstanceDynamic.h"
#include "PhysicsEngine/BodySetup.h"
#include "RHICommandList.h"
#include "RenderGraphBuilder.h" // 包含 FRDGBuilder
#include "Engine/Texture.h"
#include "GenericPlatform/GenericPlatformProcess.h"
@@ -328,11 +329,11 @@ void AIronBlock::ExecuteDeformationCS()
// --- 关键修复: 在游戏线程只获取 Input RHI Texture 句柄 ---
FTextureRHIRef InputRHI = GetRenderTargetRHI(ReadTarget);
FTextureRHIRef WriteRHI = GetRenderTargetRHI(WriteTarget); // 必须获取写入目标的RHI
// 检查 Input RHI 和 WriteTarget UObject 是否有效
if (!InputRHI.IsValid() || !WriteTarget)
if (!InputRHI.IsValid() || !WriteRHI.IsValid())
{
UE_LOG(LogTemp, Error, TEXT("Invalid texture RHI resources or WriteTarget UObject!"));
UE_LOG(LogTemp, Error, TEXT("Invalid texture RHI resources!"));
return;
}
@@ -355,68 +356,87 @@ void AIronBlock::ExecuteDeformationCS()
if (UpdateRegion.Min.X >= UpdateRegion.Max.X) UpdateRegion.Max.X = UpdateRegion.Min.X + 1;
if (UpdateRegion.Min.Y >= UpdateRegion.Max.Y) UpdateRegion.Max.Y = UpdateRegion.Min.Y + 1;
// 准备参数
FDeformationCSDispatchParams Params;
Params.ImpactPoint = CurrentImpactPoint; // 确保类型匹配 (FVector -> FVector3f)
Params.ImpactNormal = CurrentImpactNormal;
Params.ImpactForce = CurrentImpactForce;
Params.DeformationRadius = CurrentDeformationRadius;
Params.Plasticity = CurrentPlasticity;
Params.InputTexture = InputRHI;
//Params.OutputTexture = OutputUAV; // **直接使用RT的UAV**
Params.UpdateRegion = UpdateRegion;
Params.TextureSize = FIntVector(TexSize, TexSize, 1);
// 在渲染线程中执行Compute Shader
ENQUEUE_RENDER_COMMAND(ExecuteDeformationCS)(
[Params, WriteTarget](FRHICommandListImmediate& RHICmdList)
// --- 关键修改:使用 RDG ---
ENQUEUE_RENDER_COMMAND(ExecuteDeformationCS_RDG)(
[
// 捕获所有需要的参数
InputRHI,
WriteRHI,
CurrentImpactPoint = this->CurrentImpactPoint, // 拷贝一份
CurrentImpactNormal = this->CurrentImpactNormal,
CurrentImpactForce = this->CurrentImpactForce,
CurrentDeformationRadius = this->CurrentDeformationRadius,
CurrentPlasticity = this->CurrentPlasticity,
UpdateRegion, //
TexSize //
](FRHICommandListImmediate& RHICmdList)
{
// --- 现在我们在渲染线程上 ---
// 1. 创建 RDG Builder
FRDGBuilder builder(RHICmdList);
// 1. 从 UObject 获取 FTextureResource
FTextureResource* RTResource = WriteTarget->GetResource();
if (!RTResource)
// 2. 将我们的外部 RT 注册到 RDG 中
// 注意:我们使用 WriteRHI->GetDesc() 来获取纹理描述
FRDGTextureRef RDGReadTexture = builder.RegisterExternalTexture(
CreateRenderTarget(InputRHI, TEXT("DeformInputTex"))
);
FRDGTextureRef RDGWriteTexture = builder.RegisterExternalTexture(
CreateRenderTarget(WriteRHI, TEXT("DeformOutputTex"))
);
// 3. 分配着色器参数
FDeformComputeShader::FParameters* Params = builder.AllocParameters<FDeformComputeShader::FParameters>();
// 4. 填充 CPU 参数
Params->ImpactPoint = FVector3f(CurrentImpactPoint); // 注意:从 FVector 转为 FVector3f
Params->ImpactNormal = FVector3f(CurrentImpactNormal);
Params->ImpactForce = CurrentImpactForce;
Params->DeformationRadius = CurrentDeformationRadius;
Params->Plasticity = CurrentPlasticity;
Params->UpdateRegionParam = FIntVector4(UpdateRegion.Min.X, UpdateRegion.Min.Y, UpdateRegion.Max.X, UpdateRegion.Max.Y);
Params->TextureSize = FIntVector(TexSize, TexSize, 1);
// 5. ✨ 魔法发生的地方:RDG 为我们创建 SRV 和 UAV
// 这就是解决你 nullptr 问题的核心
Params->InputTexture = builder.CreateSRV(RDGReadTexture);
Params->OutputTexture = builder.CreateUAV(RDGWriteTexture);
// 6. 获取着色器实例
TShaderMapRef<FDeformComputeShader> ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel));
if (!ComputeShader.IsValid())
{
UE_LOG(LogTemp, Error, TEXT("Failed to get WriteTarget resource on render thread!"));
UE_LOG(LogTemp, Error, TEXT("FDeformComputeShader is not valid!"));
return;
}
// 2. 转换为 FTextureRenderTargetResource
FTextureRenderTargetResource* WriteRTResource = static_cast<FTextureRenderTargetResource*>(RTResource);
if (!WriteRTResource)
{
UE_LOG(LogTemp, Error, TEXT("Failed to cast to FTextureRenderTargetResource on render thread!"));
return;
}
// 7. 计算线程组数量
// (注意:你的USF需要处理 UpdateRegion,这里我们调度整个区域)
FIntVector NumGroups = FIntVector::DivideAndRoundUp(
FIntVector(UpdateRegion.Width(), UpdateRegion.Height(), 1),
FDeformComputeShader::GetGroupSize()
);
// 如果你的shader总是处理整个纹理,请使用:
// FIntVector NumGroups = FIntVector::DivideAndRoundUp(
// Params->TextureSize, FDeformComputeShader::GetGroupSize()
// );
// 3. ✨ 在渲染线程上调用 GetRenderTargetUAV()
FUnorderedAccessViewRHIRef OutputUAV = WriteRTResource->GetRenderTargetUAV();
// 8. 添加 Compute Pass
FComputeShaderUtils::AddPass(
builder,
RDG_EVENT_NAME("ExecuteDeformationCS"),
ComputeShader,
Params,
NumGroups
);
// 4. 检查是否成功
if (!OutputUAV.IsValid())
{
// 如果在这里仍然失败,说明 bCanCreateUAV=true 没有生效,
// 或者 RHI 后端没有为这个 RT 创建 UAV。
UE_LOG(LogTemp, Error, TEXT("GetRenderTargetUAV() returned null ON RENDER THREAD!"));
return;
}
// 5. 填充参数并调度
FDeformationCSDispatchParams RenderParams = Params;
RenderParams.OutputTexture = OutputUAV;
FDeformationCS::Dispatch(RHICmdList, RenderParams);
// 6. (重要) 添加一个UAV屏障
// 告诉GPU,Compute Shader对UAV的写入操作已完成,
// 在下一帧中,图形管线(材质)可以安全地将其作为 SRV (TextureSample) 读取。
RHICmdList.Transition(FRHITransitionInfo(OutputUAV, ERHIAccess::UAVCompute, ERHIAccess::SRVGraphics));
// 9. 执行 RDG (这会处理所有屏障和调度)
builder.Execute();
});
// 等待渲染命令完成,以便在CPU上读取 (如果需要立即更新碰撞体)
// 注意:这是一个同步点,会影响性能。
// --- 结束 RDG 修改 ---
// 确保渲染命令完成 (如果你需要立即更新碰撞体)
// FlushRenderingCommands();
// UpdateCollisionAsync(UpdateRegion, WriteTarget); // 异步更新碰撞体
// UpdateCollisionAsync(UpdateRegion, WriteTarget);
// --- 关键修复: 更新材质参数,使其下一帧读取我们刚刚写入的纹理 ---
if (DynMaterial)