上節講到六種選擇,最終確定了QGLWidget,理由如下:
在Qt裏直接寫OpenGL基於官方glut的原始語法行不通,也沒有必要,因爲Qt5.0之後對OpenGL作了很好的支持,並且形成了自己的規則,成爲Qt內部的一分子。所以拋棄OpenGL(glut)的想法。但值得注意的是:OpenGL渲染的原理是不變的,要想出色完成3D繪圖,必須首先自學OpenGL的原理和基本寫法。
QOpenGLwidget是Qt5.4之後出現的支持OpenGL的新類。雖然它有優點,比如它通過避免創建獨立的本機窗口避免一些潛在風險,但是實現功能變化不大,基本繼承了QGLWidget。它的缺點在於,可用的開發文檔較少,很多coder在使用過程中也經常出現這樣或那樣的問題,由於寫法有很多改動,所以基本處在初期探索階段。基於以上考慮,我們最終拋棄了這種想法。
Qwt3dplot事實上是一個非常強大的基於Qt開發的開源3D圖形庫,儘管它有很長時間沒有更新了,但是已經足夠完美。然而,它的強大主要體現在渲染數學立體圖形和曲面,對於散點支持較少,我沒有發現足夠可用的API接口,而且基於開源庫實現項目的難點在於需要花大量時間閱讀開發文檔,而且自己發揮空間不大,後期如果要大幅修改,也會感到力不從心,往往找不到對應的功能實現。
最終確定了使用QGLWidget來實現可交互的基於散點繪製三維曲線的想法。
雖然GL前加了一個Q字,讓人感覺QGLWidget就是一個簡單的Qt類,照着幫助文檔裏的類說明寫寫方法就可以了,然而事實卻遠沒有這麼簡單。Qt文檔裏只是介紹了類成員函數的聲明,而成員函數的實現則完全由開發者自行發揮,事實上要求開發者首先是一個精通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();
}
};