Unity ComputeShader 基础语法与使用教程
一、基础概念
ComputeShader 是 Unity 中利用 GPU 并行计算能力的工具,适用于大规模数据处理(如粒子模拟、图像处理、物理计算等)。其核心特点:
- 独立于渲染管线:不依赖顶点/片元着色器,直接操作内存数据。
- 并行计算:通过线程组(Thread Groups)实现多线程并行处理。
- 数据驱动 :通过
ComputeBuffer或RWTexture2D在 CPU/GPU 间传递数据。
二、基础语法
1. 创建 ComputeShader 文件
在 Unity 项目中右键点击 Assets → Create → Shader → Compute Shader ,生成 .compute 文件。
2. 核函数(Kernel)定义
-
使用
#pragma kernel声明核函数入口(可定义多个)。 -
示例:
`#pragma kernel ProcessData // 声明核函数名 // 定义可读写纹理(输出目标) RWTexture2D<float4> Result; // 线程组配置:每个线程组包含 8x8x1 个线程 [numthreads(8, 8, 1)] void ProcessData (uint3 id : SV_DispatchThreadID) { // id.xy 表示当前线程处理的纹理坐标 Result[id.xy] = float4(1.0, 0.0, 0.0, 1.0); // 填充红色 }`[numthreads(x,y,z)]:定义线程组大小(通常为8x8x1或256x1x1)。SV_DispatchThreadID:全局线程索引,用于定位数据。
3. 数据类型与缓冲区
-
RWTexture2D<float4>:可读写纹理,用于图像处理。 -
RWStructuredBuffer<T>:结构化缓冲区,存储任意类型数据(如粒子位置、速度)。`struct Particle { float3 position; float3 velocity; }; RWStructuredBuffer<Particle> Particles;`
三、C# 脚本调用流程
1. 初始化资源
-
创建 RenderTexture(纹理输出) :
`RenderTexture outputTexture = new RenderTexture(256, 256, 24); outputTexture.enableRandomWrite = true; // 允许 GPU 写入 outputTexture.Create();` -
创建 ComputeBuffer(结构化数据) :
`int particleCount = 100000; ComputeBuffer particleBuffer = new ComputeBuffer(particleCount, sizeof(float) * 6); // 3位置+3速度`
2. 调用 ComputeShader
-
获取核函数索引 :
`int kernelHandle = computeShader.FindKernel("ProcessData");` -
设置参数 :
`computeShader.SetTexture(kernelHandle, "Result", outputTexture); // 传递纹理 computeShader.SetBuffer(kernelHandle, "Particles", particleBuffer); // 传递缓冲区` -
计算线程组数量 :
`uint threadGroupsX = Mathf.CeilToInt(256 / 8f); // 纹理宽度 / 线程组x维度 uint threadGroupsY = Mathf.CeilToInt(256 / 8f); // 纹理高度 / 线程组y维度` -
启动计算 :
`computeShader.Dispatch(kernelHandle, threadGroupsX, threadGroupsY, 1);`
3. 释放资源
`void OnDestroy() {
particleBuffer?.Release(); // 释放 ComputeBuffer
outputTexture?.Release(); // 释放 RenderTexture
}`
四、完整示例:图像灰度化
1. ComputeShader 代码
`#pragma kernel Grayscale
RWTexture2D<float4> InputOutput; // 输入输出共用同一纹理
[numthreads(8, 8, 1)]
void Grayscale (uint3 id : SV_DispatchThreadID) {
float4 color = InputOutput[id.xy];
float gray = dot(color.rgb, float3(0.299, 0.587, 0.114)); // 加权平均
InputOutput[id.xy] = float4(gray, gray, gray, color.a);
}`
2. C# 脚本
`using UnityEngine;
public class GrayscaleProcessor : MonoBehaviour {
public ComputeShader computeShader;
public RenderTexture inputTexture;
void Start() {
// 确保输入纹理可写
inputTexture.enableRandomWrite = true;
// 获取核函数
int kernelHandle = computeShader.FindKernel("Grayscale");
// 设置参数
computeShader.SetTexture(kernelHandle, "InputOutput", inputTexture);
// 计算线程组
uint threadGroupsX = Mathf.CeilToInt(inputTexture.width / 8f);
uint threadGroupsY = Mathf.CeilToInt(inputTexture.height / 8f);
// 启动计算
computeShader.Dispatch(kernelHandle, threadGroupsX, threadGroupsY, 1);
}
}`
五、关键注意事项
- 线程组大小优化 :
- 根据硬件调整
numthreads(如 NVIDIA GPU 擅长32x1x1,AMD 擅长16x16x1)。 - 总线程数 =
numthreads.x * numthreads.y * numthreads.z * Dispatch(x,y,z)。
- 根据硬件调整
- 数据传递性能 :
- 避免每帧频繁调用
SetData/GetData,尽量在 GPU 端完成所有计算。 - 使用
ComputeBuffer.SetCounterValue实现动态数据扩容(如粒子系统)。
- 避免每帧频繁调用
- 同步问题 :
- GPU 计算是异步的,若需同步等待,使用
ComputeShader.WaitForCompletion()(慎用,可能卡顿)。
- GPU 计算是异步的,若需同步等待,使用
- 平台兼容性 :
- 移动端需检查
SystemInfo.supportsComputeShader,部分低端设备不支持。
- 移动端需检查