在调用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. 用strace排查故障的5种简单方法(每日一译)

    原文链接:5 simple ways to troubleshoot using Strace 我很意外大部分人都不知道如何使用strace.strace一直是我的首选debug工具,因为它非常的有效 ...

  2. Android自定义组件系列【6】——进阶实践(3)

    上一篇<Android自定义组件系列[5]--进阶实践(2)>继续对任老师的<可下拉的PinnedHeaderExpandableListView的实现>进行了分析,这一篇计划 ...

  3. sdo_geometry 转 st_geometry

    CREATE OR REPLACE FUNCTION sdo2sde(geo SDO_GEOMETRY) RETURN st_geometry IS lx number; --类型 (点.线.面) c ...

  4. JSON 表达式

    JSON语法规则:     数据在名称/值对中:     数据由逗号分隔:     大括号保存对象:     中括号保存数组 1.访问对象值: var myObj,x; myObj = {" ...

  5. 利用performSelectorInBackground和performSelectorOnMainThread实现多线程

    NSObject类的performSelectorOnMainThread和performSelectorInBackground能够实现简单的多线程编程技术 1.- (void)performSel ...

  6. [Angular] Dynamic components with ComponentFactoryResolver

    To create a component dynamicly. 1. Add a container with ref: @Component({ selector: 'app-root', tem ...

  7. iPad和iPhone开发的异同

    niPad和iPhone开发的异同   niPad简介 n什么是iPad p一款苹果公司于2010年发布的平板电脑 p定位介于苹果的智能手机iPhone和笔记本电脑产品之间 p跟iPhone一样,搭载 ...

  8. Expression Blend 的点滴(4)--创建类似iPhone屏幕锁控件(上)

    原文:Expression Blend 的点滴(4)--创建类似iPhone屏幕锁控件(上) 本篇文章,最终效果图:  当然,不只是一个UI而已,如果只是一张图片,那专业的设计师能做出更出色的效果.在 ...

  9. AR Drone系列之:使用ROS catkin创建package并使用cv_bridge实现对ar drone摄像头数据的处理

    1 开发环境 Ubuntu 12.04 ROS Hydro 2 前提 可參考这篇blog:http://blog.csdn.net/yake827/article/details/44564057 b ...

  10. 学习鸟哥的Linux私房菜笔记(1)——Linux系统入门

    今天在阿里云申请了一个centos系统的云服务器,以前对linux了解的只是皮毛,记了几个命令还给忘了,整了半天都弄不好,作为一个做过javaweb开发的coder实在是惭愧啊,决定从今天开始学习Li ...