构建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)

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