OpenGL_Qt學習筆記之_04(3D圖形的繪制和旋轉)


 

     繪制四棱錐

     四棱錐由5個面構成一個封閉的立體圖,其中4個共頂點的側面是三角形,底面是個四邊形。如果我們要繪制一個3D的四棱錐只需要繪制這5個面即可,繪制的方法和前一篇文章OpenGL_Qt學習筆記之_03(平面圖形的着色和旋轉)的相同。只不過這里的頂點坐標是3維的,所以圖像深度那一維不一定為0。因此我們可以事先計算好四棱錐各個頂點的坐標,這對學過立體幾何的人來說應該是小case了。然后繪制每個面就可以。

     注意,在opengl中繪制每個面時,所有面給出的頂點的順序都要按照逆時針或者順時針(我這里采用的是逆時針),這樣才能保證所繪制出來的圖像時正確的。

     現在我們在paintGL中開始繪制四棱錐,如果按照NeHe的教程,它只是繪制了個金字塔,並沒有底面,只有4個側面,這里,我采用它的方法,代碼如下: 

/*下面開始畫四棱錐*/
    glLoadIdentity();//重置當前的模型觀察矩陣

    glTranslatef(-0.5, 0.0, -0.5);//將繪制平面移動到屏幕的左半平面和里面

    glRotatef(x_rotate, 0.2, 0.2, 0.0);

    glBegin(GL_TRIANGLES);

    /*前正面的繪制*/

    glColor3f(1.0, 0.0, 0.0);//上頂點紅色

    glVertex3f(0.0, 0.3, 0.0);

    glColor3f(0.0, 0.0, 1.0);//左下點藍色

    glVertex3f(-0.3, -0.3, 0.3);

    glColor3f(0.0, 1.0, 0.0);//右下角綠色

    glVertex3f(0.3, -0.3, 0.3);

    /*右側面的繪制*/

    glColor3f(1.0, 0.0, 0.0);//上頂點紅色

    glVertex3f(0.0, 0.3, 0.0);

    glColor3f(0.0, 0.0, 1.0);//左下點藍色

    glVertex3f(0.3, -0.3, 0.3);

    glColor3f(0.0, 1.0, 0.0);//右下角綠色

    glVertex3f(0.3, -0.3, -0.3);

    /*后側面的繪制*/

    glColor3f(1.0, 0.0, 0.0);//上頂點紅色

    glVertex3f(0.0, 0.3, 0.0);

    glColor3f(0.0, 0.0, 1.0);//左下點藍色

    glVertex3f(0.3, -0.3, -0.3);

    glColor3f(0.0, 1.0, 0.0);//右下角綠色

    glVertex3f(-0.3, -0.3, -0.3);

    /*左側面的繪制*/

    glColor3f(1.0, 0.0, 0.0);//上頂點紅色

    glVertex3f(0.0, 0.3, 0.0);

    glColor3f(0.0, 0.0, 1.0);//左下點藍色

    glVertex3f(-0.3, -0.3, -0.3);

    glColor3f(0.0, 1.0, 0.0);//右下角綠色

    glVertex3f(-0.3, -0.3, 0.3);

    x_rotate_angle1 += 3.0;

glEnd();

 

  在繪制完金子塔后,把它沿某一個方向旋轉后如下圖所示:

  

 

  如果我們在后面加上代碼,把底面補全,畫上一個四邊形,此時加入的代碼如下:

 /*底面四邊形的繪制,使四棱錐封閉起來*/

    glBegin(GL_QUADS);

    glColor3f(0.0, 0.0, 1.0);//上頂點紅色

    glVertex3f(-0.3, -0.3, 0.3);

    glColor3f(0.0, 1.0, 0.0);//左下點藍色

    glVertex3f(0.3, -0.3, 0.3);

    glColor3f(0.0, 0.0, 1.0);//右下角綠色

    glVertex3f(0.3, -0.3, -0.3);

    glColor3f(0.0, 1.0, 0.0);

    glVertex3f(-0.3, -0.3, -0.3);

glEnd();

 

  這時候的結果如下:

  

 

  繪制立方體

  繪制立方體的方法和四棱錐的方法類似,只不過這里是由6個正方形構成的封閉體,我們依次繪制出每個面即可,同樣要注意的是繪制每個面時給出點的順序要一致,繪制每個面的順序倒不需要按照什么逆時針或者順時針,什么順序都行。

  計算好正方體的8個頂點坐標后就開始寫代碼了,代碼如下:

/*下面開始畫立方體*/

    glLoadIdentity();

    glTranslated(0.5, 0, 0.5);//將繪制平面移動到屏幕的右半平面和外面

    glRotatef(rotate_angle2, -0.2, 0.2, -0.3);

    glBegin(GL_QUADS);

    //上頂面

    glColor3f(0.0, 1.0, 0.0);

    glVertex3f(-0.3, 0.3, -0.3);

    glVertex3f(-0.3, 0.3, 0.3);

    glVertex3f(0.3, 0.3, 0.3);

    glVertex3f(0.3, 0.3, -0.3);

    //下頂面

    glColor3f(0.0, 1.0, 0.0);

    glVertex3f(-0.3, -0.3, -0.3);

    glVertex3f(-0.3, -0.3, 0.3);

    glVertex3f(0.3, -0.3, 0.3);

    glVertex3f(0.3, -0.3, -0.3);

    //正前面

    glColor3f(1.0, 0.0, 0.0);

    glVertex3f(-0.3, 0.3, 0.3);

    glVertex3f(-0.3, -0.3, 0.3);

    glVertex3f(0.3, -0.3, 0.3);

    glVertex3f(0.3, 0.3, 0.3);

    //右側面

    glColor3f(1.0, 1.0, 0.0);

    glVertex3f(0.3, 0.3, 0.3);

    glVertex3f(0.3, -0.3, 0.3);

    glVertex3f(0.3, -0.3, -0.3);

    glVertex3f(0.3, 0.3, -0.3);

    //背后面

    glColor3f(0.0, 1.0, 1.0);

    glVertex3f(-0.3, 0.3, -0.3);

    glVertex3f(0.3, 0.3, -0.3);

    glVertex3f(0.3, -0.3, -0.3);

    glVertex3f(-0.3, -0.3, -0.3);

    //左側面

    glColor3f(1.0, 0.0, 1.0);

    glVertex3f(-0.3, 0.3, -0.3);

    glVertex3f(-0.3, -0.3, -0.3);

    glVertex3f(-0.3, -0.3, 0.3);

    glVertex3f(-0.3, 0.3, 0.3);

    rotate_angle2 -= 3;

glEnd();

 

  其效果如下:

   

 

  當兩者放在一起,且經過不同軸的旋轉后圖像如下:

  

 

  實驗主要部分代碼如下(附錄有工程code下載地址):

#include "glwidget.h"
#include "ui_glwidget.h"

#include <QtGui>
#include <QtCore>
#include <QtOpenGL>

GLWidget::GLWidget(QGLWidget *parent) :
    QGLWidget(parent),
    ui(new Ui::GLWidget)
{
  //  setCaption("The Opengl for Qt Framework");
    ui->setupUi(this);
    fullscreen = false;
    rotate_angle1 = 0.0;
    rotate_angle2 = 0.0;
}

//這是對虛函數,這里是重寫該函數
void GLWidget::initializeGL()
{
    setGeometry(300, 150, 640, 480);//設置窗口初始位置和大小
    glShadeModel(GL_SMOOTH);//設置陰影平滑模式
    glClearColor(0.0, 0.0, 0.0, 0);//改變窗口的背景顏色,不過我這里貌似設置后並沒有什么效果
    glClearDepth(1.0);//設置深度緩存
    glEnable(GL_DEPTH_TEST);//允許深度測試
    glDepthFunc(GL_LEQUAL);//設置深度測試類型
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);//進行透視校正
}

void GLWidget::paintGL()
{
    //glClear()函數在這里就是對initializeGL()函數中設置的顏色和緩存深度等起作用
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    /*下面開始畫四棱錐*/
    glLoadIdentity();//重置當前的模型觀察矩陣
    glTranslatef(-0.5, 0.0, -0.5);//將繪制平面移動到屏幕的左半平面和里面
    glRotatef(rotate_angle1, 0.2, 0.2, 0.0);
    glBegin(GL_TRIANGLES);
    /*前正面的繪制*/
    glColor3f(1.0, 0.0, 0.0);//上頂點紅色
    glVertex3f(0.0, 0.3, 0.0);
    glColor3f(0.0, 0.0, 1.0);//左下點藍色
    glVertex3f(-0.3, -0.3, 0.3);
    glColor3f(0.0, 1.0, 0.0);//右下角綠色
    glVertex3f(0.3, -0.3, 0.3);
    /*右側面的繪制*/
    glColor3f(1.0, 0.0, 0.0);//上頂點紅色
    glVertex3f(0.0, 0.3, 0.0);
    glColor3f(0.0, 0.0, 1.0);//左下點藍色
    glVertex3f(0.3, -0.3, 0.3);
    glColor3f(0.0, 1.0, 0.0);//右下角綠色
    glVertex3f(0.3, -0.3, -0.3);
    /*后側面的繪制*/
    glColor3f(1.0, 0.0, 0.0);//上頂點紅色
    glVertex3f(0.0, 0.3, 0.0);
    glColor3f(0.0, 0.0, 1.0);//左下點藍色
    glVertex3f(0.3, -0.3, -0.3);
    glColor3f(0.0, 1.0, 0.0);//右下角綠色
    glVertex3f(-0.3, -0.3, -0.3);
    /*左側面的繪制*/
    glColor3f(1.0, 0.0, 0.0);//上頂點紅色
    glVertex3f(0.0, 0.3, 0.0);
    glColor3f(0.0, 0.0, 1.0);//左下點藍色
    glVertex3f(-0.3, -0.3, -0.3);
    glColor3f(0.0, 1.0, 0.0);//右下角綠色
    glVertex3f(-0.3, -0.3, 0.3);
    rotate_angle1 += 3.0;
    glEnd();
    /*底面四邊形的繪制,使四棱錐封閉起來*/
    glBegin(GL_QUADS);
    glColor3f(0.0, 0.0, 1.0);//上頂點紅色
    glVertex3f(-0.3, -0.3, 0.3);
    glColor3f(0.0, 1.0, 0.0);//左下點藍色
    glVertex3f(0.3, -0.3, 0.3);
    glColor3f(0.0, 0.0, 1.0);//右下角綠色
    glVertex3f(0.3, -0.3, -0.3);
    glColor3f(0.0, 1.0, 0.0);
    glVertex3f(-0.3, -0.3, -0.3);
    glEnd();

    /*下面開始畫立方體*/
    glLoadIdentity();
    glTranslated(0.5, 0, 0.5);//將繪制平面移動到屏幕的右半平面和外面
    glRotatef(rotate_angle2, -0.2, 0.2, -0.3);
    glBegin(GL_QUADS);
    //上頂面
    glColor3f(0.0, 1.0, 0.0);
    glVertex3f(-0.3, 0.3, -0.3);
    glVertex3f(-0.3, 0.3, 0.3);
    glVertex3f(0.3, 0.3, 0.3);
    glVertex3f(0.3, 0.3, -0.3);
    //下頂面
    glColor3f(0.0, 1.0, 0.0);
    glVertex3f(-0.3, -0.3, -0.3);
    glVertex3f(-0.3, -0.3, 0.3);
    glVertex3f(0.3, -0.3, 0.3);
    glVertex3f(0.3, -0.3, -0.3);
    //正前面
    glColor3f(1.0, 0.0, 0.0);
    glVertex3f(-0.3, 0.3, 0.3);
    glVertex3f(-0.3, -0.3, 0.3);
    glVertex3f(0.3, -0.3, 0.3);
    glVertex3f(0.3, 0.3, 0.3);
    //右側面
    glColor3f(1.0, 1.0, 0.0);
    glVertex3f(0.3, 0.3, 0.3);
    glVertex3f(0.3, -0.3, 0.3);
    glVertex3f(0.3, -0.3, -0.3);
    glVertex3f(0.3, 0.3, -0.3);
    //背后面
    glColor3f(0.0, 1.0, 1.0);
    glVertex3f(-0.3, 0.3, -0.3);
    glVertex3f(0.3, 0.3, -0.3);
    glVertex3f(0.3, -0.3, -0.3);
    glVertex3f(-0.3, -0.3, -0.3);
    //左側面
    glColor3f(1.0, 0.0, 1.0);
    glVertex3f(-0.3, 0.3, -0.3);
    glVertex3f(-0.3, -0.3, -0.3);
    glVertex3f(-0.3, -0.3, 0.3);
    glVertex3f(-0.3, 0.3, 0.3);
    rotate_angle2 -= 3;
    glEnd();
}

//該程序是設置opengl場景透視圖,程序中至少被執行一次(程序啟動時).
void GLWidget::resizeGL(int width, int height)
{
    if(0 == height)
        height = 1;//防止一條邊為0
    glViewport(0, 0, (GLint)width, (GLint)height);//重置當前視口,本身不是重置窗口的,只不過是這里被Qt給封裝好了
    glMatrixMode(GL_PROJECTION);//選擇投影矩陣
    glLoadIdentity();//重置選擇好的投影矩陣
   // gluPerspective(45.0, (GLfloat)width/(GLfloat)height, 0.1, 100.0);//建立透視投影矩陣
    glMatrixMode(GL_MODELVIEW);//以下2句和上面出現的解釋一樣

    glLoadIdentity();


}
void GLWidget::keyPressEvent(QKeyEvent *e)
{
    switch(e->key())
    {
        //F1鍵為全屏和普通屏顯示切換鍵
        case Qt::Key_F1:
            fullscreen = !fullscreen;
            if(fullscreen)
                showFullScreen();
            else
            {
                setGeometry(300, 150, 640, 480);
                showNormal();
            }
            updateGL();
            break;
        //Ese為退出程序鍵
        case Qt::Key_Escape:
            close();
    }
}

GLWidget::~GLWidget()
{
    delete ui;
}

 

  總結:本文在前面文章繪制2D圖像和旋轉的基礎上,增加一維的坐標就可以繪制出3D圖形即旋轉了。在畫3D圖時,必須將OpenGL屏幕想象成一張很大的畫紙,后面還帶着許多透明的層。差不多就是個由大量的點組成的立方體。這些點從左至右、從上至下、從前到后的布滿了這個3D圖的表面。

 

  參考資料:

  http://nehe.gamedev.net/ 

  http://www.owlei.com/DancingWind/

  http://www.qiliang.net/old/nehe_qt/

 

  附錄:

  實驗工程code下載

 

 

 

 


免責聲明!

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



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