# 初识 glsl

# 一、数据结构

# 1. 数据类型

​ glsl 的值分为以下几种,无字符串类型。

  1. int: 整型
  2. uint: 无符号整型
  3. float: 单精度浮点型
  4. double: 双精度浮点型
  5. bool: 布尔类型

glsl 的数据类型分为向量和矩阵。注意不同的向量类型只能储存对应的类型的值。比如 vec 储存浮点数比如 1.0,而不能储存其他类型,比如 1 为整型,true 为布尔型。另外如果数据如果小数位太多使用单精度浮点数储存时可能会损失精度。

# 向量:
  1. vec (2,3,4): 表示储存 (2,3,4) 个单精度浮点数的向量。
  2. dvec (2,3,4): 表示储存 (2,3,4) 个双精度浮点数的向量
  3. ivec (2,3,4): 表示储存 (2,3,4) 个整型的向量
  4. uvec (2,3,4): 表示储存 (2,3,4) 个无符号整型的向量
  5. bvec (2,3,4): 表示储存 (2,3,4) 个布尔值的向量
# 矩阵:
  1. mat (2,3,4): 表示 (2,3,4) 阶矩阵,其中值为单精度浮点数

  2. mataxb: 表示 a 行 b 列矩阵。其中值为单精度浮点数

  3. dmat (2,3,4): 表示 (2,3,4) 阶矩阵,其中值为双精度浮点数

  4. dmataxb: 表示 a 行 b 列矩阵。其中值为双精度浮点数

# 2. 变量创建,赋值和类型转化

glsl 在声明变量的时候需要在变量前面添上变量类型,因为 glsl 是基于 c 语言制作的,所以这点与 c 语言相同。另外在赋值的时候需保证左右两边的数值类型相同。比如 int x = 1 正确,float x = 1 是错误的。如果左右两边的类型不同可以进行类型转化。比如:float x = float (1)。以下是三种内置的类型转化函数

  1. int (float 或 bool): 将浮点数或者布尔值转化为整型。true 转为 1,flase 转为 0,浮点数转整型相当于向下取整。
  2. float (int 或 bool): 将整型或者布尔值转化为浮点数。true 转为 1.0,flase 转为 0.0, 整型加一位小数 0
  3. bool (int 或 float): 将整型或者浮点数。对于整型如果是 0 则为 false,其他为 true,对于浮点数,0.0 为 false,其他为 true。
1
2
3
4
5
6
7
8
9
10
11
12
 向量初始化:
vec3 v1 = vec3(a,b,c,d) //如果传入的参数多了,多出来的不会传入。
vec3 v2 = vec3(a) //可以只传入一个参数,后面的数与第一个数相同。
vec3 v2 = vec3(a,b) //如果传入多个参数,但是参数小于要求的就会报错。
vec2 v3 = vec2(a,b)
vec2 v4 = vec2(c,d)
vec4 v5 = vec4(v3,v4) //可以使用其他向量创建向量
矩阵初始化:
mat2 m1 = mat2 (a,b,c,d) //注意矩阵是以列创建的。
mat2 m2 = mat2 (v3,v4) //矩阵可以由其他向量构成。
mat4 m3 = mat4 (a) //创建主对角线为a的四阶矩阵。
mat4 m3 = mat4 (a,b) //如果传入多个参数,但是参数小于要求的就会报错。

# 3. 向量和矩阵的访问

访问向量或者矩阵的元素可以使用 [] 或者。运算符。

# 向量访问:

向量名。分量。分量有以下三种集合

x,y,z,w

r,g,b,a

s,t,p,q

v1.x: 即可获取 v1 向量的第一个值。如果访问多个值可以使用混合 (swizzling)。另外分量名需在同一个集合比如 xyzw,而不能 x 和 g 混用,如果访问的不存在的分量就会报错。

float v2 = v1.xyw: 即可获取 v1 第一,二,四个的值。

float v3 = v1.zx: 可以逆序即获取 v1 第三,一个的值

float v4 = v1.xx: 可以重复获取,获取 v1 的第一,一个的值。

# 矩阵访问:

float m1 = mat [a] [b] // 访问 a 列 b 行的元素,注意先列再行。

float m2 = mat [a].y//[] 和。可以混用 访问 a 列第二行的元素

vec m3 = mat [a] // 访问 a 列的元素

# 4. 向量和矩阵的运算

  1. 向量与数之间的运算:vec4 v1 = v2 (+,-,/*) 1.0 相当于 v2 向量的四个值加减乘除上 1。
  2. 向量与向量之间的运算:vec4 v1 = v2 (+,-,/*) v3 相当于 v2 向量的四个值加减乘除 v3 对应的四个值。
  3. 矩阵与数之间的运算:mat4 m1 = m2 (+,-,/*) 1.0 相当于 m2 矩阵的每一个元素加减乘除上 1。
  4. 矩阵与向量之间的运算: vec4 v2 = v1 * m1 注意矩阵乘法没有交换律。
  5. 矩阵与矩阵之间的运算:mat4 m3 = m1 * m2

# 5. 结构体

glsl 的结构体和 typescript 的接口有点类似。

1
2
3
4
5
6
7
//使用struct创建结构体
struct a {
vec4 postion
vec4 color
}
//使用.访问结构体的成员
a.postion = vec4(1.0,1.0,1.0,1.0)

# 6. 数组

glsl 的数组与其他语言的数组不太一样。glsl 的数组只能是一维的,同时没有 pop () 和 push () 等操作。

1
2
3
4
5
6
7
8
9
10
11
//在变量名后面加[]即可创建数组
vec4 array[3] //创建一个能储存三个有四个浮点数构成的向量的数组
float array[2] //创建能储存两个浮点数的数组
//数组访问与其他语言相同,使用下标访问
array[0] //访问第一个元素
//数组赋值
float array[4] = {1,0,1.0,1.0,1.0} //使用{}赋值
array[0] = 1.0 //创建数组后,也可以使用下标访问数组赋值
float array[2] = float[2](1.0,1.0) //可以使用glsl内置的构造函数赋值
vec2 array[2] = vec2[2](vec2(1.0,1.0),vec2(1.0,1.0))
mat2 array[2] = mat2[2](mat2(1.0),mat2(1.0))

# 二、函数

glsl 的 if,elseif,还有循环与 JavaScript 一致,另外 glsl 没有 Switch。glsl 的函数和 typescript 类似。函数名前面要加返回值类型,如果没有返回值则为 void,形参也要加类型。

返回值类型(如果没有则为 void)函数名 (形参类型 形参){}。

如果传入的参数与形参的类型不一致会报错。如果函数在创建前就已经调用了,则需要先声明,这点与 JavaScript 使用 let 或者 const 创建函数的规则一致。另外 glsl 不支持自己调用自己,也即无法递归。

在 glsl 中参数可以加以下四种参数限定词

in: 如果默认不加参数限定词的话,就是这个。

const in: 函数内可以使用这个参数,但是无法改变这个参数,const 表示常量

out: 在函数内修改这个值的话,会影响实参的值。

inout:与 out 不同的是,这个传入参数时必须要初始化。

# 三、与着色器相关的限定字

  1. Attribute: 储存与顶点着色器相关的数据,比如坐标,大小。
  2. uniform: 可以储存顶点着色器或者片元着色器的数据。如果顶点着色器或片元着色器出现了同名的 uniform 变量,这两种着色器则会共同使用这个变量的数据。有一些操作不是逐顶点的,比如变换矩阵,这时这类数据就使用 uniform 储存。
  3. varying: 从顶点着色器想片元着色器传输数据。