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.着色器语言的限定词-参数限定词/存储限定词/精度限定词)

shader编程-着色器中颜色基础(WebGL-Shader开发基础06)

shader编程-着色器中颜色基础(WebGL-Shader开发基础06)