QML UI over OpenGL
I'm pretty new to QML and QtQuick, and I would like to create a simple UI over my OpenGL scene.
I have read the [url=http://qt-project.org/doc/qt-5/qtquick-scenegraph-openglunderqml-example.html]Scene Graph - OpenGL Under QML[/url] example, and this is exactly the effect I am after; however, I have already coded my OpenGL scene following the [url=http://qt-project.org/doc/qt-5/qtgui-openglwindow-example.html]OpenGL Window Example[/url], using almost the exact same openglwindow class.
Now, my issue is that the two examples use rather different approaches to rendering OpenGL (the Scene Graph example does it within the QQuickView instance, and actually renders OpenGL below QML, while I want to render QML over OpenGL), and I would like to know if I can overlay a QQuickView or similar over my OpenGL scene.
The best I could manage so far, is one of two situations:
- the UI is below the OpenGL scene, with focus on the UI ([url=https://dl.dropbox.com/s/skuf21m8t5lfpst/Screenshot_2014-07-12-18-12-36.png]screenshot[/url])
- the UI is over the scene, with focus on the scene ([url=https://dl.dropbox.com/s/oynow3rbkbrsrs4/Screenshot_2014-07-12-18-13-03.png]screenshot[/url])
You will have noticed I'm developing this app for Android; running it on my PC results in the cube and UI being in separate windows, which both respond correctly to mouse input.
Here is how I call the scene and the UI:
@RubiksGL *oglView = new RubiksGL;
This code results in the 1st situation (UI below the scene, and has focus).
Calling gui.show() before oglView->show() results in the 2nd situation.
My KQuickView class simply extends QQuickView and does the following in its constructor:
RubiksGL *oglView = new RubiksGL;
connect(this, SIGNAL(beforeRendering()), oglView, SLOT(renderNow()), Qt::DirectConnection);
(Actually, I just noticed I was doing some weird stuff, since I'm creating a RubiksGL instance in both the main and the KQuickView... though the program crashes when I try to have only one, with the following error: "kernel\qopenglcontext.cpp:796 (bool QOpenGLContext::makeCurrent(QSurface*)): Cannot make QOpenGLContext current in a different thread" and "Fatal signal 11 (SIGSEGV) at 0xdeadbaad (code=1), thread 26971 (QSGRenderThread)")
Errors aside, could anyone point me in the right direction to get a QML overlay on top of my OpenGL scene, as opposed to an OpenGL "underlay" below a QML UI?
After some research, I considered 2 ways to achieve the result I want:
- rendering the OpenGL scene to an FBO, and displaying that below the QML UI
- Following [url=https://www.youtube.com/watch?v=GYa5DLV6ADQ]this video[/url] by Sean Hammer
I followed the 2nd option, and got it working.
Now of course, my UI view "steals" all the mouse/touch events, which I'll have to propagate to my OpenGL scene.
The only issue remaining is a warning I get when rendering my OpenGL scene:
@W/Qt ( 3975): kernel\qobject.cpp:777 (bool check_parent_thread(QObject*, QThreadData*, QThreadData*)): QObject: Cannot create children for a parent that is in a different thread.
W/Qt ( 3975): (Parent is RubiksGL(0x6003b3a8), parent's thread is QThread(0x5cb65e48), current thread is QSGRenderThread(0x5cb39758)@
I made sure that I added Qt::DirectionConnection to my connection between the beforeRendering() signal and the rendering slot, so I'm not sure where the threads are different.
The only thing I know is it happens inside my OpenGL rendering function, which looks like this:
m_funcs->glViewport(0, 0, width(), height());
m_funcs->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_program->bind(); moveCamera(); computeViewProjectionMatrices(); drawObjects(); m_program->release();
drawObjects does the following:
for (int i=0; i<m_objectsList.size(); i++)
object = m_objectsList.at(i);
matrix = m_VPMatrix * object->transform();
vao = new QOpenGLVertexArrayObject(this); vao->create(); vao->bind(); std::vector<QVector3D> vertices = object->vertices(); std::vector<QVector3D> colors = object->colors(); m_verticesVBO.bind(); m_verticesVBO.allocate(&vertices, vertices.size() * sizeof(QVector3D)); m_colorsVBO.bind(); m_colorsVBO.allocate(&colors, colors.size() * sizeof(QVector3D)); m_funcs->glEnableVertexAttribArray(0); m_verticesVBO.bind(); m_funcs->glVertexAttribPointer(m_posAttr, 3, GL_FLOAT, GL_FALSE, 0, NULL); m_funcs->glEnableVertexAttribArray(1); m_colorsVBO.bind(); m_funcs->glVertexAttribPointer(m_colAttr, 3, GL_FLOAT, GL_FALSE, 0, NULL); m_funcs->glDrawArrays(GL_TRIANGLES, 0, vertices.size()); m_funcs->glDisableVertexAttribArray(1); m_funcs->glDisableVertexAttribArray(0); m_verticesVBO.release(); m_colorsVBO.release(); vao->release(); delete vao; }@
I know my usage of VAOs and VBOs is not correct (I should move them to my initialize() function), that is something I'll fix later.
The warning above is issued for each glDrawArrays call.
Is there something I missed regarding threads, either between the QQuickView and OpenGL, or directly within my rendering function?