在電腦上看到圖形的方式,通常是透過 camera 的概念。可以想像人的眼睛(或螢幕)就是一台相機的鏡頭,我們透過調整鏡頭的遠近跟位置來成像。而成像的方式通常會透過矩陣來轉換,為了方便說明,以下只列舉幾個實務上較常使用到的矩陣。
為了方便計算矩陣,我們使用到 gl-matrix.js
這個函式庫來簡化我們的矩陣計算。
一個正方體裡頭會有 8 個點。所以我們修改 createPoints
這個函數為 8 個頂點,
var vertices = [
-1, -1, -1, 1, 0, 0, 1, // 0
1, -1, -1, 1, 1, 0, 1, // 1
-1, 1, -1, 0, 1, 1, 1, // 2
1, 1, -1, 0, 0, 1, 1, // 3
-1, 1, 1, 1, 0.5, 0, 1, // 4
1, 1, 1, 0.5, 1, 1, 1, // 5
-1, -1, 1, 1, 0, 0.5, 1, // 6
1, -1, 1, 0.5, 0, 1, 1, // 7
];
前三個點代表座標,後面四個點則是代表顏色。我們要做的事情是將這 8 個點送給 GPU 繪製,同時也將顏色的資訊傳給 webGL。
如果只是單純修改頂點,你會發現畫出來的正方體只有三個邊。因為gl.TRANGLE_STRIP
的關係,所以我們每次的繪製,都會利用到前面兩個點,所以有兩個點沒有被繪製到。如果想要達成正方體的效果,我們必須要再加入兩個重複的點座標。
這顯然有點不合理。所以這邊我們使用 gl.drawElements
來取代 gl.drawArrays
。drawElements 的不同點在於,你可以自己選擇要繪製的頂點數量和開始位置(index)。
所以接下來要做的事情就是建立一個繪製頂點的 index array,讓 webGL 如何重複使用這些頂點位置。
function createIndices() {
// 建立索引,讓 webGL 知道要取用哪些頂點
var indices = [
0, 1, 2, 1, 2, 3,
2, 3, 4, 3, 4, 5,
4, 5, 6, 5, 6, 7,
6, 7, 0, 7, 0, 1,
0, 2, 6, 2, 6, 4,
1, 3, 7, 3, 7, 5
];
indexCount = indices.length;
var indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array(indices), gl.STATIC_DRAW);
}
同時,我們也修改了 createVertices 裡頭的傳值方式
// 原本為 gl.vertexAttribPointer(coord, 3, gl.FLOAT, false, 0, 0);
// 第五個參數代表每次取用頂點後,下一次的頂點從哪裡開始 Float32Array.BYTES_PER_ELEMENT * 7
gl.vertexAttribPointer(coords, 3, gl.FLOAT, false, Float32Array.BYTES_PER_ELEMENT * 7, 0);
gl.enableVertexAttribArray(coords);
通常我們在使用 3D 動畫效果時,我們會採用矩陣轉換的方式。我不想太深入數學理論,以下是動畫中常用的矩陣:
縮放:其中 Sx, Sy, Sz 代表縮放係數
旋轉:對 x, y, z 做 cos sin 運算,舉例:(對 x, y)坐旋轉。以此類推
在 javascript 當中並沒有矩陣運算的功能,只能用陣列的方式來做到,所以這邊為了簡化大量的運算,我們引入了 gl-matrix.js
當作我們的範例,在 html 加入
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.3.2/gl-matrix-min.js"></script>
以上是較粗淺的矩陣轉換介紹,之後的範例當中如果有機會再和各位詳細說明。
uniform mat4 u_transformMatrix;
uniform mat4 u_perspectiveMatrix;
void main(void) {
gl_Position = perspectiveMatrix * transformMatrix * coords;
gl_PointSize = pointSize;
varyingColors = colors;
}
在 vertex shader 當中,我們加入兩個變數 transformMatrix 及 perspectiveMatrix,讓 javascript 傳值進入。一般矩陣的相乘在 GSGL 中直接用 *
表示即可。
在 draw function 中加入:
mat4.rotateX(matrix, matrix, -0.043); // 每次旋轉 X -0.043
mat4.rotateY(matrix, matrix, 0.01); // 每次旋轉 0.01
mat4.rotateZ(matrix, matrix, 0.01); // 每次旋轉 0.01
var transformMatrix = gl.getUniformLocation(shaderProgram, "transformMatrix");
gl.uniformMatrix4fv(transformMatrix, false, matrix);
還是要提醒一下,在 webGL 的座標系統當中,只有 -1 ~ 1
最後,就可以看到成果啦!
到目前為止,我們已經學習了不少 webGL 的 API 跟運作方式,明天會介紹 webGL 中蠻重要的功能 - sampler(採樣器),並且將我們目前所學的知識做一些應用來當作 webGL 的結尾。之後就可以進入高階一點的世界 - Three.js 了。