compute shader是在GPU上运行的着色器程序,可用于大规模并行 GPGPU(General Purpose GPU)算法,或加速部分游戏渲染。
shaderlab和Compute Shader都使用HLSL语言编写,但功能大不相同,这是一些比较:
1. compute shader没有Material Property,意味着无法通过Material调整属性,只能依靠shader的设置值方法,但是用法相同,可以用来设置各种shader变量和贴图。
2. compute shader没有subpass和pass,也没有renderqueue,这是因为它独立固定在GPU渲染流程开始时进行,不直接创建drawcall,而是其输出在后面的渲染阶段使用。
3. compute shader没有顶点着色器和片元着色器,这是因为它是通过Kernel Function直接被C#调用,本质上可以当做C# script的一部分,只是这一部分计算放在GPU上计算。
用法如下:
Compute Shader Instancing
compute shader跟GPU instancing结合起来可以实现很强大的功能。这个技术在大世界生成非常重要。
相关方法(参数有精简):
可变mesh个数:DrawMeshInstancedIndirect,argsOffset指定了存储mesh个数的位置。
DrawMeshInstancedIndirect(
Mesh mesh,
int submeshIndex,
Material material,
Bounds bounds,
ComputeBuffer bufferWithArgs,
int argsOffset = 0
)
固定mesh个数:DrawMeshInstancedProcedural
DrawMeshInstancedProcedural(
Mesh mesh,
int submeshIndex,
Material material,
Bounds bounds,
int count
);
无mesh,可变次数:DrawProceduralIndirect
DrawProceduralIndirect(Material material,
Bounds bounds,
MeshTopology topology,
GraphicsBuffer bufferWithArgs,
int argsOffset
)
无mesh,固定次数:DrawProcedural
DrawProcedural(
Material material,
Bounds bounds,
MeshTopology topology,
int vertexCount,
int instanceCount
)
前两个方法接口是CPU传入mesh,后两个是由GPU生成mesh。 这些函数都是在GPU侧直接绘制,需要在Compute Buffer中预先存好unity_ObjectToWorld信息。在使用后两个方法时,还需要在顶点着色器手动根据InstanceId构造好Mesh。
用上面的方法,可以实现非常高效的Instancing,因为此时CPU向GPU传递的数据大大减少了,不再需要每帧为每个物体传递位置信息,甚至不用传递mesh(DrawProcedural的情况)。
优点:减少了CPU到GPU的数据传输,不需要做每个物体的裁剪和深度排序。
缺点:由于没有深度排序,导致overdraw。但由于性能提升很大这个缺点一般可以忽略,并且也有解决办法:
贴图渲染
可以用于各种程序化贴图的生成,比如各种Noise的生成,适用于需要动态变化的贴图,比如水面颜色或者法线。或者单纯是为了提高编辑器中实时显示的性能。例如:
粒子
在这篇文章中,还提到了粒子的使用:
实际上是用DrawProcedural Point实现的模拟粒子,不是Particle System。虽然不如Particle System,但是性能好很多,适合超大规模的粒子特效渲染。
UAV
UAV定义是Unordered Access View,介绍参考这里。
简单来说就是支持随机写入,这和传统渲染流程不一样。传统流程渲染贴图时必须按照固定的顺序,比如后处理时输入一张Quad,传统渲染每次绘制时一定是逐个像素点执行一次,执行完就输出。但有的时候我们不想这样,而是每次写入数据的位置是可变的,并且可能在一次绘制当中,覆盖之前写好的像素。正常来说这种处理只能在CPU侧,用一张输出贴图来支持这种写入。但是UAV解决了这个问题,可以在GPU侧实现这个功能。
实现这一点就需要使用Compute Shader,最常见的应用是SSPR,应用可以参考: