Shader第二十八讲 Compute Shaders
来源:互联网 发布:带数据库的网站源码 编辑:程序博客网 时间:2024/04/30 05:58
http://blog.sina.com.cn/s/blog_471132920102w97k.html
首先简单介绍GPGPU programming
和CPU Random Memory Accesses(随机内存获取)不同,GPU是用平行架构处理 大量的并行数据,例如vertex和fragment就是分开计算的。使用GPU并利用这种特性来进行非图形计算被称为GPGPU编程(General Purpose GPU Programming)。大量并行无序数据的少分支逻辑(少if)适合GPGPU,例如粒子间互不影响的粒子系统。GPGPU平台或接口有DirectCompute,OpenCL,CUDA等。从此图可以看出 CPU和GPU之间的数据传输是瓶颈。故当使用GPGPU时,对Texture的逐像素处理不需要传回CPU,因而速度比较快。
【概念】
Compute Shaders是在GPU运行却又在普通渲染管线之外的程序。用于运行GPGPU program。平行算法被拆分成 很多线程组,而线程组包含很多线程。例如一个线程处理一个像素点。而一定要注意这种处理是无序的随机的,并不一定是固定的处理顺序,例如不一定是从左到右挨个处理像素点。
线程组
A Thread Group 运行在一个GPU单元 (A single multiprocesser),如果GPU有16个multiprocesser,那么程序至少要分成16个 Thread Group使得每个multiprocesser都参与计算。组之间不分享内存。线程一个线程组包含n个线程,每32个thread称为一个warp(nvidia:warp=32 ,ati:wavefront=64,因此未来此数字可能会更高)。从效率考虑,一个线程组包含的线程数最好的warp的倍数,256是一个比较合适的数字。【实现步骤】 (1)在compute shader里 通过对贴图或者buffer进行数据读写(2)在cs脚本里设置shader的贴图或者buffer并运行
【规则语法】1 Compute Shaders的文件后缀为.compute
2 使用#pragma指出内核。
一个Compute Shader至少需要一个内核。
例如 #pragma kernel FillWithRed
也可以接宏定义
#pragma kernel KernelOne SOME_DEFINE DEFINE_WITH_VALUE=1337 #pragma kernel KernelTwo OTHER_DEFINE
3 函数语法
下面通过一个完整简单的ComputeShader演示
- #pragma kernel FillWithRed
- RWTexture2D< float4 > res;
- [numthreads(1,1,1)]
- void FillWithRed (uint3 id : SV_DispatchThreadID)
- {
-
res[id.xy] = float4(1,0,0,1); - }
这一段代码只是输出红色至res贴图.
一 前缀
在核的前缀用三个纬度,定义了一个线程组内线程的数量,如果只用2个纬度那么,最后一个参数为1即可[numthreads(thread_group_size_x,thread_group_size_y,1)]GroupID:线程组idThreadIID:组内线程idDispatchThreadID:线程DispatchId(DispatchThreadID =GroupID*组内线程数 + ThreadId)这些id都是从0开始 二 资源类型cs可以读取两种类型的资源:buffer ,texture 【buffer】例如顶点缓冲就是一种buffer,很多时候我们去定义struct数组并作为buffer传入cs自己定义buffer(必须是固定size):struct Data{float x;};StructuredBuffer< Data > b;RWStructuredBuffer< Data > b;buffer的添加是append,消耗是consume texture:只读 Texture2d< float4 > xx;读写 RWTexture2d< float4 > xx;RWTexture2d< float2 > xx; //RG_int 在Unity里读写的只能是RenderTexture并且支持随机读写(RenderTexture enableRandomWrite=true)三 其他1 每个线程都有一个对应的id: SV_DispatchThreadID对贴图进行采样不能用Sample 而是SampleLevel,额外的参数是mipmap level ,0为最高级,1为次级,2...2 int格子转换至[0,1]uv范围例如一张512x512的贴图Texture2d tex;tex.SampleLevel(samPoint,float2(id.x,id.y)/512)blur需要所有所有像素都sample完,因此需要同步:GroupMemoryBarrierWithGroupSync(); [例一:基本贴图计算] 将一张贴图所有像素点赋予红色,很简单。CS脚本
- using
UnityEngine ; - using
System .Collections; - public
class SetTexColor_1 : MonoBehaviour { -
Material mat; -
ComputeShader shader; -
Start() -
-
(); -
-
RunShader() -
-
-
RenderTexture -
-
新建RenderTexture -
tex = new RenderTexture (256, 256, 24); -
开启随机写入 -
= true; -
创建RenderTexture -
(); -
赋予材质 -
= tex; -
-
Compute Shader -
-
找到compute shader中所要使用的KernelID -
k = shader.FindKernel ("CSMain"); -
设置贴图 参数1=kid 参数2=shader中对应的buffer名 参数3=对应的texture, 如果要写入贴图,贴图必须是RenderTexture并enableRandomWrite -
(k, "Result", tex); -
运行shader 参数1=kid 参数2=线程组在x维度的数量 参数3=线程组在y维度的数量 参数4=线程组在z维度的数量 -
(k, 256 / 8, 256 / 8, 1); -
- }
Compute Shader
- //1
定义kernel的名称 - #pragma
kernel CSMain - //2
定义buffer - RWTexture2D
Result; - //3
kernel函数 - //组内三维线程数
- [numthreads(8,8,1)]
- void
CSMain (uint3 id : SV_DispatchThreadID) - {
-
//给buffer赋值 -
//纯红色 -
//Result[id.xy] = float4(1,0,0,1); -
//基于uv的x给颜色 -
float v = id.x/256.0f; -
Result[id.xy] = float4(v,0,0,1); - }
[例二:Buffer使用] 这个例子并不是讲实现粒子系统,而只是演示简单的Buffer使用和传递。步骤:shader:1 定义struct结构体2 声明struct变量3 函数里计算c#:1 定义对应的struct结构体2 声明struct数组3 创建buffer ComputeBuffer buffer = new ComputeBuffer(count,40); 参数1是 数组长度(等于2个三维的乘积),参数2是结构体的字节长度如float=44 初始化结构体并赋予buffer buffer .SetData (values); 参数是 struct数组5 Dispatch还是 FindKernel-> SetBuffer ->DispatchCompute Shader
- #pragma
kernel CSMain - struct
PBuffer - {
-
float life; -
float3 pos; -
float3 scale; -
float3 eulerAngle; - };
- RWStructuredBuffer
buffer; - float
deltaTime; - [numthreads(2,2,1)]
- void
CSMain (uint3 id : SV_DispatchThreadID) - {
-
int index = id.x + id.y * 2 * 2; -
buffer[index].life -= deltaTime; -
buffer[index].pos = buffer[index].pos + float3(0,deltaTime,0); -
buffer[index].scale = buffer[index].scale; -
buffer[index].eulerAngle = buffer[index].eulerAngle + float3(0,20*deltaTime,0); - }
CS脚本
using
using
using
//Buffer数据结构
struct
{
};
public
}
参考:
《Introduction_to_3D_Game_Programming_with_Directx_11》
- Shader第二十八讲 Compute Shaders
- Compute Shaders
- 第二十八讲 Ajax技术
- Shader第二讲 Fixed Function Shader
- Shader第二讲:Fixed Function Shader
- Java基础:第二十八讲 成员变量
- JavaSE第二十八讲:Object类详解
- unity3d 插件之Shader Forge第二讲
- 韩顺平网页第二十七讲二十八讲
- Compute Shader (DX11)
- DirectX 11 - Compute Shader
- unity3d 从零开始compute shader
- Unity5 Compute && Geometry Shader
- GLSL-Compute Shader
- 第二十八讲 : ADO.NET概述(OLEDB对象操作)
- 【Unity Shaders】Shader中的光照
- 【Unity Shaders】Surface Shader 概述
- DirectX 11 Compute Shader tutorial
- 数据结构实验之排序五:归并求逆序数
- bash shell环境下执行基本的算数运算以及bc的使用
- 线程(2)——JAVA中的基本线程操作(上)
- 实现ArrayList和HashMap类
- restclient调用post接口的方法
- Shader第二十八讲 Compute Shaders
- 欢迎使用CSDN-markdown编辑器
- 关于极光推送的小应用
- iOS纯代码自定义UITableViewCell及性能优化
- Linux spi驱动分析(四)----SPI设备驱动(W25Q32BV)
- AC自动机
- JAVA设计模式---单例模式(singleton)
- 理解mipi协议
- HTML+CSS基础课程之使用提交按钮,提交数据