三维投影变换是3D固定流水线的重要组成部分,是将相机空间中的点从视锥体(frustum)变换到规则观察体(Canonical View Volume,CVV)中,待裁剪完毕后进行透视除法的行为。在算法中它是通过透视矩阵乘法和透视除法两步完成的。通过投影,几何图形的3D坐标转换成屏幕上的2D坐标。通过指定投影,可以指定在窗口中显示的视景体(Viewing Volume),并指定如何对其进行变换。
正投影(Orthographic Projection)
又称平行投影,使用这种投影需要指定一个正方形或长方形的视景体,视景体之外的任何物体将被裁剪掉,不会被绘制。所有实际大小相同的物体在屏幕上都有相同的大小,不管远近。
public array orthographic_matrix(float l, float r, float t, float b, float n, float f)
{
vector4 row0 = vector4( 2/(r-l), 0, 0, (l+r)/(l-r) );
vector4 row1 = vector4( 0, 2/(t-b), 0, (b+t)/(b-t) );
vector4 row2 = vector4( 0, 0, 2/(f-n), (n+f)/(n-f) );
vector4 row3 = vector4( 0, 0, 0, 1 );
return matrix_4(row0, row1, row2, row3);
}
透视投影(Perspective Projection)
在这种投影中,远处的物体看上去比近处的物体更小一些。它的视景体看上去像一个顶部被削平的金字塔,叫平截头体(frustum),观察方向从金字塔的尖端到宽阔端,观察者的视点与金字塔的尖端拉开一定距离。
public array perspective_matrix(float fov, float aspect, float n, float f)
{
float cot = 1/math.tan(fov/2);
vector4 row0 = vector4( cot/aspect, 0, 0, 0 );
vector4 row1 = vector4( 0, cot, 0, 0 );
vector4 row2 = vector4( 0, 0, (f+n)/(f-n), 2*f*n/(n-f) );
vector4 row3 = vector4( 0, 0, 1, 0 );
return matrix_4(row0, row1, row2, row3);
}
透视投影是非线性变换,光栅化过程中对纹理坐标的插值不能使用线性插值,要使用透视校正插值进行计算。
参考资料
OpenGL学习脚印: 投影矩阵和视口变换矩阵(math-projection and viewport matrix)