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

## 本文大纲

• 矩阵和线性变换是什么？
• webgl如何实现缩放和旋转？
• 平移不是线性变换，那该怎么办？
• webgl如何实现平移？

## 今天的主菜是“矩阵”

Âx = Ax2 = 02 = 0
Ây = Ay2 = 02 = 0
Ḃx = Bx2 = 12 = 2
Ḃy = By2 = 02 = 0
Ćx = Cx2 = 02 = 0
Ćy = Cy2 = 12 = 2

``````    ⎡ 2  0 ⎤
Â = ⎪      ⎪ * A
⎣ 0  2 ⎦  ``````

## 解剖矩阵

``````    ⎡ A  B ⎤
⎣ C  D ⎦  ``````

``````    ⎡ A  B ⎤  ⎡x⎤  =   ⎡ A*x + B*y ⎤
⎣ C  D ⎦  ⎣y⎦      ⎣ C*x + D*y ⎦``````

### 缩放矩阵 与 旋转矩阵

``````    ⎡ 2  0 ⎤
⎣ 0  2 ⎦  ``````

``````    ⎡ n  0 ⎤  ⎡x⎤  =   ⎡ n*x ⎤
⎣ 0  n ⎦  ⎣y⎦      ⎣ n*y ⎦``````

``````    ⎡ cosø  -sinø ⎤
⎣ sinø   cosø ⎦  ``````

## webgl和矩阵更配哟～

``````<canvas id="canvas" width="1000" height="1000"></canvas>
<div id="control">
<input type="range" value=".75" min=".5" max="1" step="0.01" id="scale" value="0">
<input type="range" value="0" min="0" max="360" step="0.01" id="rotate" value="0">
</div>``````

``````<script id="vertex-shader-2d" type="notjs">
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);
}

</script>``````

``````...
var positionAttribLocation = gl.getAttribLocation(program, 'vertPosition');
var colorAttribLocation = gl.getAttribLocation(program, 'vertColor');
var scaleMatrix = gl.getUniformLocation(program, 'scaleMatrix');
var rotateMatrix = gl.getUniformLocation(program, 'rotateMatrix');
...``````

``````....
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);
}``````

## 教练我动不了了

### webgl和齐次变换更配哟～

``````<div id="control">
...
<input type="range" value="0" min="-0.5" max="0.5" step="0.01" id="tranX">
<input type="range" value="0" min="-.5" max=".5" step="0.01" id="tranY">
</div>``````

``````<script id="vertex-shader-2d" type="notjs">
...
// 将原本二维矩阵定义为三维
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);
}

</script>``````

``````...
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);
....``````