参考文章 GL学习笔记(2) - 终于搞明白gluPerspective和gluLookAt的关系了(zz)

gluPerspective的具体含义

解密--神秘的gluPerspective

函数原型

gluLookAt(GLdoble eyex,GLdouble eyey,GLdouble eyez,GLdouble centerx,GLdouble centery,GLdouble centerz,GLdouble upx,GLdouble upy,GLdouble upz);
gluPerspective(GLdouble fovy,GLdouble aspect,GLdouble zNear,GLdouble zFar)

使用方法

// 设置投影矩阵
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (GLfloat)w/(GLfloat)h, 0.1f, 100.0f);

gluPerspective


一个一个来,首先得设置gluPerspective,来看看它的参数都表示什么意思
fovy,这个最难理解,我的理解是,眼睛睁开的角度,即,视角的大小,如果设置为0,相当你闭上眼睛了,所以什么也看不到,如果为180,那么可以认为你的视界很广阔,
aspect,这个好理解,就是实际窗口的纵横比,即x/y,这个影响到视野的截面有多大。
zNear 表示近裁剪面到眼睛的距离,zFar表示远裁剪面到眼睛的距离,注意zNear和zFar不能设置设置为负值(你怎么看到眼睛后面的东西)。
zFar表示远处的裁面。

如果还没有理解就继续看,
我们知道,远处的东西看起来要小一些,近处的东西看起来会大一些,这就是透视原理。

假设那两条线表示公路,理论上讲,它们的两条边是平行的,但现实情况中,它们在远方(可以无限远)总要相交于一点,实际线段AB的长度=CD的长度,只是在此例中使用了透视角,故会有如上的效果,是不是很接近现实的情况?

结合我们刚才这两个函数
zNear,眼睛距离近处的距离,假设为10米远,请不要设置为负值,OpenGl就傻了,不知道怎么算了,
zFar表示远处的裁面,假设为1000米远,
就是这两个参数的意义了,

再解释下那个"眼睛睁开的角度"是什么意思,
首先假设我们现在距离物体有50个单位距离远的位置,
在眼睛睁开角度设置为45时,请看大屏幕:

我们可以看到,在远处一个球,,很好玩哈,
现在我们将眼睛再张开点看,将"眼睛睁开的角度"设置为178
(180度表示平角,那时候我们将什么也看不到,眼睛睁太大了,眼大无神)
我们只看到一个点,,,,,,,,,,,,,,,,,,,,,,,,,,,
因为我们看的范围太大了,这个球本身大小没有改变,但是它在我们的"视界"内太小了,
反之,我们将眼睛闭小些,改为1度看看会出现什么情况呢?

在我们距离该物体3000距离远,"眼睛睁开的角度"为1时,我们似乎走进了这个球内,这个是不是类似于相机的焦距?

当我们将"透视角"设置为0时,我们相当于闭上双眼,这个世界清静了,

我们什么也看不到,,,,,,,,,

给出一个测试用例:

    void display(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 清除屏幕及深度缓存
glLoadIdentity(); // 重置当前的模型观察矩阵
//glutSolidSphere(1.0, 400, 16); //繪製一個球體
/*当您调用glLoadIdentity()之后,您实际上将当前点移到了屏幕中心,X坐标轴从左至右,Y坐标轴从下至上,Z坐标轴从里至外。OpenGL屏幕中心的坐标值是X和Y轴上的0.0f点。中心左面的坐标值是负值,右面是正值。移向屏幕顶端是正值,移向屏幕底端是负值。移入屏幕深处是负值,移出屏幕则是正值。
glTranslatef(x, y, z)沿着 X, Y 和 Z 轴移动。根据前面的次序,下面的代码沿着X轴左移1.5个单位,Y轴不动(0.0f),最后移入屏幕6.0f个单位。注意在glTranslatef(x, y, z)中当您移动的时候,您并不是相对屏幕中心移动,而是相对与当前所在的屏幕位置。*/ glPushMatrix();
   glTranslatef(-2.5f,0.0f,-6.0f); // 左移 1.5 单位,并移入屏幕 6.0
glRotatef(rtri,0.0f,1.0f,0.0f); // 绕Y轴旋转三角形    glBegin(GL_TRIANGLES); // 绘制三角形
glColor3f(1.0, 0.0, 0.0);
glVertex3f( 0.0f, 1.0f, 0.0f); // 上顶点
glColor3f(0.0, 1.0, 0.0);
glVertex3f(-0.5f,0.0f, 0.0f); // 左下
glColor3f(0.0, 0.0, 1.0);
glVertex3f( 0.5f,0.0f, 0.0f); // 右下
glEnd(); // 三角形绘制结束
glPopMatrix(); //绘制四棱锥
//glLoadIdentity();
glPushMatrix();
glTranslatef(4.0f, -0.5f, -6.0f);
glRotatef(rtri, 0.0f, 1.0f, 0.0f);
glBegin(GL_TRIANGLES);
//繪製上頂點 左側面
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 1.0f, 0.0f); glColor3f(0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f, 0.0f, 0.0f); glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(0.0f, 0.0f, 1.0f);
//右側面
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 1.0f, 0.0f); glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(0.0f, 0.0f, 1.0f); glColor3f(0.0f, 1.0f, 0.0f);
glVertex3f(1.0f, 0.0f, 0.0f);
//右后側面
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 1.0f, 0.0f); glColor3f(0.0f, 1.0f, 0.0f);
glVertex3f(0.0f, 0.0f, -1.0f); glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(0.0f, 0.0f, -1.0f); //左后側面
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 1.0f, 0.0f); glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(0.0f, 0.0f, -1.0f); glColor3f(0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f, 0.0f, 0.0f); glEnd();
glPopMatrix();
//绘制茶壶
glPushMatrix();
glTranslatef(0.0f, 0.0f, -8.0f);
glutWireTeapot(2.0f);
glPopMatrix(); //設置當前使用的顏色為白色
glColor3f(1.0, 1.0, 1.0);
glFlush(); rtri += 0.3;
rquad += 0.2;
}

gluLookAt

现在来看gluLookAt(GLdoble eyex,GLdouble eyey,GLdouble eyez,GLdouble
centerx,GLdouble centery,GLdouble centerz,GLdouble upx,GLdouble
upy,GLdouble upz);

它共接受三对坐标,
分别为eye,center,up
故名思义,eye表示我们眼睛在"世界坐标系"中的位置,
center表示眼睛"看"的那个点的坐标,

最后那个up坐标表示观察者本身的方向,如果将观察点比喻成我们的眼睛,那么这个up则表示我们是正立还是倒立异或某一个角度在看,所看的影像大不相同,故此时需要指明我们现在正立,那么X,Z轴为0,Y轴为正即可,通常将其设置为1,只要表示一个向上的向量(方向)即可
球是画在世界坐标系的原点上的,即O(0,0,0)坐标上,我们的眼睛位于观察点A(0,0,100),Z轴向屏幕里看去的方向为负,屏幕外我们的位置,Z轴为正值,其实很好理解,即我们距离原点的距离,设置100,将观察到如下图所示的影像

 

如果我们向前或向后移动,则相应的图像会变大或变小,这里其实就是运用了透视原理,近处的物体大,远处的物体小,实际物体的大小是不变的,

同理改变center坐标(眼睛看去的那个点,可简单理解为视线的终点)也会影响球的大小,同样可以认为是改变了物体与观察点的距离所致,

最后那个up坐标表示观察者本身的方向,如果将观察点比喻成我们的眼睛,那么这个up则表示我们是正立还是倒立异或某一个角度在看,所看的影像大不相同,
故此时需要指明我们现在正立,那么X,Z轴为0,Y轴为正即可,通常将其设置为1,只要表示一个向上的向量(方向)即可,我们指定0.1f或
0.00001f异或1000.0f,效果是一样的,只要能表示方向即可,

以上理解了之后,来做一个测试
透视图不变,最远处仍为3000,近处为0.1

gluPerspective                            // 设置透视图
        (45,               
            // 透视角设置为 45 度,在Y方向上以角度为单位的视野
        (GLfloat)x/(GLfloat)y,    // 窗口的宽与高比
        0.1f,               
                //
视野透视深度:近点1.0f
        3000.0f       
                    //
视野透视深度:始点0.1f远点1000.0f
        );

将我们的观察点置于A(0,10,0),
将观察位置(视线终点)坐标置于(0,0,0)
然后在原点开始绘图,画一个V字形,并将Z轴的值从-1000递增加到+1000,增量为10,
代码如下

    glColor3f(0.5f, 0.7f, 1.0f);

glBegin(GL_LINES);
        for(int i=-1000;i<=1000;i+=10)
        {
            glVertex3f(0,0,i);
            glVertex3f(10,10,i);

glVertex3f(0,0,i);
            glVertex3f(-10,10,i);
        }
    glEnd();

F5运行效果如下图

上图证实了我们的推测

//---------------------------------------------
    //生成网络
    glColor3f(0.5f, 0.7f, 1.0f);
    int x=(int)(40*2);
   
    glBegin(GL_LINES);
            for(int i=-x;i<=x;i+=4)
            {
                glVertex3i(-x,0,i);
                glVertex3i(x,0,i);

glVertex3i(i,0,x);
                glVertex3i(i,0,-x);
            }
    glEnd();

//生成球体
    GLUquadricObj * pObj;
    pObj = gluNewQuadric();
    gluQuadricDrawStyle(pObj,GLU_LINE);
    gluQuadricNormals(pObj,GLU_SMOOTH);
    gluSphere(pObj,16,16,16);

QT范例源代码
glwidget.h
#ifndef glwidget_H_
#define glwidget_H_
#include <QtGui/QtGui>
#include <QtOpenGL/QtOpenGL>

class GLWidget : public QGLWidget
{
    Q_OBJECT
public:
    GLWidget();
protected:
    void initializeGL();
    void paintGL();
    void resizeGL(int width,int height);

void mousePressEvent(QMouseEvent *ev);
    void mouseMoveEvent(QMouseEvent *ev);
    void mouseDoubleClickEvent(QMouseEvent *ev);
    void wheelEvent(QWheelEvent *ev);
private:
    QPoint lastPos;
    GLfloat eyeX,eyeY,eyeZ;
};
#endif

glwidget.cpp
#include "glwidget.h"

GLWidget::GLWidget()
:QGLWidget()
{
    setGeometry(300,300,600,480);
    setWindowTitle(tr("glulookat test"));
}

void GLWidget::initializeGL()
{
    glShadeModel(GL_SMOOTH);
    glClearColor(0.5,0.5,0.5,0.5);
    glClearDepth(1.0);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LEQUAL);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
   
    eyeX = 0.0;
    eyeY = 80.0;
    eyeZ = 0.0;
}

void GLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    //gluLookAt(9.0,0.0,10.0,0.0,0.0,-10.0,0.0,1.0,0.0);
    //to look at the second lines
    gluLookAt(eyeX,eyeY,eyeZ,0.0,0.0,0.0,1.0,0.0,0.0);

//glTranslatef(0.0,0.0,-10.0);
    /*glBegin(GL_TRIANGLES);
        glColor3f(1.0,0.0,0.0);
        glVertex3f(0.0,1.0,0.0);
        glVertex3f(-1.0,0.0,0.0);
        glVertex3f(1.0,0.0,0.0);
    glEnd();*/

glColor3f(0.5f,0.7f,1.0f);
    //glBegin(GL_LINES);
    //    for(int i = -1000;i <= 1000;i+=10)
    //    {
    //        glVertex3f(0.0,0.0,i);
    //        glVertex3f(10.0,10.0,i);
    //        glVertex3f(0.0,0.0,i);
    //        glVertex3f(-10.0,10.0,i);
    //    }
    //glEnd();
    int x = (int)(40*2);
    glBegin(GL_LINES);
        for(int i = -x ;i <= x ; i+=4 )
        {
            glVertex3i(-x,0,i);
            glVertex3i(x,0,i);

glVertex3i(i,0,x);
            glVertex3i(i,0,-x);
        }
    glEnd();
    GLUquadricObj *pObj;
    pObj = gluNewQuadric();
    gluQuadricDrawStyle(pObj,GLU_LINE);
    gluQuadricNormals(pObj,GLU_SMOOTH);
    gluSphere(pObj,16,16,16);
}

void GLWidget::resizeGL(int width,int height)
{
    if(height == 0)
        height = 1;
    glViewport(0,0,width,height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0,(GLfloat)width/(GLfloat)height,0.1,3000.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

}

void GLWidget::mousePressEvent(QMouseEvent *ev)
{
    if(ev->buttons() & Qt::LeftButton)
    {
        lastPos = ev->pos();
    }
}

void GLWidget::mouseMoveEvent(QMouseEvent *ev)
{
    if(ev->buttons() & Qt::LeftButton)
    {
        QPoint pt = ev->pos() - lastPos;
        if(eyeY >= 3000.0 && pt.y() > 0)
        {
            return ;
        }
        if(eyeY <= 1.0 && pt.y() < 0)
            return ;
        eyeY += pt.y();
        updateGL();
    }   
}

void GLWidget::mouseDoubleClickEvent(QMouseEvent *ev)
{
    QString str = QString("X:%1-Y:%2-Z:%3").arg(eyeX).arg(eyeY).arg(eyeZ);
    QMessageBox::information(this,str,str);
}

void GLWidget::wheelEvent(QWheelEvent *ev)
{
    QString str = QString("delta: %1").arg(ev->delta());
    //QMessageBox::information(this,str,str);
}

运行结果:

 
 
 
 

gluPerspective和gluLookAt的关系的更多相关文章

  1. OpenGL的gluPerspective和gluLookAt的关系[转]

    函数原型void gluLookAt(GLdoble eyex, GLdouble eyey, GLdouble eyez,  GLdouble centerx, GLdouble centery, ...

  2. 再议gluPerspective和gluLookAt的关系

    http://www.cnblogs.com/chengmin/archive/2011/09/12/2174004.html 看了Opengl的相关程序,发现有些东西还是特别迷茫,尤其是gluLoo ...

  3. OpenGL(六) gluLookAt和gluPerspective函数解析

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

  4. OpenGl从零开始之坐标变换

    http://www.tuicool.com/articles/uiayYrI OpenGL学习脚印: 坐标变换过程(vertex transformation) http://blog.csdn.n ...

  5. 【OpenGL】画立方体

    编写一个程序,该程序运行时可以用鼠标的一个按键调整立方体的方向,用另一个按键平移立方体,用第三个按键缩放立方体. 这是题目,我的程序不一定完全按照这个来.初学OpenGL,对那一堆坐标系表示十分混乱, ...

  6. 【翻译】 View Frustum Culling --1 View Frustum’s Shape

    这是一些列来自lighthouse3d的视锥体裁剪教程.旨在学习总结,及便于查阅. 1.视锥体的形状 在OpenGL中,透视投影是由两个函数定义的gluPerspective和gluLookAt.我们 ...

  7. OpenGL学习进程(5)第三课:视口与裁剪区域

    本节是OpenGL学习的第三个课时,下面介绍如何运用显示窗体的视口和裁剪区域:     (1)知识点引入:     1)问题现象: 当在窗体中绘制图形后,拉伸窗体图形形状会发生变化: #include ...

  8. OpenGL(十二) 纹理映射(贴图)

    OpenGL绘制纹理的步骤: 1. 开启纹理功能 使用glEnable(GL_TEXTURE_2D)开启2D纹理功能,使用glDisable(GL_TEXTURE_2D)关闭纹理,默认情况下纹理是关闭 ...

  9. CS184.1X 计算机图形学导论(第五讲)

    一.观察:正交投影 1.特性:保持平行线在投影后仍然是平行的 2.一个长方体,对处在只有深度不同的位置上的同一物体来说,它的大小不会改变. 3.透视投影:平行线在远处会相交(例如铁轨) 4.glOrt ...

随机推荐

  1. Twilio介绍和使用

    1.Twilio是?需要如何才能通过Twilio打国际网络电话 http://uuxn.com/twilio-toll-free-sms介绍了通过网页来收取和发送信息 需求:通过TWILIO拨打国外座 ...

  2. vue 所有的路由跳转加一个统一参数

    需求是什么 所有的路由跳转加一个统一的参数 实现方式 先深入理解一下router的全局前置守卫 router.beforeEach((to, from, next) => { const que ...

  3. js+css实现全局loading加载

    js var Mask = function() { //定义一个Mask对象 this.btn = ["取消", "确定"], this.init = fun ...

  4. luogu P3396 哈希冲突(分块?)

    我们可以维护一个\(f[i][j]\)代表%\(i\)意义下得\(j\)的答案.然后维护就炸了. 先设\(x=\sqrt{n}\)然后我们发现,当\(i>x\)时我们直接暴力复杂度为\(O(x) ...

  5. 紫书 习题 8-13 UVa 10570 (枚举+贪心)

    我看到数据范围只有500, 第一反应枚举所有的可能,然后求出每种可能的最小次数. 但是不知道怎么求最小次数.我想的是尽量让一次交换可以让两个不在应该在的位置的数字 到原来应该在的位置的数字, 这样可以 ...

  6. NIO框架之MINA源代码解析(一):背景

     "你们的agent占了好多系统的port.把我们的非常多业务系统都给整死了,给我们造成了非常大的损失.要求你们的相关领导下周过来道歉"   --   来自我们的一个客户.   ...

  7. HttpClient 图讲解明

    大家刚看这个名字一定会想问这是什么东东,在这我特意百度百科了下 HTTP 协议可能是如今 Internet 上使用得最多.最重要的协议了,越来越多的 Java 应用程序须要直接通过 HTTP 协议来訪 ...

  8. HDU 1789 Doing Homework again【贪心】

    题意:给出n个作业的截止时间,和该作业没有完成会被扣掉的分数.问最少会被扣掉多少分. 第一次做这一题是好久之前,当时不会(不会处理两个关键字关系@_@)---现在还是不会---看了题解---原来是这样 ...

  9. 函数式JS: 原来promise是这样的monad

    转载请注明出处: http://hai.li/2017/03/27/prom... 背景 上篇文章 函数式JS: 一种continuation monad推导 得到了一个类似promise的链式调用, ...

  10. Bomb HDU - 3555 数位dp

    Code: #include<cstdio> #include<algorithm> #include<cstring> #include<string> ...