之前对视图知其然而不知其所以然,故而于此深究其理。
一、四种变换
1. 视图变换;
2. 模型变换;
3. 投影变换;
4. 视口变换。
弄明白这四种变换,视图方面的理解也该差不多了。
首先定义位置。OpenGL中位置用(x,y,z,w)表示,x,y,z表示空间中的位置,而w通常为1,在之后的“透视除法”中使用。
二、视图变换
比如用库函数画一个四面体线框:
gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glutWireCube(1.0);
视图变换设置:位置为(0.0, 0.0, 5.0),视线上的任一点(0.0, 0.0, 0.0),即确定了方向,向上方向为(0.0, 1.0, 0.0),即Y轴正方向。显示的结果为:
如若改变视图变换为:
gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0);
显示的结果为:
即把照相机向右倾斜了45度。
默认情况下,照相机位于原点,指向z轴的负方向,以y轴的正方向为朝上方向。
三、模型变换
模型变换是对空间中的物体进行变换,主要有三种:平移、旋转和缩放。
void glTranslate(TYPE x, TYPE y, TYPE z);
void glRotate(TYPE angle, TYPE x, TYPE y, TYPE z);
void glScale(TYPE x, TYPE y, TYPE z);
实际上,视图变换的某些效果可以由模型变换组合得到。因此,在OpenGL中,把视图变换和模型变换一起用模型视图矩阵表示(关于矩阵见后)。
四、投影变换
投影变换做两件事:一是规定场景中的哪部分进行显示(定义视景体/平头截体);二是如何显示(正投影和透视投影)。
定义视景体的部分总被我忽略,导致显示与预计不符,这种错误会浪费”巨大“时间去追踪。
1. 透视投影
透视投影将距照相机远的物体显示的较小。openGL库以glFrustum指定透视投影及其视影体。
void glFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far);
指定了视影体的左下近点和右上远点。
另有openGL工具函数库提供gluPerspective函数定义视影体(较直观)。
void gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble near, GLdouble far);
如下示例代码及其显示效果:
2. 正投影正投影的视景体是个长方体。物体和照相机间的距离不影响其显示大小。正投影由glOrtho指定。
void glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far);
透视投影和正投影的效果:
前图为透视投影,后图为正投影。
五、视口变换。
通俗的讲,视口变换规定了最终图像显示在窗口的哪个区域。
void glViewport(GLint x, GLint y, GLsizei width, GLsizei height);
左下角为(x,y),宽为width,高为height。
以上图为例,”正常情况“下视口的宽高比与窗口相同,显示的是正方体。但是如果宽高比为1:2,则显示的是长方体,如下。
glViewport(0, 0, (GLsizei)w/2, (GLsizei)h);
六、矩阵堆栈
OpenGL中的变换是通过矩阵实现的。
对于模型视图矩阵,堆栈中可以存放32个4*4矩阵。每次操作的是栈顶,可以用下面的函数压入和弹出矩阵。
void glPushMatrix(void);
void glPopMatrix(void);
当创建顶点数组渲染时,为了不影响其他的矩阵,可以先Push个单位阵进去,使用完后,再Pop出来。
七、综上所述,对我最终显示在屏幕上东西,是由多方因素影响的,比如当不显示时,不一定是物体空间有问题,可以是视点或者视景体设置的不同。因为要多方考量。
八、从数学层面上来看,视图的变化实际上就是矩阵的点乘操作。最终形成的矩阵中,每个元素(或者多个)代表不同的含义。参见: