十、WGSL 笔记

120 阅读4分钟

WGSL需要明确直到每个变量、结构字段、函数参数和函数返回值的类型。

普通类型

  • i32 :32位有符号整型
  • u32 :32位无符号整型
  • f32 :32位浮点型
  • bool :boolean类型
  • f16 :16位浮点型 (可选功能,需要主动开启)

变量声明

在WGSL中,所有变量都具有块作用域。var是一个具有存储空间的变量,因此是可变的。let为常数值,不可变。const不是一个变量,它是一个编译时常数。运行时发生变化的对象不能使用const。

const one: f32 = 1; 
var a: f32 = 1;
let c: f32 = 3;
fn d(e: f32) -> f32 { return e * 2; }

矢量Vector

WGSL中有3种矢量类型vec2、vec3和vec4。他们的基本风格是vec?,所以vec2是一个包含2个i32数值的矢量,vec3是一个包含3个f32元素的矢量,vec4是一个包含4个u32数值的矢量,vec3一个包含3个布尔值的矢量。

let a = vec2<i32>(1, -2);
let b = vec3<f32>(3.4, 5.6, 7.8);
let c = vec4<u32>(9, 10);

//如何访问
let a = vec4<f32>(1, 2, 3, 4);
let b = a.z;   // via x,y,z,w
let c = a.b;   // via r,g,b,a
let d = a[2];  // via array element accessors
//一次访问多个元素
let a = vec4<f32>(1, 2, 3, 4);
let b = a.zx;   // via x,y,z,w
let c = a.br;   // via r,g,b,a
let d = vec2<f32>(a[2], a[0]);

数学运算

let a = vec4f(1, 2, 3, 4);
let b = vec4f(5, 6, 7, 8);
let c = a + b;  // c is vec4f(6, 8, 10, 12)
let d = a * b;  // d is vec4f(5, 12, 21, 32)
let e = a - b;  // e is vec4f(-4, -4, -4, -4)
//函数
let a = vec4f(1, 2, 3, 4);
let b = vec4f(5, 6, 7, 8);
let c = mix(a, b, 0.5);                   // c is vec4f(3, 4, 5, 6)
let d = mix(a, b, vec4f(0, 0.5, 0.5, 1)); // d is vec4f(1, 4, 5, 8)

矩阵Matrices

WGSL中包含很多矩阵类型,矩阵可以看作是一组矢量。格式为matx<>,以mat3x4为例,可以看作是3个vec4。和矢量一样,矩阵也有简写形式

// a 和 b 类型一样
let a: mat4x4<f32> = ...
let b: mat4x4f = ...

// 访问
let a = mat4x4f(...);
let b = a[2];   // b is a vec4f of the 3rd vector of a

数组arrays

WGSL中数组可以通过array<type, numElements>进行声明。

let a = array<f32, 5>;   // an array of five f32s
let b = array<vec4f, 6>; // an array of six vec4fs

// 其它构造方式,它接受任意数量的参数并返回一个数组,而且参数必须是相同的类型。
let arrOf3Vec3fsA = array(vec3f(1,2,3), vec3f(4,5,6), vec3f(7,8,9));
let arrOf3Vec3fsB = array<vec3f, 3>(vec3f(1,2,3), vec3f(4,5,6), vec3f(7,8,9));

// runtime sized arrays
@group(0) @binding(0) var<storage> foo: array<mat4x4f>;
// 使用arrayLength查询长度。
let numMatrices = arrayLength(&foo);

函数functions

WGSL中函数声明形式为fn name(parameters) -> returnType { ..body... }

fn add(a: f32, b: f32) -> f32 {
  return a + b;
}

着色器入口entry points

WGSL代码需要一个入口函数,可以通过@vertex, @fragment 或 @compute进行标识。

@vertex fn myFunc(a: f32, b: f32) -> @builtin(position): vec4f {
  return vec4f(0, 0, 0, 0);
}

属性attributes

单词attributes在WebGPU中有两种含义,一种是顶点属性(vertex attributes)在顶点缓存区已经介绍过。另一种是WGSL中以@开头的属性。

@location(number) //用来定义着色器的输入和输出。

阶段变量inter stage variables

对于阶段变量,@location属性定义变量在着色器之间传递的位置。

struct VSOut {
  @builtin(position) pos: vec4f,
  @location(0) color: vec4f,
  @location(1) texcoords: vec2f,
};
 
struct FSIn {
  @location(1) uv: vec2f,
  @location(0) diffuse: vec4f,
};
 
@vertex fn foo(...) -> VSOut { ... }
@fragment fn bar(moo: FSIn) ... 

片元着色器输出fragment shader outputs

在片元着色器中@location指定了使用哪个GPURenderPassDescriptor.colorAttachment存储结果。

struct FSOut {
  @location(0) albedo: vec4f;
  @location(1) normal: vec4f;
}
@fragment fn bar(...) -> FSOut { ... }

// @builtin(name)属性通常用于指定来之WebGPU内置变量的值。
@vertex fn vs1(@builtin(vertex_index) foo: u32, @builtin(instance_index) bar: u32) ... {
  ...
}

流程控制 flow control

// for ////////////////
  for (var i = 0; i < 10; i++) { ... }
// if //////////////////
   if (i < 5) {
      ...
    } else if (i > 7) {
      ..
    } else {
      ...
    }
// while ///////////////////
  var j = 0;
  while (j < 5) {
    ...
    j++;
  }
// loop //////////////////////////
  var k = 0;
  loop {
    k++;
    if (k >= 5) {
      break;
    }
  }
// break
 var k = 0;
  loop {
    k++;
    if (k >= 5) {
      break;
    }
  }
// break if
  var k = 0;
  loop {
    k++;
    break if (k >= 5);
  }
// continue
  for (var i = 0; i < 10; ++i) {
    if (i % 2 == 1) {
      continue;
    }
    ...
  }
​
// continuing
  for (var i = 0; i < 10; ++i) {
    if (i % 2 == 1) {
      continue;
    }
    ...
 
    continuing {
      // continue goes here
      ...
    }
  }
// discard
   if (v < 0.5) {
     discard;
   }
// discard仅在片元着色器中可以使用。

// switch /////////////////////////
var a : i32;
let x : i32 = generateValue();
switch x {
  case 0: {      // The colon is optional
    a = 1;
  }
  default {      // The default need not appear last
    a = 2;
  }
  case 1, 2, {   // Multiple selector values can be used
    a = 3;
  }
  case 3, {      // The trailing comma is optional
    a = 4;
  }
  case 4 {
    a = 5;
  }
}