在调用gluLookAt和gluPerspective函数之前一般要先调用一下glLoadIdentity函数,先说一下这个函数是做什么的。

glLoadIdentity

glLoadIdentity是一个无参的无值函数,其功能是用一个4*4的单位矩阵来替换当前矩阵,实际上就是对当前矩阵进行初始化为单位矩阵。也就是说,无论以前进行了多少次矩阵变换,在该命令执行后,当前矩阵均恢复成一个单位矩阵,即相当于没有进行任何矩阵变换状态。之后对矩阵的变换都相当于是针对模型是位于世界坐标原点位置处进行的。

gluLockAt

在openGL中,视图变换是指保持模型坐标不变的情况下,从不同的方位观察模型,常用的设置观察者属性的函数为glLookAt 。

glLookAt 会定义一个视图矩阵,并与当前模型的模型矩阵相乘,获得模型的模型视图矩阵,再该模型视图矩阵左乘模型,就会获得在观察位置上模型的状态,就是我们在屏幕上最终看到的模型的状态。

gluLookAt用来定义观察者(相机)的状态,包括观察者在世界坐标系中所处的位置、看向世界坐标系中的方向(可以理解为眼睛所看向的方向)、观察者头部的朝向(可以在一个平面上360°旋转)。

void gluLookAt (
GLdouble eyex, GLdouble eyey, GLdouble eyez,
GLdouble centerx, GLdouble centery, GLdouble centerz,
GLdouble upx, GLdouble upy, GLdouble upz);
  • 第一二三个参数定义相机在世界坐标系中的位置坐标
  • 第四五六个参数定义相机正对着的世界坐标系中的点的位置坐标,成像后这一点会位于画板的中心位置
  • 第七八九参数,定义相机本身的朝向。这三个坐标是在世界坐标系中的坐标点,可以理解为人站立在相机处头的朝向。这三个坐标是世界坐标系中的坐标点,不是相机坐标系的,只是用来定义方向,注意这个不是视线(镜头)的朝向,而是摆放时相机本身的朝向,跟视线朝向方向是垂直的。

如果没有调用glLookAt设置视图矩阵,默认情况下,相机会被设置为位置在世界坐标系原点,指向z轴负方向,朝上向量为(0,1,0)。

以观察者的角度去看这几个参数就很容易理解了。第一组参数是定义人站在距离物体有多远处,第二组参数是定义人眼看向世界坐标系中的哪个方向,有时候屏幕上黑黑的什么也看不到,可能就是这组参数设置的方向不对,有可能物体就在你身后不远处,,第三组参数是人的朝向,也表示一个方向,这个朝向跟视线是垂直的。

始终需要明确的一点是openGL中世界坐标系是右手坐标系,在二维屏幕上,屏幕水平方向是x 轴方向,向右为正,屏幕竖起方向是Y轴方向,向上为正,垂直于屏幕的方向是Z轴方向,从屏幕里往外为正。

一图胜万言。以下从实际例子上分析一下这三组参数。

gluLookAt中前三个参数定义观察者的坐标,我们假定从Y轴正上方看一个位于世界坐标系原点的模型,坐标点为(0,5,0),此时看到的场景:

如果观察者沿着Y轴正方向移动一段距离,比如从5到8,则距离模型的距离远了,看起来的模型也应该小一些,事实确实如此:

gluLookAt中中间三个参数定义观察者视线正对着的世界坐标系中的位置。以上默认是(0,0,0),即看向原点,如果设置为(2,0,0),则点(2,0,0)应该成为视野的中心,相应的物体会沿着X轴的负方向移动2:

注意,这个茶壶模型的初始位置是在原点,壶口所对的方向是X轴正方向,壶把所对的方向是X轴负方向,由于在第一步中把视点从Z轴上移动到了Y轴上,所以上图中X轴变为了竖直方向,向上为正。

gluLookAt中最后三个参数定义观察者或者相机本身的朝向,这个朝向是跟视线方向相互垂直的,就像相机拍摄的时候可以旋转一定角度,上下颠倒等,但是视线(即镜头对准的方向)并没有变,对观察者来说,观察者的头部可以旋转一定角度,这三个参数就是定义相机或者观察者头部的转动方向的。

观察者头部朝向的方向为(1,0,0)时,模型为:

头部顺时针旋转45°,方向向量为(1,0,1),此时相当于模型逆时针旋转45°:

观察者头部颠倒一下方向,方向向量为(-1,0,0),此时模型方向也颠倒过来:

gluPerspective

如果说gluLookAt定义的是相机外在参数如相机所处位置、旋转角度等,那么gluPerspective定义的就是相机的内在镜头参数了。

gluPerspective (
GLdouble fovy,
GLdouble aspect,
GLdouble zNear,
GLdouble zFar);
  • 第一个参数flvy,定义可视角的大小,flvy值小,表示从相机(人眼)出发的光线的角度小,此时同等距离下,可观察到的视野范围较小,反之则大。从物体显示在画板的大小来反映,如果flvy值较大,则物体在画板中所占比例就较少,看起来比较小,反之则显示比较大。
  • 第二个参数aspect,定义物体显示在画板上的x和y方向上的比例。aspect小于1,则物体显示出来比实际更高,大于1,显示出来比实际看起来更宽,设为1,会按实际反应长宽比。
  • 第三个参数zNear,定义距离相机(人眼)最近处物体截面相距的距离。这个值越大,表示观测点距离物体距离越远,看起来物体就比较小,反之则比较大。如果物体运动到距离观测点的距离小于了设定的zNear,则物体不会被绘制在画板上。
  • 第四个参数zFar,定义可观测到的物体的最远处截面相距相机的距离。如果物体运动到距离观测点的距离大于了设定的zFar,则物体不会被绘制的画板上。

各个参数的意义可以用下图表示:



第一参数表示视场角的大小,符合人眼的条件一般设置为40°~70°之间,第二个参数定义模型显示的长宽比,这两个参数比较容易理解。第三和第四个参数定义了观察者在深度上的可视范围,可以理解为镜头的景深,所不同的是镜头在景深外成像时模糊的,而在这里“景深”之外的影响是直接被屏蔽掉的。

还要注意一点的是zNear和zFar都是从观察者或者相机的视点出发计算的,而不是从世界坐标系的原点出发的。

仍以上图为例,视点离原点的距离为5,我们设置zNear为4,zFar为10,可以看到完整的模型:




当进一步推进zNear为4.5时,已经有部分被截取掉,此时已经相当于视线深入到茶壶内部了:




完整代码如下,通过调整gluLookAt和gluPerspective的各个参数可以查看模型不同的显示效果:

#include <GL/glut.h>
#include <stdlib.h> void display(void)
{
glClearColor(1,1,1,0);
glClear (GL_COLOR_BUFFER_BIT);
glColor3f (0, 0, 1.0); //画笔蓝色
glLoadIdentity(); //加载单位矩阵
gluLookAt(0.0,5.0,0.0, 0,0,0, 1.0,0.0,0);
glutWireTeapot(1.3);
glutSwapBuffers();
} void reshape (int w, int h)
{
glViewport (0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 4, 10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
} int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize (500, 500);
glutInitWindowPosition (100, 100);
glutCreateWindow ("gluPerspective ( X, X, 4,10 )");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}


OpenGL(六) gluLookAt和gluPerspective函数解析的更多相关文章

  1. OpenGL函数解析之gluPerspective()

    函数原型: void gluPerspective(GLdouble fovy,GLdouble aspect,GLdouble zNear,GLdouble zFar); 参数说明: fovy:指定 ...

  2. OpenGL的gluLookAt和glOrtho的关系

    OpenGL的gluLookAt和glOrtho的关系 一直不明白gluLookAt()和glOrtho()两者之间的关系:gluLookAt()是观察变换,glOrtho()是正交投影.glLook ...

  3. 小猪猪C++笔记基础篇(六)参数传递、函数重载、函数指针、调试帮助

    小猪猪C++笔记基础篇(六) ————参数传递.函数重载.函数指针.调试帮助 关键词:参数传递.函数重载.函数指针.调试帮助 因为一些事情以及自己的懒惰,大概有一个星期没有继续读书了,已经不行了,赶紧 ...

  4. OpenGL中glFrustum()和gluPerspective()的相互转换

    OpenGL中在窗口的大小发生变化的时候会触发resize()函数,这里会传入一个新的宽和高,在resize()函数中我们会设置投影矩阵,在可以使用OpenGL基础函数glFrustum()函数和gl ...

  5. x265探索与研究(六):main()函数

    x265探索与研究(六):main()函数 x265源代码的入口函数是main(),本文分析main()的主要功能. 首先给出main()函数的功能及其代码结构:其次给出main()函数源代码以及分析 ...

  6. python重要的第三方库pandas模块常用函数解析之DataFrame

    pandas模块常用函数解析之DataFrame 关注公众号"轻松学编程"了解更多. 以下命令都是在浏览器中输入. cmd命令窗口输入:jupyter notebook 打开浏览器 ...

  7. [转]javascript eval函数解析json数据时为什加上圆括号eval("("+data+")")

    javascript eval函数解析json数据时为什么 加上圆括号?为什么要 eval这里要添加 “("("+data+")");//”呢?   原因在于: ...

  8. Oracle函数解析

    一:大小写控制函数 lower()函数:(此函数将全部的大写字母都可以变为小写字母) upper()函数:(将输入的字符串变为大写字母) initcap()函数:(将每个字符串的首字母大写)  二:字 ...

  9. PHP json_decode 函数解析 json 结果为 NULL 的解决方法

    在做网站 CMS 模块时,对于模块内容 content 字段,保存的是 json 格式的字符串,所以在后台进行模块内容的编辑操作 ( 取出保存的数据 ) 时,需要用到 json_decode() 函数 ...

随机推荐

  1. 与Eclipse关于"Call Hierarchy"和"Find Reference"功能比较

    "Call Hierarchy"功能比较 Eclipse的"Call Hierarchy"可以查看一个Java方法或类成员变量的调用树(caller和calle ...

  2. Android 控件EditText的setOnEditorActionListener方法的理解

    需要注意的是 setOnEditorActionListener这个方法,并不是在我们点击EditText的时候触发,也不是在我们对EditText进行编辑时触发,而是在我们编辑完之后点击软键盘上的回 ...

  3. Android MagicIndicator系列之一 —— 使用MagicIndicator打造千变万化的ViewPager指示器

    说到 ViewPager 指示器,想必大家都不陌生,绝大部分应用中都有这个.使用频率非常之高.但系统对它的支持并不好,自带的 PagerTabStrip 和 PagerTitleStrip 太弱,很难 ...

  4. bash - trap

    http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html The syntax for the trap statement is s ...

  5. 【u008】瑞瑞的木棍

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] 瑞瑞有一堆的玩具木棍,每根木棍的两端分别被染上了某种颜色,现在他突然有了一个想法,想要把这 些木棍连在 ...

  6. TOP 10 ONLINE COMPILER

    Top 10 Online Compilers +1338 Tweet Share106 Share Pin 444 Shares Online compilers are one type of t ...

  7. 【转】C++11 并发指南五(std::condition_variable 详解)

    http://www.cnblogs.com/haippy/p/3252041.html 前面三讲<C++11 并发指南二(std::thread 详解)>,<C++11 并发指南三 ...

  8. 代码中jndi数据源的支持

    项目中基本都使用Spring框架,支持jndi还是很简单的,只需在spring配置文件中加入 <!-- 使用jndi配置数据源 --> <bean id="dataSour ...

  9. QT类库与Delphi VCL类库的体系结构对比——两者十分类似!

    今天在看QT对象内存管理的一篇文章时:http://blog.csdn.net/dbzhang800/article/details/6300025想到了一个问题:就是QT类库体系结构与Delphi类 ...

  10. 图片拉伸:IOS开发UIImage中stretchableImageWithLeftCapWidth

    意思就是用来创建一个内容可拉伸,而边角不拉伸的图片,需要两个参数,第一个是左边不拉伸区域的宽度,第二个参数是上面不拉伸的高度.那么接下来的一个像素会被拉伸.例如,leftCapHeight为6,top ...