QT自帶例程Boxes使用QT Graphics View框架實現了2D圖形和3D圖形的混合渲染,綜合性比較強,整合知識較多,值得學習。
- 可以使用鼠標通過以下方式控制演示中的元素:
- 按住鼠標左鍵的同時拖動鼠標可以旋轉中心的Box。
- 按住鼠標右鍵的同時拖動鼠標會旋轉衛星箱。
- 按住鼠標滾輪的同時拖動鼠標會旋轉整個3D背景層。
- 滾動鼠標滾輪可放大和縮小場景。
選項窗格可用於微調Demo中的各種參數,包括顏色和像素着色器
原始的在Widget中繪圖通過重寫paintEvent繪圖響應函數,在其中使用QPainter來繪制。
存在問題:
1、 支持更多的圖形時函數體會很長
2、 移動操作圖形時會很費勁
Graphics View基本架構
Graphics View設計為管理大量2D圖形,每一個2D圖形都是一個item,其類為QGraphicsItem,QT內置了橢圓、矩形、直線、路徑、圖像、多邊形和文本等基本item,可以通過派生QGraphicsItem來實現自定義的item,需要重寫boundingRect以及paint函數。
QGraphicsScene場景類包含所有的items,並且充當了一個view與items之間的接口橋梁。其擁有所有的圖形item,可以傳播繪制事件以及其他鼠標事件,而且提供了定位和管理圖形item的各種方便的方法。
場景初始化:
QGraphicsScene *scene = new QGraphicsScene(this);
scene->setSceneRect(-100, -100, 201, 201);
場景中添加圖形item:
QGraphicsItem *item = scene->addRect(20, 20, 60, 60,
QPen(Qt::red, 3),
QBrush(Qt::green));
QGraphicsView視圖類widget充當了顯示一個場景(場景是虛擬的)的視口。
QGraphicsView *view = new QGraphicsView();
QGraphicsScene *scene = setupScene();
view->setScene(scene);
為了能在場景中添加QT基本的圖形組件(如PushButton、LineEdit等),QT提供了QGraphicsWidget類,為了進一步能使得圖形item使用信號-槽的功能,QT又提供了QGraphicsObject類,非常的全面周到。
QGraphicsProxyWidget *button = scene->addWidget(new QPushButton(tr("Click me!")));
button->setPos(20, -30);
圖形項item交互操作
圖形項item的flags控制着它們如何可以與之互動
- ItemIsMovable - 一個方便的功能,原始鼠標事件方法讓用戶拖動
- ItemIsSelectable - 使用setSelected和QGraphicsScene :: setSelectionArea方法選擇
- ItemIsFocusable - 獲取鍵盤焦點
場景通過BSP樹管理圖形項item,二進制空間分區樹存儲圖形項於一棵樹中,主要取決於它們在空間的位置。
繪制各種2D圖形項
OpenGL渲染
為了使用OpenGL渲染場景,需要更改view的視口widget:
QGraphicsView *view = new QGraphicsView();
view->setViewport(new QGLWidget);
繪制3D圖形項
一般地,圖形項的繪制時在paint函數中使用QPainter來繪制,QPainer是繪制2D圖形的類,而想繪制3D圖形則需要使用OpenGL API,同樣滴,在paint中是OpenGL命令代碼如下:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
class
MyItem :
public
QGraphicsItem { public : MyItem( QGraphicsItem *parent = 0 ) : QGraphicsItem(parent), w( 200 ), h( 200 ) {} void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { painter->drawRect(boundingRect()); painter->beginNativePainting(); /* Reset The Current Viewport And Perspective Transformation */ glViewport( 20 , 20 , w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective( 45 .0f, (GLfloat)w / (GLfloat)h, 0 .1f, 100 .0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef( 0 .0f , 0 .0f, - 6 .0f); glBegin(GL_TRIANGLES); glVertex3f( 0 .0f, 1 .0f, 0 .0f); glVertex3f(- 1 .0f, - 1 .0f, 0 .0f); glVertex3f( 1 .0f, - 1 .0f, 0 .0f); glEnd(); painter->endNativePainting(); } QRectF boundingRect () const { return QRectF( 20 , 20 , w, h); } private : int w, h; }; |
繪制3D場景
QGraphicsScene類提供了三個層面:背景層、圖元層和前景層。上面2D圖形項的繪制都是在圖元層,是一個2D場景,如果我們想要實現一個3D場景,則可以在背景或前景層使用OpenGL命令,而底層是3D場景,上面是2D場景的情況很類似於我們玩網絡游戲的情景,所以常在背景層繪制3D場景。各層繪制順序:背景層-圖元層-前景層
1
2 3 4 5 6 |
void
QGraphicsScene::drawBackground(QPainter *painter,
const
QRectF &rect) { painter->beginNativePainting(); // do opengl draw… painter->endNativePainting(); } |
Box例程學習:
在Windows上安裝的QT版本在build該例程時會出現錯誤,提示缺少opengl-desktop版本的支持,這是由於windows的發布版本QT沒有使用該選項(只能重新編譯QT源代碼了),而linux版本使用了該選項可以正常構建運行。
Qt Graphics View + OpenGL Render:
QGLWidget *widget = new QGLWidget(QGLFormat(QGL::SampleBuffers));
widget->makeCurrent();
Scene scene(1024, 768, maxTextureSize);
GraphicsView view;
view.setViewport(widget);
view.setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
view.setScene(&scene);
view.show();
類圖: