• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Computer Shader

武飞扬头像
longger0000
帮助2

        ComputerShader是一种特殊的shader,得利于GPU强大的并行计算力,computershader可以轻松完成一些重复且量大的计算任务。


ComputerShader用法

ComputerShader部分:

        ComputerShader是以.comCputer为后缀的文件。可以在Project面板中右键-Creat-Shader-ComputerShader来创建它。打开之后可以看到文件中自带的几行示例:学新通

 #pragma kernal CSMain :预编译命令,和我们熟悉的#pragma vertex vert类似,用于指定要编译的核心函数名,这里函数名就是CSMain,可以在c#中通过这个名称指定调用。

RWTexture2D<float4> Result :声明一张存储float4类型的纹理,RW代表是可读可写的;可写意味着我们会将它作为输出纹理来使用,与之对应的还有可读不可写的输入纹理Texture2D<>。除纹理之外,还可以声明其他类型的值如float、int、struct、RWStructuredBuffer<>等用于在c#中传递数据。

[numthreads(8,8,1)] :用于指定一个三维的线程组大小,x,y,z分量分别指定了三个维度的长度。关于线程、线程组、组内线程索引、线程组索引等易混淆的概念在下文中详细解释。

void CSMain(uint3 id : SV_DispatchTreadID){...} :ComputerShader的核心-函数主体部分,一个computershader可以有多个这样的函数,只需要在开头处加上相应的预编译命令#pragma kernal functionName即可。这个函数是没有返回值的,因为我们会把要输出的数据存储在可写纹理中,只需要在c#中申请rt并指定给computershader即可。

函数的参数unit3 id :SV_DispatchThreadID是unit3类型的线程id,关于线程编号如何来算下文详述。

c#部分:

        要使用computershader,就需要在脚本中传递参数,然后创建commendBuffer来调用其中的函数。(在urp管线下)通过Project面板中右键-Creat-Rendering-URP Renderer Feature来创建一个脚本。关于RendererFeature的用法不是本文重点,不再详述。

通过CommandBuffer.SetComputeFloatParam()、CommandBuffer.SetComputeTextureParam()等函数可以向指定的ComputerShader传参数:

  1.  
    //首先在commandbuffer池中申请一个对象
  2.  
    CommandBuffer cmd = CommandBufferPool.Get("ComputerExample");
  3.  
     
  4.  
    //根据colorBuffer的大小申请一个临时rt
  5.  
    int temptex = Shader.PropertToID("tempTex");
  6.  
    var camData = renderingData.cameraData;
  7.  
    var tempDesc = camData.cameraTargetDescriptor;
  8.  
    //打开随机写入
  9.  
    tempDesc.enableRandomWrite = true;
  10.  
    cmd.GetTemporaryRT(temptex,tempDesc);
  11.  
     
  12.  
    //向computerShader传值
  13.  
    cmd.SetComputeFloatParam(myCS,"csFloatParam",1.52f);
  14.  
    cmd.SetComputeTextureParam(myCS,"Result",temptex); //将temptex作为输出rt传入
  15.  
     
  16.  
    //执行函数
  17.  
    cmd.DispatchCompute(myCS,0,(int)tempDesc.width/10,(int)tempDesc.height/10,1);
  18.  
    //myCS为指定的computershader名,0为kernal索引(类似shader中的pass索引),后边三个参数为线程组参数
  19.  
    //还可以:cmd.Dispatch(kernalid,(int)tempDesc.width,(int)tempDesc.height,1);
  20.  
     
  21.  
    //将结果绘制到colorBuffer中
  22.  
    cmd.Blit(tempDesc,Sour);
  23.  
    //释放commandBuffer
  24.  
    context.ExecuteCommandBuffer(cmd);
  25.  
    CommandBufferPool.Release(cmd);
学新通

线程、线程组与调度

学新通

Thread(线程) :shader中最小的调度单元,一个执行中的函数即一个线程 。

ThreadGroup(线程组):由线程组成的三维数组,存储几十到几百个线程。上面的[numthreads(8,8,1)]便表示一个线程组,其中有64=8*8*1个线程。

Dispatch(调度) :调度的单位是线程组,一次调度会包含多个线程组,即调度是由线程组组成的三维数组,存储了几百到几千个线程。如c#脚本中的cmd.Dispatch(Kernelid,3,2,1),表示调度6=3*2*1个由[numthreads(8,8,1)]构成的线程组。

DispatchThreadID(调度线程ID):kernel函数默认的传入参数,是一个三个分量组成的数组,表示线程在所有线程调度中的绝对位置,即第x个线程组的第y号线程。具体算法很简单,用组号乘上每组内的线程数,再加上线程在组内的相对位置即可:

DispatchThreadID = GroupThreadID GroupID*numthreads

学新通

 以上图这个位置为例,它在组内的相对位置为(2,1,0),它所在的线程组的位置为(0,1,0),因此它的调度线程ID为:(2,5,0)=(2,1,0) (0,1,0)*(4,4,3)。

GroupThreadID(组内线程ID)和GroupID(线程组ID):kernel函数接受传入参数时可以选择SV_GroupThreadIDSV_GroupID来接受组内线程id线程组id作为参数。它们也是一个三分量的数组,分别表示线程在组内的相对位置线程所在线程组组在调度中的位置


ComputerShader是一个灵活且强大的工具,可以用它来实现自定义的后处理效果,还可以利用它快速并行运算的特点来构建一个粒子系统,用来实现粒子流体、粒子特效等。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhibabhh
系列文章
更多 icon
同类精品
更多 icon
继续加载