在调用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. spring-如何在项目启动的情况下获取Bean实例

    十年阿里,就只剩下这套Java开发体系了 >>>   大家都知道,项目启动的时候,spring读取xml文件,将配置的bean 或者 注解下的controller service d ...

  2. [D3] Load and Inspect Data with D3 v4

    You probably use a framework or standalone library to load data into your apps, but what if that’s o ...

  3. 1.2.4 Java Annotation 提要

    (本文是介绍依赖注入容器Spring和分析JUnit源码的准备知识) Java Annotation(标注) java.lang.annotation.Annotation是全部Java标注的父接口. ...

  4. Qt on Android: http下载与Json解析

    百度提供有查询 ip 归属地的开放接口,当你在搜索框中输入一个 ip 地址进行搜索,就会打开由 ip138 提供的百度框应用,你能够在框内直接输入 ip 地址查询.我查看了页面请求,提取出查询 ip ...

  5. 用DOM4J包实现对xml文件按属性分离。

    转自本人博客:http://www.xgezhang.com/dom4j_xml_separata.html dom4j是一个Java的XML API.类似于jdom.用来读写XML文件的. dom4 ...

  6. NSOperationQueue小结

    将建立的线程增加队列之中.他们都是并发运行的  假设想有一个线程在另外一个线程之后再运行的话 有一个方法能够实现- (void)addDependency:(NSOperation *)op; 这一个 ...

  7. 嵌入式project师考试知识点总结 微内核结构

    在操作系统的结构设计中,微内核结构表示的是 A)  总体式结构 B)  层次结构 C)  分布式结构 D)  客户机/server结构    微内核是指把操作系统结构中的内存管理.设备管理.文件系统等 ...

  8. Visual Studio Debugger

    Visual Studio Debugger中七个鲜为人知的小功能   Visual Studio debugger是一个很棒的调试工具,可以帮助程序猿们快速地发现和解决问题.这里给大家简单介绍一下V ...

  9. 【u115】&&【t031】 01迷宫

    01迷宫(maze01) Time Limit: 1 second Memory Limit: 128 MB [问题描述] 有一个仅由数字0与1组成的n×n格迷宫.若你位于一格0上,那么你可以移动到相 ...

  10. 常规容器下SpringBootServletInitializer如何实现web.xml作用解析

    在之前的<使用jsp作为视图模板&常规部署>章节有过一个实践,需要启动类继承自SpringBootServletInitializer方可正常部署至常规tomcat下,其主要能够起 ...