在上一篇中咱們已經實現了使用webgl繪製圖形這個小目標《前端圖形學從入門到放棄》001 畫一個三角形
今天咱們來探討一個新的話題矩陣
咱們都知道空間中的點咱們能夠用向量表示,例如二維平面中的點(1,1)就表示第一象限的點:
而多個點就能組成圖形,這也是上一篇文章中咱們說過的。
實際生產中這些圖形每每並不會固定在畫面中不懂,例如咱們能夠對圖形進行旋轉,縮放,移動。
實際上這個過程就是將圖形的頂點組進行了旋轉,縮放,移動,成爲了新的頂點組,再由新的頂點組繪製成新的圖形。html
例如咱們要將由點A(0,0),B(1,0),C(0,1)組成的三角形放大一倍,那麼咱們很容易知道放大後的點ÂḂĆ的座標前端
Âx = Ax 2 = 02 = 0
Ây = Ay 2 = 02 = 0
Ḃx = Bx 2 = 12 = 2
Ḃy = By 2 = 02 = 0
Ćx = Cx 2 = 02 = 0
Ćy = Cy 2 = 12 = 2
數學家嫌這一番操做太過麻煩,而點又是能夠寫成向量形式的,要是能把操做簡化成Â = M*A的形式就再好不過了,因而web
⎡ 2 0 ⎤ Â = ⎪ ⎪ * A ⎣ 0 2 ⎦
真是一頓操做猛如虎,一句不懂二百五canvas
舉證表明了一種計算,如上咱們使用了一個二維矩陣segmentfault
⎡ 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的視頻。oop
而上文咱們看到的矩陣webgl
⎡ 2 0 ⎤ ⎣ 0 2 ⎦
就是一個把任意點放大兩倍的矩陣,更通常的,若是能夠寫出縮放矩陣(n≠0)spa
⎡ n 0 ⎤ ⎡x⎤ = ⎡ n*x ⎤ ⎣ 0 n ⎦ ⎣y⎦ ⎣ n*y ⎦
相比於縮放還有一種操做也很高頻,那就是旋轉。前面沒有提到,矩陣的變換是線性的。什麼叫作線性?也是是說一樣的操做(放大2倍)對A點產生的效果,和對B點產生的效果(放大2倍)是同樣的。
因此對於旋轉矩陣咱們也能夠找到特殊的點進行求解,從而獲得廣泛適用的矩陣
對於x軸上的點a,旋轉ø角後,能夠用下圖描述
咱們就獲得了二維平面上的旋轉矩陣code
⎡ cosø -sinø ⎤ ⎣ sinø cosø ⎦
下面咱們把矩陣和webgl結合起來,讓《前端圖形學從入門到放棄》001 畫一個三角形中咱們實現的三角形能夠旋轉與縮放
首先咱們在頁面上添加兩個滑塊分辨實現旋轉與縮放
<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>
這兩個申明的變量也要在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)
此時就能夠實現平移
根據上文,咱們已經瞭解的矩陣知識,不難寫出
而這種經過n+1維實現了n維線性變換外加移動操做的變換,就被稱爲齊次變換
。
下面咱們繼續改造原有的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); ....
大功告成:
我想二維的世界,你們也膩了,下篇咱們將進入三維世界,並說說光線是如何影響物體的