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小屋的博客
 
 
 
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM