zoukankan      html  css  js  c++  java
  • gluPerspective和gluLookAt的关系

    参考文章 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运行效果如下图

    GL学习笔记(2) - 终于搞明白gluPerspective和gluLookAt的关系了(zz) - cowboy小屋 - cowboy小屋的博客

    上图证实了我们的推测












    //---------------------------------------------
        //生成网络
        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);
    }

    运行结果:

    GL学习笔记(2) - 终于搞明白gluPerspective和gluLookAt的关系了(zz) - cowboy小屋 - cowboy小屋的博客
     
     
     
     
  • 相关阅读:
    修复PLSQL Developer 与 Office 2010的集成导出Excel 功能
    Using svn in CLI with Batch
    mysql 备份数据库 mysqldump
    Red Hat 5.8 CentOS 6.5 共用 输入法
    HP 4411s Install Red Hat Enterprise Linux 5.8) Wireless Driver
    变更RHEL(Red Hat Enterprise Linux 5.8)更新源使之自动更新
    RedHat 5.6 问题简记
    Weblogic 9.2和10.3 改密码 一站完成
    ExtJS Tab里放Grid高度自适应问题,官方Perfect方案。
    文件和目录之utime函数
  • 原文地址:https://www.cnblogs.com/arxive/p/7001530.html
Copyright © 2011-2022 走看看