Qt+OpenGL

ここでは、Qtが用意しているOpenGL wrapperではなく、
Qtが用意したOpenGLContextに対して、glewなどにより自前の描画を行う場合の引っかかった点を書く。
描画対象は、QGraphicsScene/QGraphicsView/QGraphicsItemとする。
Qtのバージョンは4.6以降とする。

これを行うメリット

・OpenGLで描画している部分がQtに依存しない
・OpenGLで描画した上に、QPainterで描画できる。
・しかもQPainterの描画はテクスチャ上に描画されているっぽいので、
 文字を描画したとしても高速に動く。


  ↑画像の赤丸部分のように、QPainterで上から描画できる。32msってのはデバッグ版ゆえに。


デメリット

・やり方(下記)見つけ出すまでが大変。


基本(QGraphicsItemに描画する場合

// ビュー初期化時。
// ここでrendererは自前描画クラスなので気にしないように。
if (HogeGraphicView *graphicView = new HogeGraphicView(main_window->ui_main_window().mainwidget, renderer))
{
  QGLWidget *widget = new QGLWidget(QGLFormat(QGL::SampleBuffers));
  widget->makeCurrent();
  // OpenGLレンダラはコンテキストがあるときに初期化する
  renderer->init();
  graphicView->setupViewport(widget);
}

void HogeGraphicsView::setupViewport(QWidget *widget)
{
  QGLWidget *glWidget = dynamic_cast<QGLWidget*>(widget);
  if (glWidget) {
    glWidget->updateGL();
    setViewport(widget);
  }
}

// 実際に描画するところ
void HogeGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
  painter->beginNativePainting();
  // ここでOpenGL描画(※)
  painter->endNativePainting();
  // ここでQPainterでの描画
}


↑(※)のOpenGL描画では、OpenGLのステートを完璧に元に戻すこと。

特にDEPTH_BUFFERでハマった。GL_DEPTH_TESTはデフォでOFFになっている。

glDepthMask(TRUE); //念のため
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);

glClearColor(0.21f, 0.21f, 0.21f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

//ここでポリゴンなどを描画

glDisable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDepthMask(FALSE); //念のため
 



その他補足

・QGraphicsSceneはdrawForegroundでしか描けないようだ。
・QGraphicsViewはdrawForeground/drawBackgroundともに描けるようだ。
・QGraphicsItemはpaintで描けるということ以外は未調査。
・VBOとFBOが使えるのを確認した。
・VBOで、glBindBufferしたあとglBindBuffer(hoge_ARRAY_BUFFER,0)をしていなくて非常にはまった。


その他知識
・QGLViewは裏でシェーダ使っている。



OpenGLコンテキストの共有


紛らわしいことに、QGLWidgetのコンストラクタにはQGLContextを入れることもできるように書いてあるが、windowsでは動かない。
共有する場合は、QGLWidgetのコンストラクタに、parentと、共有するコンテキストを保持したビューをを突っ込む。


        // このwidgetのコンテキストを共有する
        QGLWidget *main_glwidget = NULL;

        // 共有元のビュー
        if (UMGraphicView *graphicView = new UMGraphicView(main_window->ui_main_window().mainwidget, renderer))
        {
            if (renderer->type() == IUMRenderer::TYPE_OPENGL ||
                renderer->type() == IUMRenderer::TYPE_OPENGL_FBX)
            {
                if (main_glwidget = new QGLWidget(QGLFormat(QGL::SampleBuffers), main_window->ui_main_window().mainwidget))
                {
                    main_glwidget->makeCurrent();
                    // レンダラはコンテキストがあるときに初期化
                    renderer->init();
                    graphicView->setupViewport(main_glwidget);
                }
            }
            else
            {
                renderer->init();
            }

            main_window->ui_main_window().mainlayout->addWidget(graphicView);
        }
        // 共有先のビュー
        if (UMGraphicView *graphicView = new UMGraphicView(main_window->ui_main_window().previewwidget, renderer))
        {
            if (renderer->type() == IUMRenderer::TYPE_OPENGL ||
                renderer->type() == IUMRenderer::TYPE_OPENGL_FBX)
            {
                if (main_glwidget)
                {
                    if (QGLWidget *glwidget = new QGLWidget(QGLFormat(QGL::SampleBuffers), main_window->ui_main_window().previewwidget, main_glwidget))
                    {
                        if (glwidget->isSharing())
                        {
                            // ここに来たら共有成功
                            graphicView->setupViewport(glwidget);
                        }
                    }
                }
            }

            main_window->ui_main_window().previewlayout->addWidget(graphicView);
        }


ċ
qttest.zip
(19166k)
uimac jp,
2012/06/01 8:30
Comments