OpenGL - 透视投影

我们知道,在计算机中3D场景本身并非真实存在的,而是通过一系列的数据来模拟出来的效果,最终通过渲染将它隐射到屏幕上。这就类似于绘画时,我们在脑子里虚构了一个场景,然后通过一些技巧,比如近大远小等等将它跃然纸上。

如果使用过一段时间的3D引擎,我们就会知道相机这个东西。实际上相机并非真实存在的,像其他术语一样,它是人们为了模拟3D世界上的一个观察点而形象地设置的一个概念。在3D绘制中有透视相机和平行相机,他们对应的分别是透视投影和正交投影。

参见: http://rungame.me/blog/2014/05/12/u3d-projection/

透视

在OpenGL里,默认以原点为相机的观察点,沿着z轴的负方向来来绘制x、y、z坐标范围为[-1,1]的场景内容(在一些引擎里坐标系可能远大于[-1,1],但最终都要通过矩阵转化为[-1,1]这个坐标系)。

但是,我们习惯以原点为中心点来构建场景,这样相机就与场景就重合了,导致什么也看不到。所以,我们要想方设法把相机转移到一个远离场景的位置。使用glm库的lookAt的函数可以改变相机的位置。

glm::lookAt(glm::vec3 const & eye,     //相机位置
            glm::vec3 const & center,   //相机观察的点
            glm::vec3 const & up);       //世界的朝上方向,没有特殊情况填(0,1,0)

看到这个函数,我们也就能知道到需要怎么做了,因为场景在原点所以观察点的位置center应该是(0,0,0)。而相机的位置eye需要设置一个远离(0,0,0)点的位置,比如在正上方(0.0f,0.0f,3.0f)。

glm::lookAt(glm::vec3(0.0f,0.0f,3.0f),
            glm::vec3(0,0,0),
            glm::vec3(0,1,0));

需要注意的是,在3D世界里,我们想观察一座山时,我们不是改变相机位置而是通过改变山的位置。lookAt函数的原理也是如此,lookAt函数通过一系列的矩阵转换(具体就是translate和rotate)将3D空间的世界进行转换从而让相机能观察到。

在真实世界中,人在观察物体时通常会有“近大远小”的感觉,而在透视相机里通过perspective矩阵模拟了该效果。perpective函数设置了一个四方锥,并将靠近四方锥近面的物体变大,而靠近底面的物体变小,最后转化为一个x、y、z的范围为[-1,1]的立方体。(参见:http://rungame.me/blog/2014/05/12/u3d-projection/)

glm::mat4 perspective(float fovy,        //张角角度
                        float aspect,     //视口比例为屏幕宽高比
                        float zNear,      //近平面距离
                        float zFar);      //远平面距离

我们在实例里添加了一个通过AD键来控制模型旋转的矩阵Model。

完整代码

接上一部分代码,加入了投影、视图转换,并设置A D键控制旋转

https://github.com/sbxfc/OpenGLProjectionMatrices

Comments