QT5 and modern OpenGL
-
I want to use QT as a replacement of freeglut or glfw. But I am really confused because I just saw 6 different ways to use QT with OpenGL.
If I want raw performance, how would I structure my QT program?
Like this http://qt-project.org/wiki/How_to_use_OpenGL_Core_Profile_with_Qt ? -
Now someone will troll because of the way you spelled Qt ;)
I don't know where you counted 6 different ways, you can basically use GL widgets with hybrid QPainter + standard OpenGL. The GUI aspect of it is much better performance (with the right render path optimizations of course), plus you get to draw some actual 3D inside of the GUI.
Alternatively, you can use Qt3D, which unfortunately lost its developers and at the moment I don't think it is being worked on. As a result, it is no longer an integral part of Qt5 but an addon module which you must get and build manually. If offers an API that can substitute many of the standard OpenGL functions as well as those, provided by glut/freeglut and so on. There is an API for working with meshes, shaders, materials and whatnot. Qt3D can be used natively with C++ or from QML.
Since Qt aims for portability, its own GL APIs target a level of common functionality shared by desktop and mobile OGL. Since you mention performance I assume you would want to use the advanced capabilities of newer OGL versions, then you are left with no option but to code against the raw OpenGL API.
I as well as many other people have been calling for a low level graphics API for 2D and 3D for a while, ported to OpenGL as well as Direct3D, which IMO would be of tremendous value to Qt, but it doesn't seem that this will become a priority for Qt anytime soon. One can still hope with Qt5 being done there will be resources to invest in new Qt modules.
-
Thank you for the fast and very informative response. So basically I just want to use OpenGL4.X for windows and linux. This means I continue using the QGLWidgets class, but instead of using the Qt helper functions like QGLShaderProgram or QGLBuffer, I just use raw OpenGL?
At least the documentation of QGLWidgets tells me this .
"You inherit from it and use the subclass like any other QWidget, except that you have the choice between using QPainter and standard OpenGL rendering commands."
So instead of using QPainter I just use standard OpenGL.
-
You can use both. It will be hard for you do paint paths, vector art and other 2D stuff like that with OpenGL, QPainter does that for you, generate vertices and whatnot.
Nothing prevents you from using the Qt provided classes, however, they may not be up to date with the latest functionality, provided by OpenGL. That doesn't mean you can't use the assisting classes for creating and compiling shaders and stuff like that, which is faster to do with the Qt API instead of the C-style OpenGL API.
Writing pure OpenGL will be more portable thou, I mean if you consider substituting Qt for another framework for a different platform or stuff like that.
-
Be aware that this has changed with Qt5, which offers a brand new "OpenGL module":http://qt-project.org/doc/qt-5.0/qtgui/qtgui-index.html#opengl-and-opengl-es-integration for hardware-accelerated "2D":http://qt-project.org/doc/qt-5.0/qtgui/qopenglpaintdevice.html and "3D":http://qt-project.org/doc/qt-5.0/qtgui/painting-3d.html painting.
In case you've missed Sean Harmers talk on OpenGL with Qt5 at the Qt Developers Days 2012 feel free to take a look at the "presentation":http://www.youtube.com/watch?v=GYa5DLV6ADQ or the "slides":http://www.qtdeveloperdays.com/northamerica/opengl-qt-5 online.
Sean Harmer is one of the maintainers and developers of Qt3D, which is available as a Qt 5 Add On and will in all likelihood have its return to the Qt Essentials with Qt 5.1, which will also bring "additional OpenGL support":http://lists.qt-project.org/pipermail/development/2012-December/008765.html.
-
I've looked arround this, Forum, web page for some way topost a question. There does not seem to be a 'post question'. What would be the 'word', 'button' or 'link' I should click on so that I can post a question?
TIA
-
[quote author="Lukas Geyer" date="1356021868"]Be aware that this has changed with Qt5, which offers a brand new "OpenGL module":http://qt-project.org/doc/qt-5.0/qtgui/qtgui-index.html#opengl-and-opengl-es-integration for hardware-accelerated "2D":http://qt-project.org/doc/qt-5.0/qtgui/qopenglpaintdevice.html and "3D":http://qt-project.org/doc/qt-5.0/qtgui/painting-3d.html painting.
In case you've missed Sean Harmers talk on OpenGL with Qt5 at the Qt Developers Days 2012 feel free to take a look at the "presentation":http://www.youtube.com/watch?v=GYa5DLV6ADQ or the "slides":http://www.qtdeveloperdays.com/northamerica/opengl-qt-5 online.
Sean Harmer is one of the two maintainers of Qt3D, which is available as a Qt 5 Add On will in all likelihood have its return to the Qt Essentials with Qt 5.1, which will also bring "additional OpenGL support":http://lists.qt-project.org/pipermail/development/2012-December/008765.html.[/quote]
Yes I saw this presentation twice. But I also saw different implementations such as the link in my first post with the core profile. Or the opengl examples. All used different methods of implementing OpenGL in Qt.
But the sample in the video is not online, probably because he used some functionality that will come with 5.1.
I also saw the example " OpenGL Window Example" which uses QWindow & QOpenGLFunctions instead of QGLWidgets. Is this now the correct way of using OpenGL?
Note that I do not need OpenGL ES1.1 or 2.0 support only OpenGl4.X.
-
[quote author="kantaki" date="1356022517"]But I also saw different implementations such as the link in my first post with the core profile.[/quote]Be aware that the article refers to Qt4, not Qt5.
[quote author="kantaki" date="1356022517"]I also saw the example " OpenGL Window Example" which uses QWindow & QOpenGLFunctions instead of QGLWidgets. Is this now the correct way of using OpenGL?[/quote]Prefer QOpenGL, but you can also use any highlevel functionality like Qt3D or the scenegraph.
-
[quote author="ArbolOne" date="1356022181"]I've looked arround this, Forum, web page for some way topost a question. There does not seem to be a 'post question'. What would be the 'word', 'button' or 'link' I should click on so that I can post a question?[/quote]
!http://i.imgur.com/J58SK.png(Start new discussion)! -
Hi,
it depends what you want to do. You can freely choose to use QGLWidget or QWindow plus QOpenGLContext.
QGLWidget creates it's own QGLContext which is in turn implemented in terms of QOpenGLContext so they are equivalent really.
The main difference is that QGLWidget can (more) easily be embedded inside a widget based application. Whereas, QWindow + QOpenGLContext will just give you a single window more suitable for games or other full-screen visualisation tools.
I did not use any classes that are not readily available in those talks. All prototype classes I mentioned in the videos are available on gerrit. See the patch series starting at https://codereview.qt-project.org/#change,30554 for example. I am currently refactoring some of these and will soon resubmit them against the development branch. They should apply cleanly against Qt 5.0.0 I believe.
I am also aiming to make the examples I show in the talk available online shortly but I have been uber-busy since returning from DevDays. ;)
If you have any specific questions please ask them here and I will do my best to answer you.
-
Incidentally the wiki article you reference in the original post was written a long time ago for Qt 4. I should find some time to update it for Qt5 to show the option of QWindow+QOpenGLContext.
-
Speaking of the devil... ;-)
-
[quote author="Lukas Geyer" date="1356023511"]Speaking of the devil... ;-)[/quote]
I'm like Beetlejuice :)
-
Okay thanks a lot :). But I have one last question. You mentioned I should only use QWindow + QOpenGLContext.
So I do not need QOpenGLFunctions at all if I only want to use OpenGL (no OpenGL ES)?
It's mainly for a graphics engine showcase in the future. -
I didn't say you should only use QWindow+QOpenGLContext. The other QOpenGL* classes are perfectly fine to use. I highly recommend QOpenGLShaderProgram and friends. They will save you writing a lot of boiler-plate code.
QOpenGLFunctions however does not expose all OpenGL functions, only the subset used by Qt itself. This is what I am trying to address with https://codereview.qt-project.org/#change,35408
As mentioned earlier in this thread and on the development@qt-project.org mailing list, we have a whole bunch of other OpenGL enabler classes we could potentially add for Qt 5.1.
Of course once you have a window and context you are free to use raw OpenGL calls. Just beware that you will have to handle resolving the function pointers for any functions you use. Especially on windows this can be a pain.
-
Ok thanks , I think I should be able to use it now. :)
-
Okay I encountered a problem. :x
I tried to create opengl window with the QWindow but I am not sure how I can tell QWindow "Hey you have to use OpenGL now".
I did the following. I read the documentation but I probably misunderstood something.
@#ifndef GLWINDOW_H
#define GLWINDOW_H
#include <QWindow>
#include <QOpenGLBuffer>
#include <QOpenGLContext>
#include <QOpenGLShader>
#include <QGLFormat>class GLWindow : public QWindow
{
QOpenGLContext* context;public:
GLWindow(); void initGL(); void resize(int w, int h);
};
#endif // GLWINDOW_H@
@#include "glwindow.h"
#include <QDebug>GLWindow::GLWindow()
{
initGL();
}
void GLWindow::resize(int w, int h){glViewport(0,0,w,h); qDebug() << w << " " <<h;
}
void GLWindow::initGL()
{
context = new QOpenGLContext(this);
context->setFormat(requestedFormat());
context->create();}
@
@#include "mainwindow.h"
#include <QGuiApplication>
#include <glwindow.h>
#include <QSurfaceFormat>
int main(int argc, char *argv[])
{
QGuiApplication a(argc, argv);
QSurfaceFormat format;
format.setSamples(4);
GLWindow window;
window.setFormat(format);
window.resize(800,600);
window.show();
return a.exec();
}@ -
[quote author="kantaki" date="1356053482"]I tried to create opengl window with the QWindow but I am not sure how I can tell QWindow "Hey you have to use OpenGL now".[/quote]
"QWindow::setSurfaceType()":http://qt-project.org/doc/qt-5.0/qtgui/qwindow.html#setSurfaceTypeHave you taken a look at the "OpenGL Window Example":http://qt-project.org/doc/qt-5.0/qtgui/openglwindow.html?
-
Something like this will do it:
@
OpenGLWindow::OpenGLWindow( const QSurfaceFormat& format,
QScreen* screen )
: QWindow( screen ),
m_context( 0 ),
m_scene( 0 )
{
// Tell Qt we will use OpenGL for this window
setSurfaceType( OpenGLSurface );// Request a full screen button (if available) setFlags( flags() | Qt::WindowFullscreenButtonHint ); // Create the native window setFormat( format ); create(); // Create an OpenGL context m_context = new QOpenGLContext; m_context->setFormat( format ); m_context->create();
}
@where the QSurfaceFormat is created in your main() function (adjust to suit your needs of course):
@
#include <QGuiApplication>
#include <QSurfaceFormat>#include "diffusescene.h"
#include "openglwindow.h"int main( int argc, char* argv[] )
{
QGuiApplication a( argc, argv );// Specify the format we wish to use QSurfaceFormat format; format.setMajorVersion( 3 );
#if !defined(Q_OS_MAC)
format.setMinorVersion( 3 );
#else
format.setMinorVersion( 2 );
#endif
format.setDepthBufferSize( 24 );
format.setSamples( 4 );
format.setProfile( QSurfaceFormat::CoreProfile );OpenGLWindow w( format ); w.setScene( new DiffuseScene ); w.show(); return a.exec();
}
@Hope this helps.
ps The DiffuseScene class is just a custom class that does the actual OpenGL rendering in my case.
pps Remember to call QOpenGLContext::makeCurrent() on the QWindow before using it to render and to call QOpenGLContext::swapBuffers() after rendering.
-
This code works fine (displays a purple triangle) on Qt 4.8.1, but not on 5.0.0 (pre-compiled version, Windows 7 x64, MSVC2010 32bit compile). I get a window with a grey widget inside. I use "GLWidget" with "setCentralWidget(new GLWidget());" in a QMainWindow constructor... Most of the code is ripped straight from the "hellogl_es2" example btw.
Note that I uncommented the usage of native painting too:
@QPainter painter;
painter.begin(this);
painter.beginNativePainting();
...
painter.endNativePainting();
@
because it just doesn't work for me, on BOTH Qt versions...What am I doing wrong?!
GLWidget.h
@#pragma once#include <vector>
#include <QGLWidget>
#include <QGLShaderProgram>
#include <QGLFunctions>
#include <QTime>class GLWidget: public QGLWidget, protected QGLFunctions
{
int frames;
QTime time;QGLShaderProgram program;
int vertexAttribute;
int normalAttribute;
int matrixUniform;float viewAngleX;
float viewAngleY;
float viewScale;
QMatrix4x4 projection;std::vector<QVector3D> vertices;
std::vector<QVector3D> normals;public:
GLWidget(QWidget * parent = nullptr);virtual void initializeGL();
virtual void resizeGL(int width, int height);
virtual void paintGL();void setDefaultScene();
void drawScene();
};@GLWidget.cpp
@#include "GLWidget.h"#include <QMessageBox>
GLWidget::GLWidget(QWidget * parent)
: QGLWidget(parent), viewScale(1.0f), viewAngleX(0.0f), viewAngleY(0.0f)
{
setAttribute(Qt::WA_PaintOnScreen);
setAttribute(Qt::WA_NoSystemBackground);
setAutoBufferSwap(true);
setMinimumSize(512, 512);
}void GLWidget::resizeGL(int width, int height)
{
//Set up OpenGL viewport
glViewport(0, 0, width, height);
float aspect = (float)width / ((float)height ? height : 1.0f);
const float zNear = 1.0f, zFar = 10.0f, fov = 45.0f;
projection.setToIdentity();
projection.perspective(fov, aspect, zNear, zFar);
}void GLWidget::initializeGL()
{
initializeGLFunctions();QGLShader *vshader = new QGLShader(QGLShader::Vertex, this); const char *vsrc = "attribute highp vec4 vertex;\n" "attribute mediump vec3 normal;\n" "uniform mediump mat4 matrix;\n" "varying mediump vec4 color;\n" "void main(void)\n" "{\n" " vec3 toLight = normalize(vec3(0.0, 0.3, 1.0));\n" " float angle = max(dot(normal, toLight), 0.0);\n" " vec4 col = vec4(0.8, 0.8, 0.8, 1.0) * angle + vec4(0.2, 0.2, 0.2, 1.0);\n"
" color = clamp(col, 0.0, 1.0);\n"
" gl_Position = matrix * vertex;\n"
"}\n";
if (!vshader->compileSourceCode(vsrc) || vshader->log().size() > 0) {
QMessageBox::warning(this, "Error", QString("Error compiling vertex vertex shader source: %1").arg(vshader->log()));
return;
}QGLShader *fshader = new QGLShader(QGLShader::Fragment, this); const char *fsrc = "varying mediump vec4 color;\n" "void main(void)\n" "{\n" " gl_FragColor = vec4(0.4, 0.0, 0.4, 1.0);\n" "}\n"; if (!fshader->compileSourceCode(fsrc) || fshader->log().size() > 0) {
QMessageBox::warning(this, "Error", QString("Error compiling fragment shader source: %1").arg(fshader->log()));
return;
}if (!program.addShader(vshader)) {
QMessageBox::warning(this, "Error", QString("Error adding vertex shader: %1").arg(program.log()));
return;
}if (!program.addShader(fshader)) {
QMessageBox::warning(this, "Error", QString("Error adding fragment shader: %1").arg(program.log()));
return;
}if (!program.link() || !program.bind()) {
QMessageBox::warning(this, "Error", QString("Error linking shaders: %1").arg(program.log()));
return;
}vertexAttribute = program.attributeLocation("vertex"); normalAttribute = program.attributeLocation("normal"); matrixUniform = program.uniformLocation("matrix");
setDefaultScene();
}void GLWidget::paintGL()
{
/*QPainter painter;
painter.begin(this);painter.beginNativePainting();*/ glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); QMatrix4x4 modelview; modelview.rotate(viewAngleX, 1.0f, 0.0f, 0.0f); modelview.rotate(viewAngleY, 0.0f, 1.0f, 0.0f); modelview.scale(viewScale); modelview.translate(0.0f, 0.0f, -2.0f); program.bind(); program.setUniformValue(matrixUniform, projection * modelview); drawScene(); program.release(); //painter.endNativePainting();
}
void GLWidget::setDefaultScene()
{
vertices.clear();
normals.clear();vertices.push_back(QVector3D(-0.3f, -0.3f, 0.0f));
vertices.push_back(QVector3D( 0.3f, -0.3f, 0.0f));
vertices.push_back(QVector3D( 0.3f, 0.3f, 0.0f));normals.push_back(QVector3D( 0.0f, 0.0f, 1.0f));
normals.push_back(QVector3D( 0.0f, 0.0f, 1.0f));
normals.push_back(QVector3D( 0.0f, 0.0f, 1.0f));
}void GLWidget::drawScene()
{
program.enableAttributeArray(normalAttribute);
program.enableAttributeArray(vertexAttribute);
program.setAttributeArray(vertexAttribute, vertices.data());
program.setAttributeArray(normalAttribute, normals.data());
glDrawArrays(GL_TRIANGLES, 0, vertices.size());
program.disableAttributeArray(normalAttribute);
program.disableAttributeArray(vertexAttribute);
}@