QOpenGLFramebufferObject renders only first frame
-
HI!
I am trying to use OpenGL with QtQuick, with use of QQuickFramebufferObject. Generally, everything seems to be working, but only on the first frame. Every other redraw (resizing window or calling 'update()') gives empty widget filled with color set by glClearColor(...). I was trying to manipulate with OpenGL's state, disabling everything that could potentially make scene invisible, but nothing solved the problem. I can't find similar problem in web so i'm asking for help here.
I'm guessing the problem can be with context state after Qt done some stuff on other widgets but i have no idea what could go wrong with this code :/
Or maybe I am trying something very weird here? I don't know. I have seen couple of ways to use OpenGL with Qt but do not exacly know which way is the preffered one.
I will be grateful for any kind of help.
first frame
redrawed window after resize (update() gives same effect)
qml
import QtQuick 2.12 import QtQuick.Window 2.12 import OpenGLItem 1.0 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") OpenGLItem { anchors.fill: parent } }
createRenderer()
QQuickFramebufferObject::Renderer *OpenGLItem::createRenderer() const { return new OpenGLRenderer(); }
Renderer
#include "openglitem.h" #include <QOpenGLFramebufferObjectFormat> #include <QOpenGLFunctions> #include <QQuickWindow> class OpenGLRenderer : public QQuickFramebufferObject::Renderer { private: GLuint m_VBO; GLuint m_ShaderProgram; QQuickWindow *m_Window = nullptr; public: OpenGLRenderer() { QOpenGLFunctions *ogl = QOpenGLContext::currentContext()->functions(); float verts[] = { -1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f }; const char *vertexShaderSource = "#version 330 core\n" "layout(location=0) in vec3 a_Position;\n" "void main() {\n" " gl_Position = vec4(a_Position, 1.0);\n" "}\n\0"; const char *fragmentShaderSource = "#version 330 core\n" "out vec4 FragColor;\n" "void main() {\n" " FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" "}\n\0"; char infoLog[1024]; ogl->glGenBuffers(1, &m_VBO); ogl->glBindBuffer(GL_ARRAY_BUFFER, m_VBO); ogl->glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); ogl->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); ogl->glEnableVertexAttribArray(0); ogl->glBindBuffer(GL_ARRAY_BUFFER, 0); m_ShaderProgram = ogl->glCreateProgram(); GLuint vertexShader = ogl->glCreateShader(GL_VERTEX_SHADER); ogl->glShaderSource(vertexShader, 1, &vertexShaderSource, 0); ogl->glCompileShader(vertexShader); ogl->glAttachShader(m_ShaderProgram, vertexShader); ogl->glGetShaderInfoLog(vertexShader, 1024, 0, infoLog); qDebug() << infoLog; ogl->glDeleteShader(vertexShader); GLuint fragmentShader = ogl->glCreateShader(GL_FRAGMENT_SHADER); ogl->glShaderSource(fragmentShader, 1, &fragmentShaderSource, 0); ogl->glCompileShader(fragmentShader); ogl->glAttachShader(m_ShaderProgram, fragmentShader); ogl->glGetShaderInfoLog(fragmentShader, 1024, 0, infoLog); qDebug() << infoLog; ogl->glDeleteShader(fragmentShader); ogl->glLinkProgram(m_ShaderProgram); ogl->glGetProgramInfoLog(m_ShaderProgram, 1024, 0, infoLog); qDebug() << infoLog; ogl->glUseProgram(m_ShaderProgram); } virtual void render() override { static bool firstTime = true; QOpenGLFunctions *ogl = QOpenGLContext::currentContext()->functions(); ogl->glDisable(GL_DEPTH_TEST); ogl->glDisable(GL_CULL_FACE); ogl->glDisable(GL_SCISSOR_TEST); ogl->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); ogl->glDisable(GL_BLEND); ogl->glDisable(GL_TEXTURE_2D); if(firstTime) { firstTime = false; ogl->glClearColor(1.0f, 1.0f,0.0f,1.0f); } else ogl->glClearColor(1.0f, 0.0f,1.0f,1.0f); ogl->glClear(GL_COLOR_BUFFER_BIT); ogl->glUseProgram(m_ShaderProgram); ogl->glBindBuffer(GL_ARRAY_BUFFER, m_VBO); ogl->glDrawArrays(GL_TRIANGLES, 0, 3); ogl->glBindBuffer(GL_ARRAY_BUFFER, 0); ogl->glFlush(); ogl->glFinish(); ogl->glUseProgram(0); update(); if(m_Window) m_Window->resetOpenGLState(); } virtual QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) override { QOpenGLFramebufferObjectFormat format; format.setAttachment(QOpenGLFramebufferObject::Attachment::Depth); format.setSamples(1); return new QOpenGLFramebufferObject(size, format); } virtual void synchronize(QQuickFramebufferObject *item) override { m_Window = item->window(); } };
main
#include "openglitem.h" #include <QGuiApplication> #include <QQmlApplicationEngine> int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); qmlRegisterType<OpenGLItem>("OpenGLItem", 1, 0, "OpenGLItem"); QQmlApplicationEngine engine; const QUrl url(QStringLiteral("qrc:/main.qml")); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.load(url); return app.exec(); }
-
'Client vertex and index arrays - all vertex array attribute and element array
index pointers must refer to buffer objects. The default vertex array object
(the name zero) is also deprecated. Calling VertexAttribPointer when no
buffer object or no vertex array object is bound will generate an INVALID_-
OPERATION error, as will calling any array drawing command when no vertex array object is bound.'source: https://www.khronos.org/registry/OpenGL/specs/gl/glspec33.core.pdf
page 344