Qt Examples - Boxes (在Qt場景視圖中結合OpenGL渲染)


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命令代碼如下:

 C++ Code 
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場景。各層繪制順序:背景層-圖元層-前景層

 C++ Code 
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();

 

類圖:


免責聲明!

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



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