• 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小屋的博客
     
     
     
     
  • 相关阅读:
    java中间件
    JAVA 并发编程关键点
    pull类型消息中间件-消息服务端(三)
    pull类型消息中间件-消息消费者(二)
    pull类型消息中间件-消息发布者(一)
    push类型消息中间件-消息服务端(三)
    push类型消息中间件-消息发布者(二)
    push类型消息中间件-消息订阅者(一)
    RPC框架基本原理(三):调用链路分析
    JAVA包装类
  • 原文地址:https://www.cnblogs.com/arxive/p/7001530.html
Copyright © 2020-2023  润新知