UE5 中的computer shader使用

转载:UE5 中的computer shader使用 - 知乎 (zhihu.com)

目标

  1. 通过蓝图输入参数,经过Compture Shader做矩阵运算

流程

1. 新建插件
2. 插件设置
3. 声明和GPU内存对齐的参数结构
4. 声明Compture Shader结构
5. 参数绑定
6. 着色器实现
7. 分配 work groups
8. 计算和输出
9. 额外添加参数

1. 新建插件

新建空白插件即可,正常插件创建流程,看官方文档,

2. 插件设置

XXX.Build.cs
		PrivateDependencyModuleNames.AddRange(new string[]{"CoreUObject","Engine","Renderer","RenderCore","RHI","Projects"// ... add private dependencies that you statically link with here ...	});
XXX.uplugin
"Modules": [{"Name": "CS_Test","Type": "Runtime","LoadingPhase": "PostConfigInit"}]

3. 声明和GPU内存对齐的参数结构

struct CS_TEST_API FMySimpleComputeShaderDispatchParams
{int X;int Y;int Z;int Input[2];int Output;FMySimpleComputeShaderDispatchParams(int x, int y, int z): X(x), Y(y), Z(z){}
};

4. 声明Compture Shader结构和参数绑定

MySimpleComputeShader.cpp
#include "MySimpleComputeShader.h"
#include "../../../Shaders/Public/MySimpleComputeShader.h"
#include "PixelShaderUtils.h"
#include "RenderCore/Public/RenderGraphUtils.h"
#include "MeshPassProcessor.inl"
#include "StaticMeshResources.h"
#include "DynamicMeshBuilder.h"
#include "RenderGraphResources.h"
#include "GlobalShader.h"
#include "UnifiedBuffer.h"
#include "CanvasTypes.h"
#include "MaterialShader.h"DECLARE_STATS_GROUP(TEXT("MySimpleComputeShader"), STATGROUP_MySimpleComputeShader, STATCAT_Advanced);
DECLARE_CYCLE_STAT(TEXT("MySimpleComputeShader Execute"), STAT_MySimpleComputeShader_Execute, STATGROUP_MySimpleComputeShader);// This class carries our parameter declarations and acts as the bridge between cpp and HLSL.
class CS_TEST_API FMySimpleComputeShader : public FGlobalShader
{
public:DECLARE_GLOBAL_SHADER(FMySimpleComputeShader);SHADER_USE_PARAMETER_STRUCT(FMySimpleComputeShader, FGlobalShader);class FMySimpleComputeShader_Perm_TEST : SHADER_PERMUTATION_INT("TEST", 1);using FPermutationDomain = TShaderPermutationDomain<FMySimpleComputeShader_Perm_TEST>;BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )/** Here's where you define one or more of the input parameters for your shader.* Some examples:*/// SHADER_PARAMETER(uint32, MyUint32) // On the shader side: uint32 MyUint32;// SHADER_PARAMETER(FVector3f, MyVector) // On the shader side: float3 MyVector;// SHADER_PARAMETER_TEXTURE(Texture2D, MyTexture) // On the shader side: Texture2D<float4> MyTexture; (float4 should be whatever you expect each pixel in the texture to be, in this case float4(R,G,B,A) for 4 channels)// SHADER_PARAMETER_SAMPLER(SamplerState, MyTextureSampler) // On the shader side: SamplerState MySampler; // CPP side: TStaticSamplerState<ESamplerFilter::SF_Bilinear>::GetRHI();// SHADER_PARAMETER_ARRAY(float, MyFloatArray, [3]) // On the shader side: float MyFloatArray[3];// SHADER_PARAMETER_UAV(RWTexture2D<FVector4f>, MyTextureUAV) // On the shader side: RWTexture2D<float4> MyTextureUAV;// SHADER_PARAMETER_UAV(RWStructuredBuffer<FMyCustomStruct>, MyCustomStructs) // On the shader side: RWStructuredBuffer<FMyCustomStruct> MyCustomStructs;// SHADER_PARAMETER_UAV(RWBuffer<FMyCustomStruct>, MyCustomStructs) // On the shader side: RWBuffer<FMyCustomStruct> MyCustomStructs;// SHADER_PARAMETER_SRV(StructuredBuffer<FMyCustomStruct>, MyCustomStructs) // On the shader side: StructuredBuffer<FMyCustomStruct> MyCustomStructs;// SHADER_PARAMETER_SRV(Buffer<FMyCustomStruct>, MyCustomStructs) // On the shader side: Buffer<FMyCustomStruct> MyCustomStructs;// SHADER_PARAMETER_SRV(Texture2D<FVector4f>, MyReadOnlyTexture) // On the shader side: Texture2D<float4> MyReadOnlyTexture;// SHADER_PARAMETER_STRUCT_REF(FMyCustomStruct, MyCustomStruct)SHADER_PARAMETER_RDG_BUFFER_SRV(Buffer<int>, Input)SHADER_PARAMETER_RDG_BUFFER_UAV(RWBuffer<int>, Output)END_SHADER_PARAMETER_STRUCT()public:static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters){const FPermutationDomain PermutationVector(Parameters.PermutationId);return true;}static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment){FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment);const FPermutationDomain PermutationVector(Parameters.PermutationId);/** Here you define constants that can be used statically in the shader code.* Example:*/// OutEnvironment.SetDefine(TEXT("MY_CUSTOM_CONST"), TEXT("1"));/** These defines are used in the thread count section of our shader*/OutEnvironment.SetDefine(TEXT("THREADS_X"), NUM_THREADS_MySimpleComputeShader_X);OutEnvironment.SetDefine(TEXT("THREADS_Y"), NUM_THREADS_MySimpleComputeShader_Y);OutEnvironment.SetDefine(TEXT("THREADS_Z"), NUM_THREADS_MySimpleComputeShader_Z);// This shader must support typed UAV load and we are testing if it is supported at runtime using RHIIsTypedUAVLoadSupported//OutEnvironment.CompilerFlags.Add(CFLAG_AllowTypedUAVLoads);// FForwardLightingParameters::ModifyCompilationEnvironment(Parameters.Platform, OutEnvironment);}
private:
};// This will tell the engine to create the shader and where the shader entry point is.
//                            ShaderType                            ShaderPath                     Shader function name    Type
IMPLEMENT_GLOBAL_SHADER(FMySimpleComputeShader, "/Plugin/CS_Test/Private/MySimpleComputeShader.usf", "MySimpleComputeShader", SF_Compute);void FMySimpleComputeShaderInterface::DispatchRenderThread(FRHICommandListImmediate& RHICmdList, FMySimpleComputeShaderDispatchParams Params, TFunction<void(int OutputVal)> AsyncCallback) {FRDGBuilder GraphBuilder(RHICmdList);{SCOPE_CYCLE_COUNTER(STAT_MySimpleComputeShader_Execute);DECLARE_GPU_STAT(MySimpleComputeShader)RDG_EVENT_SCOPE(GraphBuilder, "MySimpleComputeShader");RDG_GPU_STAT_SCOPE(GraphBuilder, MySimpleComputeShader);typename FMySimpleComputeShader::FPermutationDomain PermutationVector;// Add any static permutation options here// PermutationVector.Set<FMySimpleComputeShader::FMyPermutationName>(12345);TShaderMapRef<FMySimpleComputeShader> ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel), PermutationVector);bool bIsShaderValid = ComputeShader.IsValid();if (bIsShaderValid) {FMySimpleComputeShader::FParameters* PassParameters = GraphBuilder.AllocParameters<FMySimpleComputeShader::FParameters>();const void* RawData = (void*)Params.Input;int NumInputs = 2;int InputSize = sizeof(int);FRDGBufferRef InputBuffer = CreateUploadBuffer(GraphBuilder, TEXT("InputBuffer"), InputSize, NumInputs, RawData, InputSize * NumInputs);PassParameters->Input = GraphBuilder.CreateSRV(FRDGBufferSRVDesc(InputBuffer, PF_R32_SINT));FRDGBufferRef OutputBuffer = GraphBuilder.CreateBuffer(FRDGBufferDesc::CreateBufferDesc(sizeof(int32), 1),TEXT("OutputBuffer"));PassParameters->Output = GraphBuilder.CreateUAV(FRDGBufferUAVDesc(OutputBuffer, PF_R32_SINT));auto GroupCount = FComputeShaderUtils::GetGroupCount(FIntVector(Params.X, Params.Y, Params.Z), FComputeShaderUtils::kGolden2DGroupSize);GraphBuilder.AddPass(RDG_EVENT_NAME("ExecuteMySimpleComputeShader"),PassParameters,ERDGPassFlags::AsyncCompute,[&PassParameters, ComputeShader, GroupCount](FRHIComputeCommandList& RHICmdList){FComputeShaderUtils::Dispatch(RHICmdList, ComputeShader, *PassParameters, GroupCount);});FRHIGPUBufferReadback* GPUBufferReadback = new FRHIGPUBufferReadback(TEXT("ExecuteMySimpleComputeShaderOutput"));AddEnqueueCopyPass(GraphBuilder, GPUBufferReadback, OutputBuffer, 0u);auto RunnerFunc = [GPUBufferReadback, AsyncCallback](auto&& RunnerFunc) -> void {if (GPUBufferReadback->IsReady()) {int32* Buffer = (int32*)GPUBufferReadback->Lock(1);int OutVal = Buffer[0];GPUBufferReadback->Unlock();AsyncTask(ENamedThreads::GameThread, [AsyncCallback, OutVal]() {AsyncCallback(OutVal);});delete GPUBufferReadback;} else {AsyncTask(ENamedThreads::ActualRenderingThread, [RunnerFunc]() {RunnerFunc(RunnerFunc);});}};AsyncTask(ENamedThreads::ActualRenderingThread, [RunnerFunc]() {RunnerFunc(RunnerFunc);});} else {// We silently exit here as we don't want to crash the game if the shader is not found or has an error.}}GraphBuilder.Execute();
}
MySimpleComputeShader.h
#pragma once#include "CoreMinimal.h"
#include "GenericPlatform/GenericPlatformMisc.h"
#include "Kismet/BlueprintAsyncActionBase.h"#include "MySimpleComputeShader.generated.h"struct CS_TEST_API FMySimpleComputeShaderDispatchParams
{int X;int Y;int Z;int Input[2];int Output;FMySimpleComputeShaderDispatchParams(int x, int y, int z): X(x), Y(y), Z(z){}
};// This is a public interface that we define so outside code can invoke our compute shader.
class CS_TEST_API FMySimpleComputeShaderInterface {
public:// Executes this shader on the render threadstatic void DispatchRenderThread(FRHICommandListImmediate& RHICmdList,FMySimpleComputeShaderDispatchParams Params,TFunction<void(int OutputVal)> AsyncCallback);// Executes this shader on the render thread from the game thread via EnqueueRenderThreadCommandstatic void DispatchGameThread(FMySimpleComputeShaderDispatchParams Params,TFunction<void(int OutputVal)> AsyncCallback){ENQUEUE_RENDER_COMMAND(SceneDrawCompletion)([Params, AsyncCallback](FRHICommandListImmediate& RHICmdList){DispatchRenderThread(RHICmdList, Params, AsyncCallback);});}// Dispatches this shader. Can be called from any threadstatic void Dispatch(FMySimpleComputeShaderDispatchParams Params,TFunction<void(int OutputVal)> AsyncCallback){if (IsInRenderingThread()) {DispatchRenderThread(GetImmediateCommandList_ForRenderCommand(), Params, AsyncCallback);}else{DispatchGameThread(Params, AsyncCallback);}}
};DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnMySimpleComputeShaderLibrary_AsyncExecutionCompleted, const int, Value);UCLASS() // Change the _API to match your project
class CS_TEST_API UMySimpleComputeShaderLibrary_AsyncExecution : public UBlueprintAsyncActionBase
{GENERATED_BODY()public:// Execute the actual loadvirtual void Activate() override {// Create a dispatch parameters struct and fill it the input array with our argsFMySimpleComputeShaderDispatchParams Params(1, 1, 1);Params.Input[0] = Arg1;Params.Input[1] = Arg2;// Dispatch the compute shader and wait until it completesFMySimpleComputeShaderInterface::Dispatch(Params, [this](int OutputVal) {this->Completed.Broadcast(OutputVal);});}UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true", Category = "ComputeShader", WorldContext = "WorldContextObject"))static UMySimpleComputeShaderLibrary_AsyncExecution* ExecuteBaseComputeShader(UObject* WorldContextObject, int Arg1, int Arg2) {UMySimpleComputeShaderLibrary_AsyncExecution* Action = NewObject<UMySimpleComputeShaderLibrary_AsyncExecution>();Action->Arg1 = Arg1;Action->Arg2 = Arg2;Action->RegisterWithGameInstance(WorldContextObject);return Action;}UPROPERTY(BlueprintAssignable)FOnMySimpleComputeShaderLibrary_AsyncExecutionCompleted Completed;int Arg1;int Arg2;};

6. 着色器实现

MySimpleComputeShader.usf
#include "/Engine/Public/Platform.ush"Buffer<int> Input;
RWBuffer<int> Output;[numthreads(THREADS_X, THREADS_Y, THREADS_Z)]
void MySimpleComputeShader(uint3 DispatchThreadId : SV_DispatchThreadID,uint GroupIndex : SV_GroupIndex )
{// Outputs one numberOutput[0] = Input[0] * Input[1];
}

7. 分配 work groups

关于整个解释

https://learnopengl.com/Guest-Articles/2022/Compute-Shaders/Introduction​learnopengl.com/Guest-Articles/2022/Compute-Shaders/Introduction

[numthreads(THREADS_X, THREADS_Y, THREADS_Z)]
是在HLSL中分配计算空间的语法


8. 计算和输出


9. 额外添加参数流程





本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/211812.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go语言中结构体的使用和示例

结构体&#xff08;简称struct&#xff09;用于创建不同数据类型的成员集合&#xff0c;放入一个单一的变量中。虽然数组用于将相同数据类型的多个值存储在单一变量中&#xff0c;但结构体用于将不同数据类型的多个值存储在单一变量中。结构体对于将数据组合在一起以创建记录非…

Unity调用dll踩坑记

请用写一段代码&#xff0c;让unity无声无息的崩溃。 你说这怕是有点难哦&#xff0c;谁会这么不幸呢&#xff1f;不幸的是&#xff0c;我幸运的成为了那个不幸的人。 unity里面调用dll的方式是使用 DllImport &#xff0c;比如有一个 Hello.dll&#xff0c;里面有一个 char* …

[23] 4K4D: Real-Time 4D View Synthesis at 4K Resolution

paper | proj | code 提出一种基于K-Planes的4D point cloud Representation&#xff1b;提出一种Hybrid appearance model&#xff0c;包含image blending model和SH model。其中&#xff0c;image blending model将3D点映射回原图中求得&#xff0c;SH model通过模型预测求得…

Jsonpath - 数据中快速查找和提取的强大工具

JSON&#xff08;JavaScript Object Notation&#xff09;在现代应用程序中广泛使用&#xff0c;但是如何在复杂的JSON数据中 查找和提取所需的信息呢&#xff1f; JSONPath是一种功能强大的查询语言&#xff0c;可以通过简单的表达式来快速准确地定位和提取JSON数据。本文将介…

网工内推 | Base北京,国企网工运维,最高30k*14薪,IE认证优先

01 万方数据股份有限公司 招聘岗位&#xff1a;网络工程师 职责描述&#xff1a; 1.负责完成基础网络组网工作&#xff1b; 2.负责网络对象的访问控制及安全策略&#xff0c;配置VLan&#xff0c;黑白名单、地址转换、故障排查及网络安全监控工作&#xff1b; 3.负责对操作系…

flutter,uni-app开发调试ios

一、申请ios开发者账号 二、ios开发者配置 ios 开发者需要配置的地方 https://developer.apple.com/account/resources/certificates/list Certificates&#xff08;证书&#xff09;: 作用&#xff1a; 证书用于对应用程序和开发者进行身份验证&#xff0c;确保安全性和可…

Mock 数据

1. Mock 数据的方式 2. json-server 实现 Mock 数据 项目中安装json-server npm i -D json-server准备一个json文件添加启动命令 //package.json"scripts": {"start": "craco start","build": "craco build","test&q…

IAR为恩智浦S32M2提供全面支持,提升电机控制能力

IAR Embedded Workbench for Arm已全面支持恩智浦最新的S32系列&#xff0c;可加速软件定义汽车的车身和舒适性应用的开发 瑞典乌普萨拉&#xff0c;2023年11月22日 – 嵌入式开发软件和服务的全球领导者IAR现已全面支持恩智浦半导体&#xff08;NXP Semiconductors&#xff0…

AI:87-基于深度学习的街景图像地理位置识别

🚀 本文选自专栏:人工智能领域200例教程专栏 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带有在本地跑过的代码,详细讲解供大家学习,希望可以帮到大家。欢迎订阅支持,正在不断更新中,…

【JavaSE】不允许你不会使用String类

&#x1f3a5; 个人主页&#xff1a;深鱼~&#x1f525;收录专栏&#xff1a;JavaSE&#x1f304;欢迎 &#x1f44d;点赞✍评论⭐收藏 目录 前言&#xff1a; 一、常用方法 1.1 字符串构造 1.2 String对象的比较 &#xff08;1&#xff09;比较是否引用同一个对象 注意…

如何应用ChatGPT撰写、修改论文及工作报告,提供写作能力及优化工作??

如果我想让gpt从pdf文档中提取相关关键词的内容&#xff0c;可以怎么做呢&#xff1f;&#xff1f;我们评论区讨论 ChatGPT 在论文写作与编程方面也具备强大的能力。无论是进行代码生成、错误调试还是解决编程难题&#xff0c;ChatGPT都能为您提供实用且高质量的建议和指导&am…

轻松管理文件名:文件批量重命名的技巧与操作

在日常工作中&#xff0c;文件管理是一项至关重要的任务。其中&#xff0c;文件名的管理更是关键。文件名是在查找文件时最直观的线索。一个好的文件名简短而准确地反映文件的内容或用途。然而&#xff0c;随着时间的推移&#xff0c;可能会发现文件名变得冗长、混乱甚至无法反…