由于OpenGl每次都会将物体都是变换为屏幕上的二维来显示,所以少不了坐标变换(将3D处理在2D上显示),然后并进行裁剪处理(显示范围之外的点都被裁剪掉(Clipped)),默认的可见坐标是-1.0~1.0,假如我们想自己显示投影的部分,那么就需要投影矩阵,通过投影矩阵可以创建一个观察箱(Viewing Box),又称为平截头体(Frustum),那么所有出现在观察箱里的顶点都会显示在屏幕上,创建一个投影矩阵有两种不同方法:
正射投影矩阵(Orthographic Projection Matrix)或一个透视投影矩阵(Perspective Projection Matrix)。.
1.正射投影(orthographic projection matrix)
正射投影对应的qt中函数是:
void QMatrix4x4::ortho(float left, float right,
float bottom, float top,
float nearPlane, float farPlane)
// left right, bottom, top : 设置观察箱(平截头体)的上下左右坐标
// nearPlane: 设置近平面的距离
// farPlane: 设置远平面的距离
对应如下图所示:
初始化好投影矩阵后,会将处于这些x,y,z值范围内的坐标变换为标准化设备坐标,对应的源码如下所示:
如上图所示,可以看到将转换规则以一个系数存储在矩阵中,当乘上原本的标准坐标向量时,就会将标准坐标转为标准化设备坐标,而对于w分量部分(矩阵最后一行)依然是[0 0 0 1],所以会导致无论物体距离相机多远投影后的物体大小尺寸不变.如下图所示:
使用透视投影的话,远处的顶点看起来比较小,而在正射投影中每个顶点距离观察者的距离都是一样的。
2.透视投影
使用透视投影,会比正射投影更加真实(投影中心无变形,离中心越远变形越大)
透视投影通过w分量来实现,离观察者越则w分量越大,然后顶点坐标的每个分量都会去除以它的w分量(所以越远,则顶点坐标越小):
所以我们之前学习的坐标向量都是vec4,因为通过w分量才能帮我们进行透视投影.
透视投影对应的qt中函数是:
void QMatrix4x4::perspective(float verticalAngle, float aspectRatio, float nearPlane, float farPlane)
// verticalAngle: 垂直角度(也就是裁剪窗口的高度),值越大,那么物体越小
// aspectRatio: 横纵比(由视口的宽除以高所得),值越大则越宽值,比如宽高为100X50,那么就等于2
// nearPlane: 设置近平面的距离(一般设置为0.1)
// farPlane: 设置远平面的距离(一般设置为100)
源代码如下所示:
可以看到对于w分量部分(矩阵最后一行)是[0 0 -1 0],假如z向量有值的话会乘以(-1).得到的w分量将会有值的,通过透视除法后将会导致坐标越小,接下来我们便来测试一下.
3.正射投影和透视投影测试
测试代码如下所示:
Vector4D vec(1,2,100,1);
QMatrix4x4 projection1;
projection1.ortho(10,20,0,10,10,100);
qDebug()<<projection1<<projection1*vec;
QMatrix4x4 projection2;
projection2.perspective(10,20,0.1,100);
qDebug()<<projection2<<projection2*vec;
运行打印:
可以看到对于z为100的物体,通过透视投影转换后得到的坐标的z值是-100。然后当顶点变换到裁剪空间时,会执行透视除法,从而导致顶点坐标很小.
而对于正射投影的话,转换出来的向量z值始终为1. 所以正射投影不支持透视除法.
未完待续,下章就在3D场景中使用投影矩阵.
本专栏opengl技术交流群:929155430