diff --git a/BladeSmith.sln.DotSettings.user b/BladeSmith.sln.DotSettings.user index 58aa921..571bc59 100644 --- a/BladeSmith.sln.DotSettings.user +++ b/BladeSmith.sln.DotSettings.user @@ -2,4 +2,6 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded + ForceIncluded ForceIncluded \ No newline at end of file diff --git a/Content/StarterContent/Audio/Collapse01.uasset b/Content/StarterContent/Audio/Collapse01.uasset index 9c68be4..2cfc455 100644 Binary files a/Content/StarterContent/Audio/Collapse01.uasset and b/Content/StarterContent/Audio/Collapse01.uasset differ diff --git a/Content/StarterContent/HDRI/HDRI_Epic_Courtyard_Daylight.uasset b/Content/StarterContent/HDRI/HDRI_Epic_Courtyard_Daylight.uasset index bc93f51..9b1f1be 100644 Binary files a/Content/StarterContent/HDRI/HDRI_Epic_Courtyard_Daylight.uasset and b/Content/StarterContent/HDRI/HDRI_Epic_Courtyard_Daylight.uasset differ diff --git a/Shaders/DeformationCS.usf b/Shaders/DeformationCS.usf new file mode 100644 index 0000000..3f6dcab --- /dev/null +++ b/Shaders/DeformationCS.usf @@ -0,0 +1,90 @@ +// DeformationCS.usf + +#include "/Engine/Public/Platform.ush" + +// ----------------------------------------------------------------------------- +// 1. 输入输出定义 +// ----------------------------------------------------------------------------- +// 必须与 C++ 的 SHADER_PARAMETER_RDG_TEXTURE_SRV 匹配 +Texture2D InputTexture; +// 必须与 C++ 的 SHADER_PARAMETER_RDG_TEXTURE_UAV 匹配 +RWTexture2D 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; + } +} \ No newline at end of file diff --git a/Shaders/Private/DeformationCS.usf b/Shaders/Private/DeformationCS.usf deleted file mode 100644 index 445c94b..0000000 --- a/Shaders/Private/DeformationCS.usf +++ /dev/null @@ -1,64 +0,0 @@ -// DeformationCS.usf -#include "/Engine/Public/Platform.ush" -// 输入输出定义 -Texture2D InputTexture; -RWTexture2D 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; - } -} \ No newline at end of file diff --git a/Source/BladeSmith/BladeSmith.Build.cs b/Source/BladeSmith/BladeSmith.Build.cs index 399b74d..841e79f 100644 --- a/Source/BladeSmith/BladeSmith.Build.cs +++ b/Source/BladeSmith/BladeSmith.Build.cs @@ -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" }); + } } diff --git a/Source/BladeSmith/FDeformComputeShader.cpp b/Source/BladeSmith/FDeformComputeShader.cpp index c2e9d08..2abd903 100644 --- a/Source/BladeSmith/FDeformComputeShader.cpp +++ b/Source/BladeSmith/FDeformComputeShader.cpp @@ -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 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) diff --git a/Source/BladeSmith/FDeformComputeShader.h b/Source/BladeSmith/FDeformComputeShader.h index f77c5ff..40f45a0 100644 --- a/Source/BladeSmith/FDeformComputeShader.h +++ b/Source/BladeSmith/FDeformComputeShader.h @@ -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,43 +47,58 @@ 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, OutputTexture) + SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, InputTexture) + SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D, 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) { FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment); OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE_X"), 8); OutEnvironment.SetDefine(TEXT("THREADGROUP_SIZE_Y"), 8); } - - // 分派函数 - static void Dispatch( - FRHICommandListImmediate& RHICmdList, - const FDeformationCSDispatchParams& Params); + }; \ No newline at end of file diff --git a/Source/BladeSmith/IronBlock.cpp b/Source/BladeSmith/IronBlock.cpp index 5ee46be..7c9f76c 100644 --- a/Source/BladeSmith/IronBlock.cpp +++ b/Source/BladeSmith/IronBlock.cpp @@ -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(); + + // 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 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(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)