unity 线程断点时卡机_Compute Shader在Unity和UE4中的应用

该文档为学习文档,如有错误欢迎指正。

1. D3D11 Compute Shader概述

Compute Shader 是一个通用计算 Stage。它利用了GPU的并行处理器,实现大量线程并发执行。它可以独立于渲染管线之外,计算完成的数据可以在CPU回读;也可以结合到渲染管线中,利用GPU Buffer与其他Stage进行通信。

HLSL中的Compute Shader的编写:其main(参数:线程id)函数,实际上是单个线程的执行代码;main函数的参数,是线程的id标识,即用来定位该线程,以便于在Buffer中定位数据。

D3D11中Compute Shader 的执行:->Dispatch(线程组数量),即通知GPU执行多少线程组,并且执行完返回。

2. Unity和UE4 的Compute Shader 概述

38fb89a485f34668b86202076f329d43.png

(1) Unity

Unity 在编辑器中暴露了 *.shader(vertex shader、pixel shader)和*.compute(compute shader) ,可以直接在编辑器中创建并使用。其中Shader 在 Material被引用;而Compute Shader 独立使用。 Compute Shader 在Unity中2种类型的应用方式:

① 创建“*.compute”。编写hlsl代码。若需要与其他Shader通信,则编写C#代码实现通信,实际上就用公用Buffer。

② 隐含在VFX中被创建。Visual FX (Unity 的GPU 粒子的可视化编辑器),定义了一类新的资源*.vfx。这是一个gpu粒子资源。该资源可以包含若干个*.shader和若干个*.compute,并且这些隐含资源是unity根据编辑好的节点逻辑自动生成的。

(2) UE4

UE4在编辑器中没有暴露 Shader的概念,只有材质节点编辑器。Compute shader 与其他Stage的Shader一起被封装在了底层,各类Shader(VS、HS、DS、PS、GS、CS)用一个枚举来进行区别。而Compute Shader在UE4引擎代码中 主要被分成3类来使用

① MaterialShader:需要从材质中获取信息的Compute Shader。目前UE4.19里只有一个这样的Compute Shader;其他MaterailShader都为VS、HS、DS、PS、GS

② GlobalShader:全局的ComputeShader。这类ComputeShader有一百多个实例。(应用范围,摘录自UE使用到的一些文件名: ParticleBound、ParticleSort、GPUSkinCache、GPUSort、Morph、PostProcess、Shadow、DistanceFieldAO、DistanceFieldGI、DistanceFieldShadow等等)

③ NiagaraShader: Niagara是一个UE4自己的插件,一个粒子编辑器。与MaterialShader类似,它应该也是可以根据不同的粒子,生成不同的Shader。实际上它只有一个对应的shader文件,但是可以根据粒子编辑器的编辑,生成一个hlsl的函数,插入到这个shader文件已有的代码模板中,从而产生不同的compute shader。(在代码中有看到插入函数的代码拼接过程;产生不同的cs则暂为个人推测)

3. Compute Shader

(1) D3D11相关接口和相关Flag参数

ad7bd5234e8355c379297942b9578185.png

(2) HLSL语法

① Buffer声明

Buffer类型:StructuredBuffer、RWStructuredBuffer、ByteAddressBuffer、RWByteAddressBuffer、AppendStructuredBuffer、ConsumeStructuredBuffer、IncrementCounter、DecrementCounter、TextureXD(应该还没列全)。其中“RW”前缀表示可读写

关键字groupshared:线程组内共享的buffer。

② 线程组内线程数量声明

[numthreads(x,,y,,z,)]

线程组的数量由D3D的接口Dispatch的参数来决定。

而一个线程组内线程的数量则在hlsl里确定,关键字为numthreads。组内线程数量 = x,*y,*z,

③ Main函数

为单个线程的执行代码

参数可以选取以下:

1) SV_GroupThreadID:(x,y,z)线程组内线程id

2) SV_GroupID:(x,y,z)线程组id

3) SV_DispatchThreadID:(x,y,z)在所有线程中的线程id

4) SV_GroupID:计算出来的线程组id(一个int)

7d57d10e9ec38fc98b1307123a14c81d.png

4. Unity 的 Compute Shader

(1) Unity Compute Shader 文件内容

Unity关键字:Kernel(对应一个compute shader main 函数)

文件后缀:*.compute

语法:hlsl

a7697695138165ac57b89cde10408608.png

(2) Unity C#ScriptingAPI 内Compute Shader相关

① 类ComputeShader

c900e59e0c158feccc9ebb23c5e2b4c7.png

② 类ComputeBuffer

69a6de7cafbf9ac143212b52cd1f23a6.png

5. UE4 的Compute Shader

Compute Shader 被封装到了UE4的RHI(Render Hardware Interface)的各模块中;它的使用主要被封装在了UE4的Renderer模块中。

(1) RHI(Render Hardware Interface)

外部使用图形硬件的接口

a73ad4c7294fa5acf23ee5516c13bcc1.png

① IRHIComputeContext:包含compute shader 执行时用到的接口

② IRHICommandContext:继承IRHIComputeContext。具体化为D3D11的话,包含了D3D11DeviceContext的内容

③ FDynamicRHI:具体化为D3D11的话,包含了D3D11Device的内容。可用于创建Buffer,创建Shader等等

(2) D3D11RHI

003856d2f6610c416feee65ab5b778db.png

① FD3D11DynamicRHI。实现了接口IRHICommandContext和接口FDynamicRHI。

② FD3D11StateCacheBase

这是对D3D11中StateCache的封装。State包含了 VS、HS、DS、GS、PS、CS.

在渲染时,可以同时设置VS、HS、DS、GS、PS. 在使用CS时,可单独设置CS。

(3) Renderer模块中

77e05eb30a9fb1eccabc97035cdaabbc.png

① FShader

② FShaderReouseces:包含了Shader在RHI的指针

③ FMaterialShader:需要获取材质信息的Shader

④ FNiagaraShader:Niagara中使用的Shader;Niagara是一个粒子插件。

⑤ FGlobalShader:全局Shader

⑥ FMaterial:只能包含FMaterialShader。

下面是一个简单的Unity Compute Shader示例,用于将输入纹理的红色通道值乘以一个常数系数,并将结果输出到目标纹理的绿色通道: ``` // 声明输入和输出纹理 Texture2D inputTex; RenderTexture outputTex; // 声明Compute Shader ComputeShader computeShader; int kernelID; void Start() { // 获取输入纹理 inputTex = Resources.Load<Texture2D>("InputTexture"); // 创建输出Render Texture outputTex = new RenderTexture(inputTex.width, inputTex.height, 0, RenderTextureFormat.ARGB32); outputTex.enableRandomWrite = true; outputTex.Create(); // 获取Compute Shader computeShader = Resources.Load<ComputeShader>("ComputeShader"); kernelID = computeShader.FindKernel("CSMain"); // 设置纹理参数 computeShader.SetTexture(kernelID, "InputTex", inputTex); computeShader.SetTexture(kernelID, "OutputTex", outputTex); // 设置常数系数参数 float coefficient = 2.0f; computeShader.SetFloat("Coefficient", coefficient); // 计算输出 computeShader.Dispatch(kernelID, inputTex.width / 8, inputTex.height / 8, 1); // 显示输出 GetComponent<Renderer>().material.mainTexture = outputTex; } void OnDestroy() { // 释放Render Texture outputTex.Release(); } ``` 在这个示例,我们首先声明了输入和输出纹理,以及Compute Shader和内核ID。然后,我们在Start函数加载输入纹理,创建输出Render Texture,并获取Compute Shader。接下来,我们设置Compute Shader的纹理和常数系数参数,并计算输出。最后,我们将输出纹理设置为场景的对象材质的主纹理,并在结束释放输出Render Texture。 要使用Compute Shader,您需要将其保存为.compute文件,并将其放在Unity项目的Assets文件夹。您还需要将您的Compute Shader添加到资源,以便您可以在代码加载它。请注意,Compute Shader只能用于支持Compute Shader 5.0或更高版本的显卡上运行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值