html5从入门到放弃,《前端图形学从入门到放弃》002 教练我想学矩阵

本文大纲矩阵和线性变换是什么?

webgl如何实现缩放和旋转?

平移不是线性变换,那该怎么办?

webgl如何实现平移?

今天的主菜是“矩阵”

在上一篇中我们已经实现了使用webgl绘制图形这个小目标《前端图形学从入门到放弃》001 画一个三角形

今天我们来探讨一个新的话题矩阵

我们都知道空间中的点我们可以用向量表示,例如二维平面中的点(1,1)就表示第一象限的点:

html5从入门到放弃,《前端图形学从入门到放弃》002 教练我想学矩阵_第1张图片

而多个点就能组成图形,这也是上一篇文章中我们说过的。

实际生产中这些图形往往并不会固定在画面中不懂,例如我们可以对图形进行旋转,缩放,移动。

实际上这个过程就是将图形的顶点组进行了旋转,缩放,移动,成为了新的顶点组,再由新的顶点组绘制成新的图形。

例如我们要将由点A(0,0),B(1,0),C(0,1)组成的三角形放大一倍,那么我们很容易知道放大后的点ÂḂĆ的坐标Âx = Ax2 = 02 = 0

Ây = Ay2 = 02 = 0

Ḃx = Bx2 = 12 = 2

Ḃy = By2 = 02 = 0

Ćx = Cx2 = 02 = 0

Ćy = Cy2 = 12 = 2

数学家嫌这一番操作太过麻烦,而点又是可以写成向量形式的,要是能把操作简化成Â = M*A的形式就再好不过了,于是⎡ 2 0 ⎤

 = ⎪ ⎪ * A

⎣ 0 2 ⎦

真是一顿操作猛如虎,一句不懂二百五

解剖矩阵

举证代表了一种计算,如上我们使用了一个二维矩阵⎡ A B ⎤

⎣ C D ⎦

与一个二维向量相乘,会得到一个新的二维向量,计算公式如下⎡ A B ⎤ ⎡x⎤ = ⎡ A*x + B*y ⎤

⎣ C D ⎦ ⎣y⎦ ⎣ C*x + D*y ⎦

当然矩阵也不仅仅可以和向量相乘也可以和举证相乘,矩阵也不仅仅可以是22,也可以是33,更可以是n*m(n代表行数,m代表列数)。

两个矩阵可以相乘只需要,前一个矩阵的列数和后一个矩阵的函数相等即可。

例如nm的举证可以和ml的矩阵相乘,得到n*l的矩阵。

至于计算方法不是本文讨论的内容,推荐观看3blue1brown的视频。

缩放矩阵 与 旋转矩阵

而上文我们看到的矩阵⎡ 2 0 ⎤

⎣ 0 2 ⎦

就是一个把任意点放大两倍的矩阵,更一般的,如果可以写出缩放矩阵(n≠0)⎡ n 0 ⎤ ⎡x⎤ = ⎡ n*x ⎤

⎣ 0 n ⎦ ⎣y⎦ ⎣ n*y ⎦

相比于缩放还有一种操作也很高频,那就是旋转。前面没有提到,矩阵的变换是线性的。什么叫做线性?也是是说同样的操作(放大2倍)对A点产生的效果,和对B点产生的效果(放大2倍)是一样的。

所以对于旋转矩阵我们也可以找到特殊的点进行求解,从而得到普遍适用的矩阵

对于x轴上的点a,旋转ø角后,可以用下图描述

html5从入门到放弃,《前端图形学从入门到放弃》002 教练我想学矩阵_第2张图片

我们就得到了二维平面上的旋转矩阵⎡ cosø -sinø ⎤

⎣ sinø cosø ⎦

webgl和矩阵更配哟~

下面我们把矩阵和webgl结合起来,让《前端图形学从入门到放弃》001 画一个三角形中我们实现的三角形可以旋转与缩放

首先我们在页面上添加两个滑块分辨实现旋转与缩放

由于旋转和缩放操作仅仅影响顶点位置,下面我们之需要修改顶点着色器即可:

attribute vec2 vertPosition;

attribute vec3 vertColor;

varying vec3 fragColor;

// 额外申明两个矩阵用于旋转和缩放

uniform mat2 scaleMatrix;

uniform mat2 rotateMatrix;

void main() {

fragColor = vertColor;

// 把顶点坐标与矩阵相乘,得到旋转和缩放后的新顶点,传给gl

gl_Position = vec4(scaleMatrix*rotateMatrix*vertPosition,0.0,1.0);

}

这两个申明的变量也要在js中取出...

var positionAttribLocation = gl.getAttribLocation(program, 'vertPosition');

var colorAttribLocation = gl.getAttribLocation(program, 'vertColor');

var scaleMatrix = gl.getUniformLocation(program, 'scaleMatrix');

var rotateMatrix = gl.getUniformLocation(program, 'rotateMatrix');

...

由于我们期望在滑动滑块时,页面实时变化,因此需要一个loop函数来完成这一切:....

gl.useProgram(program);

gl.drawArrays(gl.TRIANGLES, 0, 6);

loop(gl, rotateMatrix, scaleMatrix);

}

...

loop函数:var scaleNode = document.querySelector("#scale");

var rotateNode = document.querySelector("#rotate");

function loop(gl, rotateMatrix, scaleMatrix) {

var angle = rotateNode.value/180*Math.PI;

var scale = scaleNode.value;

var sin = Math.sin(angle);//旋转角度正弦值

var cos = Math.cos(angle);//旋转角度余弦值

var myArr = new Float32Array([cos, -sin, sin, cos,]);

var scaleArr = new Float32Array([scale, 0, 0, scale,]);

gl.uniformMatrix2fv(rotateMatrix, false, myArr);

gl.uniformMatrix2fv(scaleMatrix, false, scaleArr);

gl.clearColor(0.75, 0.85, 0.8, 1.0);

gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

requestAnimationFrame(function () {

loop(gl, rotateMatrix, scaleMatrix);

});

gl.drawArrays(gl.TRIANGLES, 0, 3);

}

大功告成:

教练我动不了了

不知道各位看官有没有发现,在矩阵这套线性变化下,我们没办法做平移操作。因为作为原点的o(0,0)不论乘以什么矩阵,结果都还是自己。但是平移操作是日常工作中极其常见的操作,不能平移甚至无法实现拖拽!

难道图形学之路就此gg?

但天无绝人之路,只要零点不是零点我就可以移动它,对于二维平面,我可以把它看作三维世界中一个不过原点的平面,原本的(x,y)变为(x,y,1)

此时就可以实现平移

html5从入门到放弃,《前端图形学从入门到放弃》002 教练我想学矩阵_第3张图片

根据上文,我们已经了解的矩阵知识,不难写出

html5从入门到放弃,《前端图形学从入门到放弃》002 教练我想学矩阵_第4张图片

而这种通过n+1维实现了n维线性变换外加移动操作的变换,就被称为齐次变换。

webgl和齐次变换更配哟~

下面我们继续改造原有的webgl代码!

首先我们还需要加入两个滑块分别控制,图形上下和左右运动

...

由于齐次变换将所有的矩阵都升维了,我们需要改造定点着色器。

...

// 将原本二维矩阵定义为三维

uniform mat3 scaleMatrix;

uniform mat3 rotateMatrix;

uniform mat3 transformMatrix;

void main() {

fragColor = vertColor;

vec3 v = rotateMatrix*scaleMatrix*transformMatrix*vec3(vertPosition,1.0);

// 由于我们之需要x,y把他们取出即可

gl_Position = vec4(v.xy,0.0,1.0);

}

由于矩阵从二维变为三维,取出的变量也需要重新定义为三维:...

var trMatrix = gl.getUniformLocation(program,'transformMatrix');

var scaleMatrix = gl.getUniformLocation(program, 'scaleMatrix');

var rotateMatrix = gl.getUniformLocation(program, 'rotateMatrix');

...

// 获取滑块

var tranXNode = document.querySelector("#tranX");

var tranYNode = document.querySelector("#tranY");

// 修改loop函数

...

loop(gl, rotateMatrix, scaleMatrix,trMatrix);

}

function loop(gl, rotateMatrix, scaleMatrix,trMatrix) {

...

var myArr = new Float32Array([cos, -sin, 0 , sin, cos, 0,0,0,1]);

var scaleArr = new Float32Array([scale, 0, 0,0, scale,0,0,0,1]);

var tranArr = new Float32Array([1,0,0,0,1,0,tranXNode.value,tranYNode.value,1]);

// console.log(tranXNode.value);

gl.uniformMatrix3fv(rotateMatrix, false, myArr);

gl.uniformMatrix3fv(scaleMatrix, false, scaleArr);

gl.uniformMatrix3fv(trMatrix, false, tranArr);

....

大功告成:

下期预告

我想二维的世界,大家也腻了,下篇我们将进入三维世界,并说说光线是如何影响物体的

b739ec46bb5c46d9c0aa4ce35ba1ea56.png

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[《前端图形学从入门到放弃》002 教练我想学矩阵]http://www.zyiz.net/tech/detail-145775.html

你可能感兴趣的:(html5从入门到放弃)