基於Qt的軌跡還原之二:用QGLWidget實現功能

上節講到六種選擇,最終確定了QGLWidget,理由如下:


在Qt裏直接寫OpenGL基於官方glut的原始語法行不通,也沒有必要,因爲Qt5.0之後對OpenGL作了很好的支持,並且形成了自己的規則,成爲Qt內部的一分子。所以拋棄OpenGL(glut)的想法。但值得注意的是:OpenGL渲染的原理是不變的,要想出色完成3D繪圖,必須首先自學OpenGL的原理和基本寫法。


QOpenGLwidget是Qt5.4之後出現的支持OpenGL的新類。雖然它有優點,比如它通過避免創建獨立的本機窗口避免一些潛在風險,但是實現功能變化不大,基本繼承了QGLWidget。它的缺點在於,可用的開發文檔較少,很多coder在使用過程中也經常出現這樣或那樣的問題,由於寫法有很多改動,所以基本處在初期探索階段。基於以上考慮,我們最終拋棄了這種想法。


Qwt3dplot事實上是一個非常強大的基於Qt開發的開源3D圖形庫,儘管它有很長時間沒有更新了,但是已經足夠完美。然而,它的強大主要體現在渲染數學立體圖形和曲面,對於散點支持較少,我沒有發現足夠可用的API接口,而且基於開源庫實現項目的難點在於需要花大量時間閱讀開發文檔,而且自己發揮空間不大,後期如果要大幅修改,也會感到力不從心,往往找不到對應的功能實現。


最後兩個是非常專業的3D圖形軟件,一般用來開發機械製圖等大型軟件。正因爲他們的龐雜,所以在沒有指導的情況下很難下手,學習困難較多。而且放在我們項目中,不免讓人生出“殺雞焉用牛刀”的感慨。


最終確定了使用QGLWidget來實現可交互的基於散點繪製三維曲線的想法。


雖然GL前加了一個Q字,讓人感覺QGLWidget就是一個簡單的Qt類,照着幫助文檔裏的類說明寫寫方法就可以了,然而事實卻遠沒有這麼簡單。Qt文檔裏只是介紹了類成員函數的聲明,而成員函數的實現則完全由開發者自行發揮,事實上要求開發者首先是一個精通OpenGL的人。因此,不可避免地,我們需要學習OpenGL的基礎理論知識和基本方法。項目中需要熟練掌握的是“頂點處理管線”和“着色模型”。

關於學習OpenGL,推薦下面的網站

OpenGL原理學習


在學習了OpenGL的基礎理論並加以練習後,剩下的工作變得簡單。
我們可以派生QGLWidget類,QGLWidget提供三個方便的虛函數,我們可以在子類中重寫他們,來完成一些典型的OpenGL任務:
1、paintGL()函數:繪製OpenGL圖像,當窗口需要被刷新時候被調用
2、resizeGL()函數,建立OpenGL的視圖窗口等一系列,當窗口大小改變時候被調用,(當然第一次顯示時候也會被調用,因爲所有新創建的窗口都自動得到一個改變的大小的事件)
3、initializeGL()建立OpenGL繪圖的上下文環境,聲明播放列表等等,在第一次調用resizeGL()或者paintGL()調用前調用。
4、如果除了paintGL()外還需要一個繪圖的觸發器,(典型的方法是使用定時器來繪圖),我們可以調用updateGL()函數,在updateGL()會調用glDraw()來刷新窗口。


一個典型的QGLWidget子類實現框架如下:

class MyGLDrawer : public QGLWidget
{
    Q_OBJECT        // must include this if you use Qt signals/slots
public:
    MyGLDrawer(QWidget *parent)
        : QGLWidget(parent) {}
protected:
    void initializeGL()
    {
        // Set up the rendering context, define display lists etc.:
        glClearColor(0.0, 0.0, 0.0, 0.0);
        glEnable(GL_DEPTH_TEST);
    }
    void resizeGL(int w, int h)
    {
        // setup viewport, projection etc.:
        glViewport(0, 0, (GLint)w, (GLint)h);
        ...
        glFrustum(...);
    }
    void paintGL()
    {
        // draw the scene:
        glRotatef(...);
        glMaterialfv(...);
        glBegin(GL_QUADS);
        glVertex3f(...);
        glVertex3f(...);
        glEnd();
    }
};


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章