正交投影矩阵
通过相机世界将现实世界投射到裁剪空间中的矩阵 --- 不同深度的物体不具备近大远小的透视规则。
思路过程
裁剪空间:裁剪空间是用于显示webgl图形的空间,以画布中心为原点,宽高深都为2的正方体盒子,当图像范围超过裁剪空间(大于1或小于-1)时,图像就会不显示了。
正交投影矩阵的建立需要(left, right, top, bottom, near, far)一个已知左右,上下,近裁剪面远裁剪面的矩形盒子。
正交投影就是将现实的世界投影到裁剪空间中
裁剪空间的总长度、宽度、深度都是2,现实世界是自己定义的,我们只需要按照一定的比例去缩放
将现实世界投影到裁剪空间中的比例如下 裁剪空间中的right减去left(1 - (-1))比现实世界的 right减去left 可以计算出现实世界与裁剪空间的比值
const w = (1.0 - (-1.0)) / ( right - left ) = 2 / ( right - left )
const h = (1.0 - (-1.0)) / ( top - bottom ) = 2 / ( top - bottom )
const p = (1.0 - (-1.0)) / ( far - near ) = 2 / ( far - near )
现实世界在裁剪空间中的位移量如下 (裁剪空间中的位移量 加 裁剪空间中坐标原点(中心点)的值) 乘 此方向上的缩放比例
const x = (( right - left )/2 +left) * w
const y = (( top - bottom )/2 +bottom) * h
const z = (( far - near )/2 +near) * p
这样就可以得到投影矩阵了
te[ 0 ] = w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x;
te[ 1 ] = 0; te[ 5 ] = h; te[ 9 ] = 0; te[ 13 ] = - y;
te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = -p; te[ 14 ] = - z;
te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1;
源码
makeOrthographic( left, right, top, bottom, near, far ) {
const te = this.elements;
const w = 1.0 / ( right - left );
const h = 1.0 / ( top - bottom );
const p = 1.0 / ( far - near );
const x = ( right + left ) * w;
const y = ( top + bottom ) * h;
const z = ( far + near ) * p;
te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x;
te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y;
te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = - 2 * p; te[ 14 ] = - z;
te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1;
return this;
}
比较计算结果
{
const projectionMatrix = new Matrix4()
projectionMatrix.makeOrthographic( -3, 3, 4, -4, -2, 2)
console.log(projectionMatrix.elements);
//[0.3333333333333333, 0, 0, 0, 0, 0.25, 0, 0, 0, 0, -0.5, 0, -0, -0, -0, 1]
}
{
makeOrthographic(-3, 3, 4, -4, -2, 2)
function makeOrthographic(left, right, top, bottom, near, far ) {
const w = 2 / ( right - left )
const h = 2 / ( top - bottom )
const p = 2 / ( far - near )
const x = (( right - left )/2 +left) * w
const y = (( top - bottom )/2 +bottom) * h
const z = (( far - near )/2 +near) * p
const te = [];
te[ 0 ] = w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x;
te[ 1 ] = 0; te[ 5 ] = h; te[ 9 ] = 0; te[ 13 ] = - y;
te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = -p; te[ 14 ] = - z;
te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1;
console.log(te);
//[0.3333333333333333, 0, 0, 0, 0, 0.25, 0, 0, 0, 0, -0.5, 0, -0, -0, -0, 1]
}
}
结果与源码中稍有偏差,但是不难发现其中计算结果是一样的
// 上述推导
{
const w = 2 / ( right - left )
const h = 2 / ( top - bottom )
const p = 2 / ( far - near )
const x = (( right - left )/2 +left) * w
const y = (( top - bottom )/2 +bottom) * h
const z = (( far - near )/2 +near) * p
}
// 源码
{
// 当缩放比例中裁剪空间宽高深为1时
// 化简完就和源码中一样了,在矩阵中写入缩放值([0]、[5]、[10])时要乘2
const w = 1 / ( right - left )
const h = 1 / ( top - bottom )
const p = 1 / ( far - near )
const x = (( right - left )/2 +left) * 2w
// (( right - left ) + 2left) * w
// ( right + left ) * w
const y = (( top - bottom )/2 +bottom) * 2h
// ( top - bottom + 2bottom) * h
// ( top + bottom ) * h
const z = (( far - near )/2 +near) * 2p
// ( far - near + 2near) * p
// ( far + near ) * p;
}
\