構建orthographic正投影矩陣

參考:《Webgl Programe Guide》
參考:http://eux.baidu.com/blog/fe/832
(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)

生成正投影的矩陣是相對比較好理解的一個矩陣,整理對它的推理過程的理解,另外最下面有js的代碼實現,參考自: webgl programe guide

預置條件

預置條件,正投影的視口範圍:
left=-30, righ=30, bottom=-20, top=20, near = 0, far = 10

// Specify the viewing volume
projMatrix.setOrtho(-30.0, 30.0, -20.0, 20.0, 0, 10);

場景分析

  1. 投影矩陣的使用位於視圖矩陣之後,視圖矩陣處理後的結果是:相機位置位於(0,0,0)位置,相機朝向-z軸,相機的上方向爲+y軸,右方向爲+x軸。
  2. 我們已知, OpenGL投影后的屏幕Clip Space可見座標保留範圍是(-1,-1,-1)—(1,1,1), 取值範圍外的會被認爲超出屏幕範圍, 不會展示到屏幕上,也就是看不見了。
  3. 另外正投影的效果是,定義一個長方體範圍,該範圍內的可見,輸出到屏幕中。

實現

綜合上面的點,我們需要把長方體的範圍影和可見範圍對應,讓長方體的範圍正好是可見範圍,從而達到屏幕上展示範圍爲長方體範圍,達成正投影的設置範圍效果。

1. SCALE變換:

要做到該點,首先長方體的left-right需要影射到範圍(-1,1), bottom-top需要影射到範圍(-1,1),near-far也需要影射到-1,1範圍中;
所以需要先使用縮放矩陣進行處理:
z軸和x/y軸不同,z軸可見範圍都在負軸上,但我們習慣所使用都是正值,把-z軸做爲相機正向,所以多一個負號來首先修正。
如下圖示:
在這裏插入圖片描述

2. 位移變換:

經過scale處理之後, x/y座標系上:

  1. x軸在(right-left)/2的對稱範圍內取值(-1,1);

  2. y軸在(top-bottom)/2對稱範圍內取值(-1,1)

  3. z軸在以z=0點的對稱範圍(far-near)/2內取值(1,-1),相機方向前(-z方向)的爲正值,相機後(+z方向)的爲負值。

  4. x/y軸考慮abs(right)與abs(left),abs(top)與abs(bottom)不一定相等,所以取值範圍可能會有偏差;絕對值相等時不需要修正,不相等時需要修正。
     修正時,採用影射後中心點的偏差量對值進行修正。
     對於x軸,(right+left)/2是原來的中心點,乘映射係數 2/(right-left),影射後就是(right+left)/(right-left),把該值作爲修正量從x中減掉;
     所以x軸修正量是:-(right+left)/(right-left)
    同理y軸修正量是:-(top+bottom)/(top-bottom)

  5. z軸是一定需要修正的,z=0之後是作爲相機後面的,肯定是不能被看見的,可見的範圍需要調整到在(-far, -near)之間,也就是對稱中心移到範圍中心去
     所以同x,y軸的修正算法一樣,把(-far, -near)中心點與原點的偏差減去掉。
     對於z軸,(-far + (-near))/2是原範圍的中心點,乘影射係數-2/(far-near),映射後是(far+near)/(far-near),把該值作爲修正量從z中減去掉;
     所以z軸修正量是:-(far+near)/(far-near)

  6. z軸演算以下,最開始的例子裏far=10, near=0,帶入公式;
    使用z=0, 計算影射值 0 * -2/(far-near) +(-(far+near)/(far-near)) = 0 * -2/10 -1 = -1
     使用z=-10,計算影射值 -10 * -2/(far-near) +(-(far+near)/(far-near)) = -10 * -2 / 10 - 1 = 1
     可以看出,可見範圍near=0(z=0)映射到-1,far=10(z=-10)映射到1,near->far被影射到了(-1,1)的範圍內

3. 與Direct3D不同:

爲什麼會與Direct3D不同呢,因爲ClipSpace的不一致,Direct3D使用的z的空間範圍是(0,1)

所以變換時,對於z的變換就很不一樣了,只需要把可見的z範圍變換到(0,1)空間即可。
scale時把near,far長度影射到(0,1)的範圍內,再把near的位置進行偏移修正,最終表達(0,1)範圍。
在這裏插入圖片描述

webgl代碼實現

參考自: webgl programe guide

/**
 * Set the orthographic projection matrix.
 * @param left The coordinate of the left of clipping plane.
 * @param right The coordinate of the right of clipping plane.
 * @param bottom The coordinate of the bottom of clipping plane.
 * @param top The coordinate of the top top clipping plane.
 * @param near The distances to the nearer depth clipping plane. This value is minus if the plane is to be behind the viewer.
 * @param far The distances to the farther depth clipping plane. This value is minus if the plane is to be behind the viewer.
 * @return this
 */
Matrix4.prototype.setOrtho = function(left, right, bottom, top, near, far) {
  var e, rw, rh, rd;

  if (left === right || bottom === top || near === far) {
    throw 'null frustum';
  }

  rw = 1 / (right - left);
  rh = 1 / (top - bottom);
  rd = 1 / (far - near);

  e = this.elements;

  e[0]  = 2 * rw;
  e[1]  = 0;
  e[2]  = 0;
  e[3]  = 0;

  e[4]  = 0;
  e[5]  = 2 * rh;
  e[6]  = 0;
  e[7]  = 0;

  e[8]  = 0;
  e[9]  = 0;
  e[10] = -2 * rd;
  e[11] = 0;

  e[12] = -(right + left) * rw;
  e[13] = -(top + bottom) * rh;
  e[14] = -(far + near) * rd;
  e[15] = 1;

  return this;
};

(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章