glOrtho、glFrustum && glPerspective
glOrtho :正交投影,摄像机可以位于裁剪体内,所以near和far可以取两个正值或者一正一负glFrustum :透视投影,摄像机不可以位于裁剪体内,所以near和far都必须去正值,它的参数矩阵定义了才简体以及投影的类型,但是未定义摄像机的方位。GL 中的摄像机位于原点,并指向了Z轴的负方向。函数glFrustum只是修改了摄像机的 透镜,并非位置,为了改变位置或者朝向可以借助于模型视图矩阵相对于摄像机移动场景中的对象,或者通过GL变换,或者用函数gluLookAt().以为glFrustum对参数far和near非常敏感,修改near和far则远景可能就影响很大,所以常用于观察近景。
glPerspective:也是用于透视投影,功能和glFrustum非常相似,参数不一样。相对于glFrustum来说不常用。
void glPerspective(GLdouble fov, GLdouble aspect, GLdouble near, GLdouble far)
fov是依据y方向的视角,aspect是近裁剪面的纵横比,当然远裁剪面也取这个值,near和far的意义和上面的一样。
透视投影的一个问题就是深度精度的损失,在显示设备中该问题很明显。问题出在深度缓存中深度的限制以及由透视投影引起的非线性比例变换。当近裁剪面非常靠近投影中心的时候,误差就非常大。
以下摘自网络,对参数讲的很经典:
OpenGL 关于视景台gluPerpective,glFrustum的理解
作者:华文广 [url] [/url]
07/3/30
很多刚学OpenGL的朋友,都会对视景台的定义有很大的迷惑,这里以我的经验来解释一下,希望对大家有所帮助,
void glFrustum(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far);
在这个函数中,有六下参数,这六个参数,都不是真实的世界坐标(虽然有些书上说它们是坐标),而指的是到眼睛的平面距离,
left,right分别指的是左右截面到眼睛(在XY平面上)的距离,这两个数不必一定要对称,甚至两个都可以大于或小于0;
对称
|-------------|
| |
| eye |
| |
|-------------|
left(-1.0) right(1.0)
====================================================
不对称
|-------------|
| |
eye | |
| |
|-------------|
left(1.0) right(2.0)
视景体默认情况下,眼睛位置是在坐标原点(0.0f,0.0f,0.0f)处,视线指向Z轴的负向。
如果是这种情况,上图中的left,right的值,就刚好是与它们的世界坐标一一对应的。top和bottom也同样理解。
一种理解方式是这样:
眼睛是位于坐标原点,是逆着Z轴向屏幕里看的;
gluPerpective,glFrustum函数的zNear, zFar都是相对眼睛的距离,
其各自的负值为相对于坐标系原点的坐标值;
每个画的物体,其中心最开始都是位于坐标系的原点的,
通过glTranslate, glRotate函数,把物体移动到视景中,这样物体才可以被看得见;
但是事实上,眼睛可以是任何位置,视线也可以不平行于Z轴,这种情况情下,left,right,top,bottom,near,far,
它们指的就只是到眼睛的平面距离,与坐标没有一一对应的关系。
好像越说越复杂了。呵呵。
===============================================
你可以这样想:在眼睛前面有一个视景台,这个台体并不是固定的,而是随着你视线的转动而转动,
也就是说,视景台的正面和底面始终与视线垂直。那么,当你的眼睛是在(0,0,0)处,视线是指向Z的负向时,
视景台的近面(0.3)和远面(0.7)所对应的坐标,就是(-0.3,-0.7)
[code]
|Y (0.3) (0.7)
| |
|0.0 | -0.3 |-0.7
*eye-------------|--------------|-------> -Z
| | |
| |
|[/code]再举个例子,如下图,眼睛在0.1处,视线指向X轴正向,
那么视景台也在X轴正向上,近面对应的坐标是0.4,远面对应的坐标是0.8
[code]
|Y (0.3) (0.7)
| |
|0.0 0.1 | 0.4 |0.8
-------eye *-----|--------------|------->X
| | |
| |
|[/code]另外一种理解方式是这样的:
物体在空间中者有着其固定的位置。物体不被移动,
我们可以通过调整眼睛的位置,和视线的方向,来观看空间中的所有物体。
================================================
其实这是一个非常主观性的问题,
主要是看你如何去看待。
也就是说,我们可以设想眼睛不动,只移动空间中的物体。
但是我们也可以设想坐标系中的物体不动,我们只移动眼睛,
动作是相对的,但效果是一样的
对于3DMAX这样的绘图软件就是一种眼睛不动的做法。
但对于游戏,地形漫游之类的软件,则是采用,物体不动,只移动眼睛位置的方法。来模拟一个人在地形上走动
=====================================
前面我们说过,视景台是可以不对称的(这个特性有一些高级应用),
但大多的情况下我们还是会定义一下与视线对称的视景台。于是我们可以使用gluPerpective这个函数。
gluPerpective函数的zNear, zFar都是相对眼睛的(YZ平面)距离,fovy是视野角度。
openGL坐标系
openGL使用右手坐标
从左到右,x递增
从下到上,y递增
从远到近,z递增
OPENGL坐标系可分为:世界坐标系和当前绘图坐标系。
世界坐标系以屏幕中心为原点(0, 0, 0)。你面对屏幕,你的右边是x正轴,上面是y正轴,屏幕指向你的为z正轴。长度单位这样来定: 窗口范围按此单位恰好是(-1,-1)到(1,1)。
当前绘图坐标系是 绘制物体时的坐标系。程序刚初始化时,世界坐标系和当前绘图坐标系是重合的。当用glTranslatef(),glScalef(), glRotatef()对当前绘图坐标系进行平移、伸缩、旋转变换之后, 世界坐标系和当前绘图坐标系不再重合。改变以后,再用glVertex3f()等绘图函数绘图时,都是在当前绘图坐标系进行绘图,所有的函数参数也都是相 对当前绘图坐标系来讲的。
OpenGL之gluLookAt函数
利用实用库函数gluLookAt()设置视觉坐标系。在实际的编程应用中,用户在完成场景的建模后,往往需要选择一个合适的视角或者不停地变换视角,以对场景作观察。实用库函数gluLookAt()就提供了这样的一个功能。
void gluLookAt(GLdouble eyex,GLdouble eyey,GLdouble eyez,GLdouble centerx,GLdouble centery,GLdouble centerz,GLdouble upx,GLdouble upy,GLdouble upz);
该函数定义一个视图矩阵,并与当前矩阵相乘。eyex, eyey,eyez 指定视点的位置;centerx,centery,centerz 指定参考点的位置;upx,upy,upz 指定视点向上的方向(如图)
视点E、参考点C、视点向上的方向U实际上就是设定了一个视觉坐标系。这个视觉坐标系的原点是E,视线的方向(即z轴)是C-U,y轴方向就是视点向上的方向U,剩下的x轴方向就是向量((C-E)*U)。由于y轴和x轴是垂直的,所以也要求向量(C-U)和U互相垂直。这点在设置该函数参数时是必须注意的。