最近看闫令琪老师的 现代计算机图形学入门,按照自己的理解也推导了一下透视投影变换矩阵,这里选用右手坐标系,列向量。
首先推导正交投影
我们通常在摄影机中给定[l, r], [b, t], [n, f], n和f都是大于0的数,但对应右手系的投影长方体而言, n和f是z轴负向的点,所以上图的点坐标如果按照n > 0, f > 0的惯例来说,近裁剪面左下角的点是(l,b,-n),远裁剪面右上角的点应为(r,t,-f), 而且投影空间坐标系为x轴向右,y轴向上,z轴指向屏幕里,可以知道 这个坐标系 是左手坐标系,将近裁剪面-n映射为 -1, 将-f映射为1。
要完成投影变换,需要进行两个变换,先进行平移变换, 将长方体的中心与坐标系原点重合,然后进行缩放将其变为一个x,y,z取值范围为【-1,1】的正方体。
平移矩阵
根据前述,左下角(l,b,-n),右上角(r,t,-f), 可得中心点坐标((l+r)/2, (b+t)/2, -(n+f)/2), 因此平移矩阵为
因为需要从((l+r)/2, (b+t)/2, -(n+f)/2) 移动到(0,0,0)所以平移量为(-(l+r)/2, -(b+t)/2, (n+f)/2)
缩放矩阵
以X为例说明,移动到原点后,x的范围是 [ -(r-l)/2, (r-l)/2 ], 要映射到[-1, 1],所以缩放因子为 2/(r-l)。
需要特殊说明的是z,因为平移后近裁剪面的作为为 -n + (n + f)/2 = (f - n)/2, 远裁剪面的坐标是 -f +(n+f)/2 =(n - f)/2,要将他们分别映射为-1和1, 因此缩放因子是
-(-n - (-f))/2 = (n - f)/2, 由于n>0, f > 0 && n < f, 所以 n-f < 0, 相当于Z轴反向。
合成
投影矩阵就是把前面两个矩阵相乘,先平移再缩放, 可表示为 Morthoproj = ST,, 得到的矩阵如下
透视投影
视点(眼睛)在坐标原点,近裁剪面为n,远裁剪面为f, n > 0, f > 0, 在y方向的视域角为fovy,近裁剪面宽高比为aspect.
透视投影也可分为两步, 第一步是把透视投影的四棱台映射为正交投影的长方体,第二步是做正交投影变换。
四棱台映射为长方体
将四棱台映射为长方体,保持近裁面不变(x,y,z的坐标都不变), 远裁剪面的z值不变,
这样长方体的截面就是四棱台的近裁剪面。
从坐标系原点与近裁剪面上的点Anear (x1,y1,-n)连线,形成一条射线,与远裁剪面相交于 Bfar (x2,y2,-f),则两个点Anear和Bfar满足:
x1 / 近裁面的宽度 = x2/远裁剪面的宽度;
y1 / 近裁面的高度 = y2/远裁剪面的高度;
x1/y1=x2/y2 或 x1*y2=x2*y1(可以避免y1和y2为0的情况);
将这两点连成线段,对于线段上的任意一点(x,y,z)可知其映射到长方体上之后其x和y的坐标是x1和y1
由上图可知,按照相似三角形的关系: y1/-n = y/z ,之所以是y1/-n, 是因为近裁剪面的z坐标是-n,因此有
y1 = -yn/z = yn/-z;
同理 x1=xn/-z;
先不考虑z坐标如何变化,那么对于x和y的变换用矩阵表示为
对于变换后的 z'=(?1*x + ?2*y+A*z + B)/-z, 考虑到 z' 值与x和y没有关系,
即 ?1 和 ?2 都为0,所以:
z'=(A*z+B)/-z (此处如果z'与x和y有关系,那么后面的方程就无唯一解了),
映射后要保证远近裁剪面的z值不变,所以得出如下方程组:
-n = (A * -n + B) / n 即 An - B = n * n
-f = (A * -f + B) / f 即 Af - B = f * f
这是一个二元一次方程组,可以求得
A = f + n
B = fn
因此从四棱台映射为长方体的矩阵Mpers2ortho是
合成
透视投影变换矩阵Mpers=Morthoproj * Mpers2ortho 即先将四棱台映射为长方体,然后在做正交投影,相乘后得出如下矩阵
带入上面的fovy和aspect, n, f, 可以计算出l, r, t, b:
t = n * tan(fovy/2)
b = -n*tan(fovy/2)
r = n * aspect * tan(fovy/2)
l = -n * aspect * tan(fovy/2)
因此
r-l = 2*n * aspect * tan(fovy/2)
t-b = 2*n* tan(fovy/2), r+l=0, t+b=0
代入上面的矩阵得
如果是左手坐标系,那么推导过程中n和f就不需要加负号。