WebGL-Shader入门(2.着色器语言GLSL ES矢量和矩阵的访问与运算)
Posted 点燃火柴
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WebGL-Shader入门(2.着色器语言GLSL ES矢量和矩阵的访问与运算)相关的知识,希望对你有一定的参考价值。
矢量类型和矩阵类型变量的访问与运算
1. 序
上一篇文章介绍了着色器语言的数据类型和简单使用,不过没有介绍矢量类型和矩阵类型的访问和运算,它们有很多想通之处,内容相对较多,所以专门用一篇文章来讲述。就先从它们的访问说起
2. 矢量的访问
矢量既可以通过点运算符(.)来访问也可以通过方括号运算符([])来访问
通常矢量通过点运算符来访问,只需要在矢量变量名后接点运算符,然后在接上分量名即可
先来介绍一下矢量的分量名
分量名 | 描述 |
---|---|
x,y,z,w | 用来获取顶点坐标的分量 |
r,g,b,a | 用来获取颜色分量 |
s,t,p,q | 用来获取纹理坐标的分量 |
矢量可以用来存储顶点坐标、颜色和纹理坐标。所以GLSL ES支持以上三种分量名,这样大家在使用的时候便于理解,实际上,一个矢量的x分量或r分量还是s分量都会返回这个矢量的第1个分量,一个矢量的y分量或g分量还是t分量都会返回这个矢量的第2个分量
2.1 单一分量访问
vec4 v4 = vec4(2.0,3.0,4.0,1.0);
float f;
f = v4.x; //f设为v4的第1个分量2.0
f = v4.y; //f设为v4的第2个分量3.0
f = v4.z; //f设为v4的第3个分量4.0
f = v4.w; //f设为v4的第4个分量1.0
f = v4.r; //f设为v4的第1个分量2.0
f = v4.g; //f设为v4的第2个分量3.0
f = v4.b; //f设为v4的第3个分量4.0
f = v4.a; //f设为v4的第4个分量1.0
f = v4.s; //f设为v4的第1个分量2.0
f = v4.t; //f设为v4的第2个分量3.0
f = v4.p; //f设为v4的第3个分量4.0
f = v4.q; //f设为v4的第4个分量1.0
f = v4.x; //f设为v4的第1个分量2.0
f = v4.r; //f设为v4的第1个分量2.0
f = v4.s; //f设为v4的第1个分量2.0
对矢量进行单一访问是可以使用[]操作符通过索引对矢量分量进行访问
vec4 v4 = vec4(2.0,3.0,4.0,1.0);
float f;
f = v4[0]; //f设为v4的第1个分量2.0
f = v4[1]; //f设为v4的第2个分量3.0
f = v4[2]; //f设为v4的第3个分量4.0
f = v4[3]; //f设为v4的第4个分量1.0
2.2 分量组合使用
通过分量名还可以有更多灵活的用法, 例如,可以取任意分量组合,可以逆序使用,可以重复使用,请看以下示例
vec4 v4 = vec4(1.0,2.0,3.0,4.0);
vec2 v2,v3;
v2 = v4.xy; //将v2设置为(1.0,2.0)
v2 = v4.yz; //将v2设置为(2.0,3.0)
v2 = v4.xz; //将v2设置为(1.0,3.0)
v2 = v4.xw; //将v2设置为(1.0,4.0)
v2 = v4.xx; //将v2设置为(1.0,1.0)
v2 = v4.wx; //将v2设置为(4.0,1.0)
v3 = v4.xyz;//将v3设置为(1.0,2.0,3.0)
v3 = v4.xzw;//将v3设置为(1.0,3.0,4.0)
v3 = v4.zzz;//将v3设置为(3.0,3.0,3.0)
v3 = v4.wzy;//将v3设置为(4.0,3.0,2.0)
注意,多个分量名使用时必须属于同一集合,例如不可以使用v3.was
2.3 分量聚合作为左值使用
vec4 position = vec4(1.0,2.0,3.0,4.0);
position.yw = vec2(6.0,9.0);//position = (1.0,6.0,3.0,9.0)
3. 矩阵的访问
矩阵也是既可以通过点运算符(.)来访问也可以通过方括号运算符([])来访问
通常矩阵通过方括号[] 运算符来访问,使用[]访问矩阵时,类似于访问javascript中的二维数组,大家已经知道WebGL中的矩阵是按列主序的,那么通过[0]访问到的是矩阵中第1列元素,通过[1]访问到的是矩阵中第2列元素,请看以下示例
mat4 m4 = mat4(
1.0, 2.0, 3.0, 4.0,
5.0, 6.0, 7.0, 8.0,
9.0, 10.0, 11.0, 12.0,
13.0, 14.0, 15.0, 16.0
);
vec4 v4_1 = m4[0];//获取到矩阵第一列元素,即[1.0,2.0,3.0,4.0]
float m23 = m4[1][2];//将m23设置为m4中的第2列中的第3个元素,即7.0
//同时使用[]运算符和分量名访问矩阵元素
float m32 = m4[2].y;//将m32设置为m4中的第3列中的第2个元素,即10.0
float m33 = m4[2].z;//将m33设置为m4中的第3列中的第3个元素,即11.0
注意,使用[ ]运算符访问矩阵元素时,索引值必须是常量
int index1 = 0;
vec4 v4_2 = m4[index];//错误index1不是常量索引
const int index2 = 0;
vec4 v4_3 = m4[index2];//获取到矩阵第一列元素,即[1.0,2.0,3.0,4.0]
4. 矢量与矩阵支持的运算符
运算符 | 运算 | 适用数据类型 |
---|---|---|
*,/ | 乘法, 除法 | 适用vec[234]和mat[234] |
+,- | 加法, 减法 | 运算结果的数据类型与参与运算的类型一致 |
++,– | 自增, 自减 | 适用vec[234]和mat[234],运算结果的数据类型与参与运算的类型一致 |
= | 赋值 | 适用vec[234]和mat[234] |
+=,-=,*=,/= | 运算赋值 | 适用vec[234]和mat[234] |
==,!= | 比较 | 适用vec[234]和mat[234],对于==,如果两边变量的每一个分量都相同返回true,对于!=,两边变量的任何一个分量不同返回true |
以上上矢量与矩阵支持的运算符,与基本类型相比,只可以使用==或!=比较运算符,如果确实需要比较矢量或矩阵的大小,可以使用内置函数比较函数
5. 矢量与矩阵的运算
5.1 矢量和数字的运算
矢量和数字的运算,相当于每个分量与该数都做相同的运算,注意矢量分量的类型要与参与运算的数字的类型保持一致,请参照以下示例
//矢量与浮点数运算
vec3 v3 = vec3(2.0,4.0,6.0);
vec3 result;
result = v3 + 2.0;//result = vec3(4.0,6.0,8.0)
result = v3 - 1.0;//result = vec3(1.0,3.0,5.0)
result = v3 * 2.0;//result = vec3(4.0,8.0,12.0)
result = v3 / 2.0;//result = vec3(1.0,2.0,3.0)
//矢量与整数运算
ivec3 iv3 = vec3(2,4,6);
ivec3 res;
res = iv3 + 2;//res = vec3(4,6,8)
res = iv3 - 1;//res = vec3(1,3,5)
res = iv3 * 2;//res = vec3(4,8,12)
res = iv3 / 2;//res = vec3(1,2,3)
5.2 矢量和矢量的运算
矢量和矢量的运算,首先要保证操作矢量的阶数都相同.否则不能计算,计算过程是前一个矢量每个分量与另一个矢量对应的分量做运算,具体请参照以下示例
vec3 v3_1 = vec3(2.0,4.0,6.0);
vec3 v3_2 = vec3(-2.0,-4.0,-6.0);
vec3 result;
result = v3_1 + v3_2;//result = vec3(0.0,0.0,0.0)
result = v3_1 - v3_2;//result = vec3(4.0,8.0,12.0)
result = v3_1 * v3_2;//result = vec3(-4.0,-16.0,-36.0)
result = v3_1 / v3_2;//result = vec3(-1.0,-1.0,-1.0)
5.3 矩阵和浮点数的运算
矩阵和浮点数运算,相当于矩阵的每个元素都与该浮点数做运算
以加法为例说明一下,减法、乘法、除法与加法雷同,都是逐元素和浮点数运算
mat4 m4 = mat4(
1.0, 2.0, 3.0, 4.0,
5.0, 6.0, 7.0, 8.0,
9.0, 10.0, 11.0, 12.0,
13.0, 14.0, 15.0, 16.0
);
mat4 m4_res = m4 + 2.0;//m4_res = mat4(
//3.0, 4.0, 5.0, 6.0,
//7.0, 8.0, 9.0, 10.0,
//11.0, 12.0, 13.0, 14.0,
//15.0, 16.0, 17.0, 18.0
//);
5.4 矩阵和矩阵相乘
矩阵与矩阵相乘计算过程麻烦一些,以三维矩阵与三维矩阵相乘为例说明一下,22矩阵与44矩阵运算过程雷同
mat3 m3_1 = mat3(
1.0, 2.0, 3.0,
4.0, 5.0, 6.0,
7.0, 8.0, 9.0
);
mat3 m3_2 = mat3(
1.0, 2.0, 3.0,
4.0, 5.0, 6.0,
7.0, 8.0, 9.0
);
mat3 m3_res = m3_1 * m3_2;
/*
mat3 m3_res = mat3(
1.0*1.0+2.0*4.0+3.0*7.0, 1.0*2.0+2.0*5.0+3.0*8.0, 1.0*3.0+2.0*6.0+3.0*9.0,
4.0*1.0+5.0*4.0+6.0*7.0, 4.0*2.0+5.0*5.0+6.0*8.0, 4.0*3.0+5.0*6.0+6.0*9.0,
7.0*1.0+8.0*4.0+9.0*7.0, 7.0*2.0+8.0*5.0+9.0*8.0, 7.0*3.0+8.0*6.0+9.0*9.0,
)
*/
注:A*B 与 B*A 结果是不一样,计算时要注意顺序
5.5 矩阵和右乘矢量
矩阵右乘矢量的结果还是矢量,每个分量都是原矢量中对应的分量,每个分量值为原矢量分量乘上矩阵对应行每个元素然后求和,使用时请参照以下公式
5.6 矩阵和左乘矢量
矩阵左乘矢量同样也是返回一个向量,但与右乘矢量结果完全不同,计算时需要先将这个矢量转置,然后用这个转置后的矢量乘以矩阵,具体参数以下说明
以上是关于WebGL-Shader入门(2.着色器语言GLSL ES矢量和矩阵的访问与运算)的主要内容,如果未能解决你的问题,请参考以下文章
WebGL-Shader入门(4.着色器语言GLSL ES函数定义与流程控制)
WebGL-Shader入门(1.着色器语言GLSL ES数据类型介绍与使用)
WebGL-Shader入门(6.着色器语言GLSL ES 预处理指令和宏定义)
WebGL-Shader入门(3.着色器语言的限定词-参数限定词/存储限定词/精度限定词)