【WebGL之巅】12-使用Matrix4变换矩阵实现三角形旋转、平移、缩放

By 大Van家 on 2021-07-27
阅读时间 7 分钟
文章共 1.7k
阅读量

对应《WebGL编程指南》代码:13-RotatedTriangle_Matrix4

要点:矩阵变换库(cuon-matrix.js 本书专用)、Matrix4对象

知识点

一、矩阵变换库cuon-matrix.js

OpenGL中提供了一系列有用的函数来创建变换矩阵,而WebGL没有,本书作者编写了一套函数库(cuon-matrix.js)解决这个问题。

cuon-matrix.js在其中的Matrix4对象中提供了创建变换矩阵的方法。Matrix4对象(实例)是指Matrix4类型的对象,即“调用Matrix4构造函数生成的对象”,表示一个4x4矩阵,该对象内部使用Floated32Array来存储矩阵元素。

例:创建一个选择矩阵

1
2
3
4
5
6
7
// 为旋转矩阵创建Matrix4对象
var xformMatrix = new Matrix4();
// 将xformMatrix设置为旋转矩阵
xformMatrix.setRotate(ANGLE, 0, 0, 1);
var u_xformMatrix = gl.getUniformLocation(gl.program, 'u_xformMatrix');
// 将旋转矩阵传输给顶点着色器
gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix.elements);
二、setRotate(ANGLE, 0, 0, 1)

参数:

​ 旋转角(角度值):ANGLE>0,表示逆时针方向

​ 旋转轴(x, y, z):(0, 0, 1)表示绕z轴旋转

三、Matrix4对象支持的方法和属性
setIdentity()

​ 将Matrix4实例初始化为单位阵。(单位阵:对角线为1,其余全为0的矩阵,类似1的效果)

setTranslate(x, y, z)

​ 将Matrix4实例设置为平移变换矩阵,在x轴上平移的距离为x,在y轴上平移的距离为y,在z轴上平移的距离为z

setRotate(angle, x, y, z)

​ 将Matrix4实例设置为旋转变换矩阵,旋转角度为angle,旋转轴为(x, y, z)。旋转轴(x,y,z)无需归一化(参加“光照”)

setScale(x, y, z)

​ 将Matrix4实例设置为缩放变换矩阵,在三个轴上的缩放因子分别为x、y、z

translate(x, y, z)

​ 将Matrix4实例乘以一个平移变换矩阵(该平移矩阵在x轴上的平移距离为x,在y轴上的平移距离为y,在z轴上的平移距离为z),所得到的结果存储在Matrix4中

rotate(angle, x, y, z)

​ 将Matrix4实例乘以一个旋转变换矩阵(该旋转矩阵旋转的角度为angle,旋转轴为(x、y、z)。旋转轴(x、y、z)无须归一化),所得的结果还存储在Matrix4中

scale(x, y, z)

​ 将Matrix4实例乘以一个缩放变换矩阵(该缩放矩阵在三个轴上的缩放因子分别为x、y、z。),所得结果还存储在Matrix4中

set( m )

​ 将Matrix4实例设置为m,m必须也是一个Matrix4实例

elements

​ 类型化数组(Float32Array)包含了Matrix4实例的矩阵元素

说明:单位阵在矩阵乘法中的行为,就像数字1在乘法中的行为一样。将一个矩阵生意单位阵,得到的结果和原矩阵完全相同。在单位阵中,对角线的元素为1.0,其余的元素为0.0。

multiply(matrix)

​ 两个矩阵相乘,返回的结果为一个新的matrix4对象,并且值为两个矩阵相乘的结果。例如:

1
var modelViewMatrix = viewMatrix.multiply(modelMatrix);
setOrtho(left, right, bottom, top, near, far)

​ 通过各参数计算正射投影矩阵,将其存储在Matrix4中。注意,left不一定与right相等,bottom不一定与top相等,near与far不相等。参数:

​ left、right:指定近裁剪面的左边界和右边界

​ bottom、top:指定近裁剪面的上边界和下边界

​ near、far:指定近裁剪面和远裁剪面的位置,即可视空间的近边界和远边界

setPerspective(fov, aspect, near, far)

​ 通过各参数计算透视投影矩阵,将其存储在Matrix4中。注意,near的值必须小于far。参数:

​ fov:指定垂直视角,即可视空间顶面和底面键的夹角,必须大于0

​ aspect:指定近裁剪面的高宽比(宽度/高度)

​ near、far:指定近裁剪面和远裁剪面的位置,即可视空间的近边界和远边界(near和far必须都大于0)

​ 注意,第二个参数aspect是近裁剪面的宽高比,而不是水平视角(第一个参数是垂直视角)。比如说,如果近裁剪面的高度100和宽度200,那么宽高比为2。

setInverseOf (m)

​ 使自身称为矩阵m的逆矩阵。

transpose()

​ 对自身进行转置操作,并将自身设为转置后的结果。

实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>rotate triangle</title>
</head>
<body onload="main()">
<canvas id="webgl" width="400" height="400">
Please use the browser supporting "canvas".
</canvas>

<script src="../lib/webgl-utils.js"></script>
<script src="../lib/webgl-debug.js"></script>
<script src="../lib/cuon-utils.js"></script>
<script src="../lib/cuon-matrix.js"></script>
<script src="RotatedTriangle_Matrix4.js"></script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 缓冲区对象向着色器传入多个顶点的数据
function initVertexBuffers(gl) {
var vertices = new Float32Array(
[0.0, 0.5, -0.5, -0.5, 0.5, -0.5]
);
var n=3; //点的个数

//创建缓冲区对象
var vertexBuffer = gl.createBuffer();
if(!vertexBuffer){
console.log("Failed to create thie buffer object");
return -1;
}

//将缓冲区对象保存到目标上
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);

//向缓存对象写入数据
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if(a_Position < 0){
console.log("Failed to get the storage location of a_Position");
return -1;
}

//将缓冲区对象分配给a_Postion变量
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);

//连接a_Postion变量与分配给它的缓冲区对象
gl.enableVertexAttribArray(a_Position);

return n;
}
旋转矩阵
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// 变换矩阵旋转
var VSHADER_SOURCE =
//x' = x cos b - y sin b
//y' = x sin b + y cosb
//z' = z
'attribute vec4 a_Position;\n' +
'uniform mat4 u_xformMatrix;\n' +
'void main() {\n' +
'gl_Position = u_xformMatrix * a_Position;\n' +
'}\n';

var FSHADER_SOURCE=
'void main(){'+
'gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);'+
'}';

var ANGLE = 90.0;

function main(){

var canvas = document.getElementById("webgl");
if(!canvas){
console.log("Failed to retrieve the <canvas> element");
return;
}

var gl = getWebGLContext(canvas);
if(!gl){
console.log("Failed to get the rendering context for WebGL");
return;
}

if(!initShaders(gl,VSHADER_SOURCE,FSHADER_SOURCE)){
console.log("Failed to initialize shaders.");
return;
}

//设置顶点位置
var n = initVertexBuffers(gl);
if (n < 0) {
console.log('Failed to set the positions of the vertices');
return;
}
// 为旋转矩阵创建Matrix4对象
var xformMatrix = new Matrix4();
// 将xformMatrix设置为旋转矩阵
xformMatrix.setRotate(ANGLE, 0, 0, 1);

var u_xformMatrix = gl.getUniformLocation(gl.program, 'u_xformMatrix');
if(u_xformMatrix < 0){
console.log("Failed to get the storage location of u_xformMatrix");
return;
}
// 将旋转矩阵传输给顶点着色器
gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix.elements);

gl.clearColor(0.0, 0.0, 0.0, 1.0);

gl.clear(gl.COLOR_BUFFER_BIT);

gl.drawArrays(gl.TRIANGLES, 0, n);
}
平移矩阵
1
2
// 将上例第47行改为如下内容:
xformMatrix.setTranslate(0.5, 0.5, 0.0);
缩放矩阵
1
2
// 同理修改47行为:
xformMatrix.setScale(0.5, 1.5, 1.0);

效果

实现效果与上一节相同(【WebGL之巅】11-使用Matrix变换矩阵实现三角形旋转、平移、缩放


Tips: Please indicate the source and original author when reprinting or quoting this article.