UPL9-17-b——数据类型

Compute Shader 中的数据类型

Compute Shader 的数据类型和普通 HLSL(即 Unity Shader)非常接近,
但由于它不走渲染管线,它的重点在于 通用计算与内存访问,因此在类型体系上有一些专门针对 数据并行 和 存储 的扩展
主要分为:

  1. 标量类型
  2. 向量类型
  3. 矩阵类型
  4. 复合类型
  5. 纹理类型
  6. 常量缓冲区

注意:这里只强调常用的类型

标量类型

  • bool:布尔类型
  • uint:32位无符号整形
  • int:32位整形
  • float​:32位浮点数,符号:f
  • double:64位浮点数
  • half​:16位浮点数,符号:h

注意:虽然支持 half​,但是由于对齐问题和平台支持问题以及和 C# 数据交互问题(C# 没有 half 类型),不建议在 ComputeShader 中使用

1
2
3
4
5
6
bool b;     // 1byte
int i; // 4byte
uint ui; // 4byte
float f; // 4byte
double d; // 8byte
half h; // 2byte

向量类型

内置的向量类型是基于基础数据类型声明的
向量的最大维度不超过 4 维,数据类型可以是任意数值类型(也就是基础数据类型的数值类型)

基本构成:

  • 数据类型2 = 数据类型2(n1,n2)
  • 数据类型3 = 数据类型3(n1,n2,n3)
  • 数据类型4 = 数据类型4(n1,n2,n3,n4)
1
2
3
4
5
float2 f2; float3 f3; float4 f4;
int2 i2; int3 i3; int4 i4;
uint2 ui2; uint3 ui3; uint4 ui4;
bool2 b2; bool3 b3; bool4 b4;
// ...
1
2
3
4
5
6
7
8
//二维向量
int2 i2 = int2(2, 3);
float2 f2 = float2(2.0f, 3.1f);
half2 h2 = half2(3.0h, 4.0h);
//三维向量(以float为例)
float3 f3 = float3(2, 3, 4);
//四维向量(以int为例)
int4 i4 = int4(1, 2, 3, 4);

矩阵类型

矩阵类型属于 CG 语言的内置数据类型

矩阵的最大行列不大于 4,不小于 1,数据类型可以是任意数值类型

基本构成:

  • 数据类型'n'x'm' = {n1m1, n1m2, n1m3.....}
  • 数据类型2x2
  • 数据类型3x3
  • 数据类型4x4
1
2
3
float2x2
float3x3
float4x4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//矩阵声明示例(以2x3,3x3为例)
int2x3 mInt2x3 =
{
1, 2, 3,
4, 5, 6
};

float3x3 mFloat3x3 =
{
1.0, 2.0, 3.0,
4.0, 5.0, 6.0,
7.0, 8.0, 9.0
};

复合类型

结构体

1
2
3
4
struct 结构体名
{
各类型数据
}
1
2
3
4
5
6
struct Test
{
float3 position;
float3 velocity;
float lifetime;
};

缓冲区

  • 结构体数组

    • 只读结构体数组(只读)StructuredBuffer<T>

      1
      2
      3
      4
      5
      6
      7
      8
      struct Test
      {
      float3 position;
      float3 velocity;
      float lifetime;
      };

      StructuredBuffer<Test> buffer;
    • 可读写结构体数组(读写)

      1
      2
      3
      4
      5
      6
      7
      8
      struct Test
      {
      float3 position;
      float3 velocity;
      float lifetime;
      };

      RWStructuredBuffer<Test> buffer2;
  • 字节访问数组

    • 低级字节访问数组(只读)

      1
      ByteAddressBuffer buffer3;
    • 可读写字节访问数组(读写)

      1
      RWByteAddressBuffer buffer4;
  • 动态追加元素缓冲区(队列式)

    适合一开始不知道输出元素个数的场景,可以动态想其中添加内容,只能通过 Append() 添加

    1
    AppendStructuredBuffer<float> buffer5;
  • 动态消耗元素缓冲区(队列式)

    动态从中移除对象,只能通过 Consume() 移除

    1
    ConsumeStructuredBuffer<float> buffer6;

纹理类型

1
2
3
4
5
Texture1D, Texture2D, Texture3D   // 只读普通采样纹理 
RWTexture2D, RWTexture3D // 可读写纹理
TextureCube // 立方体贴图
Texture2DMS // 多重采样纹理,用于抗锯齿
RWTexture2DArray // 可读写的纹理数组

其中,纹理类型后面可以接 <T>​,代表该纹理中的像素有多少数据,它由图片的格式和作用决定
例如,对于一张 RGBA 通道格式的贴图,对应的纹理类型就是 RWTexture2D<float4>​,
对于一张法线图,只有 RGB 三个通道,对应的纹理类型就是 RWTexture2D<float3>​,
如果是一张高度图,只有一个通道数值,则对应的纹理类型就是 RWTexture2D<float>

常量缓冲区

用于将一组常量打包在一起传给 ComputeShader,按块上传数据更高效,驱动可以批量上传并放进高效缓存

1
2
3
4
cbuffer 自定义常量区名(常用 Params): register(b[寄存器索引])    // ": register(b[寄存器索引])" 部分可省略
{
// 各类型数据
};

注意:
后面的寄存器索引相关 : register(b[寄存器索引])​ 可省略,省略后Unity会自动分配
如果要写,所以必须是 b0​ 到 b13,代表14个常量缓冲区
在编写 Compute Shader 时,应当尽量使用较少的 cbuffer,并注意每个平台的最大常量缓冲区数量

1
2
3
4
5
6
cbuffer Params : register(b0)
{
float deltaTime;
float intensity;
int count;
};