學習WebGL之透視和正交投影

本系列所有文章目錄

上一篇介紹了變換矩陣,本篇將介紹兩個重要的變換矩陣,透視投影矩陣和正交投影矩陣,可以前往我的博客查看代碼演示。

基本概念

透視投影矩陣

主要作用是模仿人眼觀察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 farZfovyRadians表示視角。aspect表示屏幕寬高比,為了將所有軸的單位長度統一,所以需要知道屏幕寬高比多少。nearZ表示可視范圍在Z軸的起點到原點(0,0,0)的距離,farZ表示可視范圍在Z軸的終點到原點(0,0,0)的距離,nearZfarZ始終為正。下面是透視投影的剖面示意圖。

透視投影矩陣默認的可視方向是向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渲染的世界了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容