上一篇介紹了變換矩陣,本篇將介紹兩個重要的變換矩陣,透視投影矩陣和正交投影矩陣,可以前往我的博客查看代碼演示。
基本概念
透視投影矩陣
主要作用是模仿人眼觀察3D世界的規律,讓物體近大遠小,所以被稱為透視。
正交投影矩陣
主要作用是將坐標系映射到其他大小,主要用于2D UI繪制。
接下來我們就結合代碼和效果深入了解這兩個矩陣。我沿用了上一篇的代碼,在渲染代碼出根據當前選擇的投影矩陣currentProjectionMatrix
使用透視或者正交投影,并配合一些平移,旋轉實現本例的效果。triangleBuffer
中修改了頂點數據,將繪制的三角形改成了矩形,方便觀察效果。同時記的把繪制的代碼頂點數改成6,gl.drawArrays(gl.TRIANGLES, 0, 6);
。
window.onWebGLRender = function render(deltaTime, elapesdTime) {
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(1.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
...
var rotateMatrix = mat4.create();
mat4.rotate(rotateMatrix, rotateMatrix, elapesdTime / 1000.0, vec3.fromValues(0, 1, 0));
var translateMatrix = mat4.create();
mat4.translate(translateMatrix, translateMatrix, vec3.fromValues(0, 0, -1));
var transform = mat4.create();
mat4.multiply(transform, translateMatrix, rotateMatrix);
mat4.multiply(transform, currentProjectionMatrix, transform);
transformUniformLoc = gl.getUniformLocation(program, 'transform');
gl.uniformMatrix4fv(transformUniformLoc, false, transform);
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
function makeBuffer() {
var triangle = [
-0.5, 0.5, 0.0,
-0.5, -0.5, 0.0,
0.5, -0.5, 0.0,
-0.5, 0.5, 0.0,
0.5, -0.5, 0.0,
0.5, 0.5, 0.0,
];
buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangle), gl.STATIC_DRAW);
return buffer;
}
透視投影
這是構建透視投影矩陣的代碼。
perspectiveProjectionMatrix = mat4.create();
mat4.perspective(perspectiveProjectionMatrix, 80 / 180.0 * Math.PI, canvas.width / canvas.height, 0.1, 1000);
perspective
方法有4個參數float fovyRadians, float aspect, float nearZ, float farZ
。fovyRadians
表示視角。aspect
表示屏幕寬高比,為了將所有軸的單位長度統一,所以需要知道屏幕寬高比多少。nearZ
表示可視范圍在Z軸的起點到原點(0,0,0)的距離,farZ
表示可視范圍在Z軸的終點到原點(0,0,0)的距離,nearZ
和farZ
始終為正。下面是透視投影的剖面示意圖。
透視投影矩陣默認的可視方向是向Z軸的反方向生長的。視角(fovyRadians)越大,看到的東西就越多。只有在nearZ和farZ兩個平面范圍內的點才會被投影到屏幕上,當然這些點也必須在視角的范圍內。根據上面的條件,一個位于z=0上的點是不能被投影到屏幕的,所以我在渲染時增加了一個平移矩陣mat4.translate(translateMatrix, translateMatrix, vec3.fromValues(0, 0, -1));
,為了演示近大遠小的視覺效果,我又增加了旋轉矩陣mat4.rotate(rotateMatrix, rotateMatrix, elapesdTime / 1000.0, vec3.fromValues(0, 1, 0));
。最后將 perspectiveMatrix * translateMatrix * rotateMatrix
的結果賦值給Vertex Shader中的transform。
如果讀者還記得上一篇提到的矩陣運算的話,就應該知道perspectiveMatrix * translateMatrix * rotateMatrix
代表著先旋轉再平移最后執行透視投影。這是以后所有3D變換操作的基本順序,投影必須放在最后。透視投影的效果如下。
正交投影
構建矩陣的代碼如下
orthoProjectionMatrix = mat4.create();
mat4.ortho(orthoProjectionMatrix, -0.8, 0.8, -0.8, 0.8, -100, 100);
正交投影其實比較好理解,原先屏幕的X軸從左到右是-1到1,Y軸從上到下是1到-1,經過mat4.ortho(orthoProjectionMatrix, -0.8, 0.8, -0.8, 0.8, -100, 100);
正交矩陣的變換,就會變成X軸從左到右是-0.8到0.8,Y軸從上到下是0.8到-0.8。正交投影里的nearZ和farZ代表可視的Z軸范圍,超出的點就不可見了。代碼效果如下。
矩陣切換
例子通過select元素切換投影效果。根據不同的選擇,currentProjectionMatrix
會賦予不同的投影矩陣值,然后在渲染代碼中直接使用。
function setupProjectionMatrixSelect() {
currentProjectionMatrix = perspectiveProjectionMatrix;
currentBuffer = triangleBuffer;
var selectNode = document.getElementById("projectionModeSelect");
selectNode.onchange = function (evt) {
switch (evt.target.value) {
case 'perspective':
currentProjectionMatrix = perspectiveProjectionMatrix;
break;
case 'ortho':
currentProjectionMatrix = orthoProjectionMatrix;
break;
}
}
}
本篇主要介紹了WebGL中的兩個重要投影矩陣,掌握好它們對于后面更深入的學習3D和2D渲染有著非常重要的作用。
下一篇會講解攝像機,作為3D渲染中最基本的三大矩陣MVP之一,學習完之后就可以正式踏入3D渲染的世界了。