GLSL ES 支持矢量和矩阵类型,这两种数据类型很适合用来处理计算机图形。矢量和矩阵类型的变量包含多个元素,每个元素是一个数值。矢量将这些元素排成一列,可以用来表示顶点坐标或颜色值等,而矩阵则将元素划分成行和列,可以用来表示变换矩阵。下图给出了矢量和矩阵的例子:
GLSL ES 支持多种不同的矢量和矩阵类型,如下表所示:
下面是声明矢量和矩阵的例子:
vec3 position; //由三个浮点数元素组成的矢量
ivec2 offset; //由两个整型数元素组成的矢量
mat4 mvpMatrix; //4x4矩阵,每个元素为一个浮点数
赋值和构造
我们使用等号来对矢量和矩阵进行赋值操作。记住,赋值运算符左右两边的变量/值的类型必须一直,左右两边的元素个数也必须相同。比如说,下面这行代码就会出错。
vec4 position = 1.0; //vec4 变量需要4个浮点数分量
这里,vec4类型变量有4个元素,你应当以某种方式传入4个浮点数值。通常我们使用与数据类型同名的内置函数来生成变量,对于vec4类型来说,就可以使用内置的 vec4()函数。比如,如果要创建4个分量各是 1.0、2.0、3.0 和 4.0 的vec4 类型变量,你就可以像下面这样调用 vec4()函数。
vec4 position = vec4(1.0, 2.0, 3.0, 4.0);
这种专门创建指定类型的变量的函数被称为 构造函数,构造函数的名称和其创建的变量的类型名称总是一致的。
矢量构造函数
在 GLSL ES 中,矢量非常重要,所以GLSL ES 提供了丰富灵活的方式来创建矢量。比如:
vec3 v3 = vec3(1.0, 0.0, 0.5);
vec2 v2 = vec2(v3);
vec4 v4 = vec4(1.0);
在第2行代码中,构造函数忽略了 v3 的第3个分量,只用其第1个和第2个分量创建了一个新的变量。类似的,在第3行海马中,只向构造函数中传入了一个参数 1.0,构造函数就会自动得将这个参数值赋给新建矢量的所有元素。但是,如果构造函数接受了不止1个参数,但是参数的个数又比矢量的元素个数少,那么就会出错。
最后,也可以将多个矢量组合成一个矢量,比如:
vec4 v4b = vec4(v2, v4);
这里的规则是,先把第1个参数v2的所有元素填充进来,如果还未填满,就继续用第2个参数 v4 中的元素填充。
矩阵构造函数
矩阵构造函数的使用方式与矢量构造函数的使用方式很类似。但是,你要保证存储在矩阵中的元素是按照主序排列的。下面几个例子显示了使用矩阵构造函数的不同方式。
- 向矩阵构造函数中传入矩阵的每一个元素的数值来构造矩阵,注意传入值的顺序必须是列主序的。
- 向矩阵构造函数中传入一个或多个矢量,按照主序使用矢量里的元素值来构造矩阵。
- 向矩阵构造函数中传入矢量和数值,按照列主序使用矢量里的元素值和直接传入的数值来构造矩阵。
- 向矩阵构造函数中传入单个数值,这样将生成一个对角线上元素都是该数值,其他元素为 0.0 的矩阵。
与矢量构造函数类似,如果传入的数值的数量大于1,又没有达到矩阵元素的数量,就会出错。
访问元素
为了访问矢量或矩阵中的元素,可以使用 . 或 []元素符,下面将分节叙述。
运算符
在矢量变量名后接点运算符,然后接上分量名,就可以访问矢量的元素了。矢量的分量名如下表所示:
由于矢量可以用来存储顶点的坐标,颜色和纹理坐标,所以 GLSL ES 支持以上三种分量名称以增强程序的可读性。事实上,任何矢量的x、r或s分量都会返回第1个分量,y、g、t 分量都返回第2个分量,等等。如果你愿意,你可以随意得交换使用它们。比如:
如你所见,这些例子中,x、r 和 s 虽然名称不同,但访问的却都是第1个分量。如果试图访问超过矢量长度的分量,就会出错:
将多个分两名共同置于点运算符后,就可以从矢量中同时抽取出多个分量。这个过程称作混合。下面这个例子中,我们使用了x、y、z 和 w,其他的集合也有相同的效果:
聚合分两名也可以用来作为赋值表达式的左侧:
记住,此时的多个分两名必须属于同一个集合,比如说,你不能用 v3.was。
[ ]运算符
除了. 元素符,还可以使用 [] 运算符并通过数组下表来访问矢量或矩阵的元素。注意,矩阵中的元素仍然是按照列主序读取的。与在JS中一样,下标从0开始,所以通过[0]可以访问到矩阵中的第1列元素,[1] 可以访问到第2列元素,[2] 可以访问到第3列元素,等等,如下所示:
此外,连续使用两个 [] 运算符可以访问某列的某个元素:
此外,你也可以同时使用 [] 元素符和分量名来访问矩阵中的元素,如下所示:
这里有一个限制,那就是在 [] 中只能出现的索引值必须是 常量索引值,常量索引值的定义如下:
- 整形字面量(如0或1)
- 用 const 修饰的全局变量或局部变量,不包括函数参数
- 循环索引
由前述三条中的项组成的表达式。
下面这个例子就用到了 const 变量作为访问数组元素的索引:
下面这个例子用到了 const 组成的表达式作为索引:
注意,你不能使用未经 const 修饰的变量作为索引值,因为它不是一个常量索引值:
运算符
下表显示了矢量和矩阵所支持的运算。矩阵和矢量的运算符和基本类型的运算符很类似。注意,对于矢量和矩阵,只可以使用比较运算符中的 == 和 !=,不可以使用 > 、<、>= 和 <=。如果你想比较矢量和矩阵的大小,应该使用内置函数,比如 lessThan()。
注意,当运算赋值操作作用于矢量或矩阵时,实际上是逐分量地对矩阵或矢量的每一个元素进行独立的运算赋值。
示例
下面这些例子显示了矢量和矩阵在运算时的常见情形。我们假设,在这些列子中,变量是如下定义的:
矢量和浮点数的运算
这个例子显示了 + 操作符的作用:
例如,v3a = vec3(1.0, 2.0, 3.0) 而 f = 1.0,那么结果就是 v3b = (2.0, 3.0, 4.0)。
矢量运算
矢量运算操作发生在矢量的每个分量上
例如,v3a = vec3(1.0, 2.0, 3.0) 而 v3b = (4.0, 5.0, 6.0),那么结果就是 v3c = (5.0, 7.0, 9.0)。
矩阵和浮点数的运算
矩阵与浮点数的运算发生在矩阵的每个分量上。
矩阵右乘矢量
矩阵右乘矢量的结果是矢量,其中每个分量都是原矢量中的对应分量,乘上矩阵对应行的每个元素的积的加和。
矩阵左乘矢量
矩阵左乘矢量也是可以的,但是结果与右乘不同,如下所示:
矩阵与矩阵相乘
矩阵与矩阵相乘,参考第4章
- -