Unity ComputeShader 基础语法与使用教程

Unity ComputeShader 基础语法与使用教程

一、基础概念

ComputeShader 是 Unity 中利用 GPU 并行计算能力的工具,适用于大规模数据处理(如粒子模拟、图像处理、物理计算等)。其核心特点:

  • 独立于渲染管线:不依赖顶点/片元着色器,直接操作内存数据。
  • 并行计算:通过线程组(Thread Groups)实现多线程并行处理。
  • 数据驱动 :通过 ComputeBufferRWTexture2D 在 CPU/GPU 间传递数据。
二、基础语法
1. 创建 ComputeShader 文件

在 Unity 项目中右键点击 AssetsCreate → 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)]:定义线程组大小(通常为 8x8x1256x1x1)。
    • 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);
    }
}`
五、关键注意事项
  1. 线程组大小优化
    • 根据硬件调整 numthreads(如 NVIDIA GPU 擅长 32x1x1,AMD 擅长 16x16x1)。
    • 总线程数 = numthreads.x * numthreads.y * numthreads.z * Dispatch(x,y,z)
  2. 数据传递性能
    • 避免每帧频繁调用 SetData/GetData,尽量在 GPU 端完成所有计算。
    • 使用 ComputeBuffer.SetCounterValue 实现动态数据扩容(如粒子系统)。
  3. 同步问题
    • GPU 计算是异步的,若需同步等待,使用 ComputeShader.WaitForCompletion()(慎用,可能卡顿)。
  4. 平台兼容性
    • 移动端需检查 SystemInfo.supportsComputeShader,部分低端设备不支持。
相关推荐
在路上看风景5 小时前
31. Unity 异步加载的底层细节
unity
天人合一peng6 小时前
Unity中做表头时像work中整个调整宽窄
unity
小李也疯狂18 小时前
Unity 中的立方体贴图(Cubemaps)
unity·游戏引擎·贴图·cubemap
牛掰是怎么形成的18 小时前
Unity材质贴图引用陷阱:包体暴涨真相
unity·材质·贴图
呆呆敲代码的小Y18 小时前
【Unity工具篇】| 超实用工具LuBan,快速上手使用
游戏·unity·游戏引擎·unity插件·luban·免费游戏·游戏配置表
EQ-雪梨蛋花汤18 小时前
【Unity优化】Unity多场景加载优化与资源释放完整指南:解决Additive加载卡顿、预热、卸载与内存释放问题
unity·游戏引擎
我的offer在哪里19 小时前
用 Unity 从 0 做一个「可以玩的」游戏,需要哪些步骤和流程
游戏·unity·游戏引擎
泡泡茶壶ᐇ19 小时前
Unity游戏开发入门指南:从零开始理解游戏引擎核心概念
unity·游戏引擎
YigAin21 小时前
Unity中的Lock,到底在锁什么,什么时候该用?
unity
Var_al21 小时前
抖小Unity WebGL分包命令行工具实践指南
unity·游戏引擎·webgl