Andrew Q
Andrew Q

Reputation: 19

QOpenGLWidget Won't Draw Triangle

So I'm trying to implement an editor for my game using Qt, and I can't seem to decipher how the QOpenGLWidget works. Right now, I just want to get a simple triangle to render, then I can worry about moving in all the rest of my stuff.

Right now, it will open the window, and, in the QOpenGLWidget, will clear to the custom color I set in the subclass (so I did promote it), but it won't draw the triangle described in the class below. I've tried following the Qt OpenGLWindow example as well as the examples in QOpenGLWidget and QOpenGLShaderProgram, I also checked every function that returns a bool to make sure they were all being executed properly, and they are, but still no triangle.

Did I miss a vital function call? Am I doing things in the absolute wrong way? Or is it something super subtle and strange with Qt?

Here's the header:

#include<qopenglwidget.h>
#include<QtGui/qopenglfunctions.h>

class EditorViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
public:
    EditorViewWidget(QWidget *parent);
protected:
    void initializeGL();
    void resizeGL(int w, int h);
    void paintGL();
    QOpenGLShaderProgram* shaderProgram;
    QOpenGLVertexArrayObject vao;
    QOpenGLBuffer VBO;
    int position_attribute;
    int color_uniform;
    float Vertices[9];
    const char* vert="#version 150          \n"
"                                           \n"
"   in vec3 position;                       \n"
"                                           \n"
"   void main()                             \n"
"   {                                       \n"
"       gl_Position = vec4(position, 1.0);  \n"
"   }";
    const char* frag="#version 150          \n"
"                                           \n"
"   uniform vec3 Color;                     \n"
"   out vec4 outColor;                      \n"
"                                           \n"
"   void main()                             \n"
"   {                                       \n"
"       outColor = vec4(Color, 1.0);        \n"
"   }";
};

and the source:

EditorViewWidget::EditorViewWidget(QWidget* parent)
    :QOpenGLWidget(parent)
{
    float v[] = {
        0.0, 0.5, 0.0,
        0.5, -0.5, 0.0,
        -0.5, -0.5, 0.0
    };
    for (int i = 0; i < 9; i++)
        Vertices[i] = v[i];
}

void EditorViewWidget::initializeGL()
{
    initializeOpenGLFunctions();
    vao.create();
    vao.bind();

    //glGenBuffers(1, &VBO);
    glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
    shaderProgram = new QOpenGLShaderProgram(this);
    shaderProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, vert);
    shaderProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, frag);
    shaderProgram->link();
    shaderProgram->bind();
    position_attribute = shaderProgram->attributeLocation("position");
    color_uniform = shaderProgram->uniformLocation("Color");
    VBO.create();
    VBO.bind();
    VBO.allocate(&Vertices, 9*sizeof(float));
    shaderProgram->enableAttributeArray(position_attribute);
    shaderProgram->setAttributeArray(position_attribute, Vertices, 3);
    shaderProgram->setUniformValue(color_uniform, 1.0f, 1.0f, 1.0f);
    //glVertexAttribPointer(position_attribute, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
}

void EditorViewWidget::resizeGL(int w, int h)
{
}

void EditorViewWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT);
    VBO.bind();
    VBO.allocate(&Vertices, 9 * sizeof(float));
    shaderProgram->enableAttributeArray(position_attribute);
    shaderProgram->setAttributeArray(position_attribute, Vertices, 3, 0);
    shaderProgram->setUniformValue(color_uniform, 1.0f, 1.0f, 1.0f);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    shaderProgram->disableAttributeArray(position_attribute);
}

Upvotes: 1

Views: 953

Answers (3)

8Observer8
8Observer8

Reputation: 1152

I have ported the example to Qt6:

  • add this line of code QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL); to the main(). At least on my laptop the program doesn't work without this line of code. This error message will be printed to the Qt debug console: GLSL 1.50 is not supported. Supported versions are: 1.10, 1.20, 1.30, 1.00 ES, and 3.00 ES
  • use setAttributeBuffer instead of setAttributeArray
  • don't call VBO.bind() inside of paintGL. You should call VAO.bind() only
  • don't call setAttributeBuffer/enableAttributeArray inside of paintGL because you have made it inside of initializeGL
  • make VBO.release(); and VAO.release(); inside of initializeGL
  • make VAO.release(); after glDrawArrays(GL_TRIANGLES, 0, 3);
  • don't call VBO.allocate inside of paintGL because you have made it inside of initializeGL
  • don't call shaderProgram->setUniformValue(uColorLocation, 1.0f, 1.0f, 1.0f); inside of paintGL because you have made it inside of initializeGL
  • use counterclockwise order. This order works:
    float v[] = {
        0.f, 0.5f, 0.f,
        -0.5f, -0.5f, 0.f,
        0.5f, -0.5f, 0.f
    };

But this one doesn't:

    float v[] = {
        0.f, 0.5f, 0.f,
        0.5f, -0.5f, 0.f,
        -0.5f, -0.5f, 0.f
    };

enter image description here

pro

QT += core gui openglwidgets

win32: LIBS += -lopengl32

CONFIG += c++17

SOURCES += \
    main.cpp \
    editor_view_widget.cpp

HEADERS += \
    editor_view_widget.h

main.cpp

#include "editor_view_widget.h"

#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
    QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL);
    QApplication app(argc, argv);
    EditorViewWidget w;
    w.show();
    return app.exec();
}

editor_view_widget.h

#ifndef EDITOR_VIEW_WIDGET_H
#define EDITOR_VIEW_WIDGET_H

#include <QtGui/QOpenGLFunctions>
#include <QtOpenGL/QOpenGLBuffer>
#include <QtOpenGL/QOpenGLShaderProgram>
#include <QtOpenGL/QOpenGLVertexArrayObject>
#include <QtOpenGLWidgets/QOpenGLWidget>

class EditorViewWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
public:
    EditorViewWidget(QWidget *parent = nullptr);

protected:
    void initializeGL() override;
    void resizeGL(int w, int h) override;
    void paintGL() override;

private:
    QOpenGLShaderProgram *shaderProgram;
    QOpenGLVertexArrayObject VAO;
    QOpenGLBuffer VBO;
    int aPositionLocation;
    int uColorLocation;
    float vertices[9];
    const char* vert="#version 150                  \n"
        "                                           \n"
        "   in vec3 aPosition;                      \n"
        "                                           \n"
        "   void main()                             \n"
        "   {                                       \n"
        "       gl_Position = vec4(aPosition, 1.0); \n"
        "   }";
    const char* frag="#version 150                  \n"
        "                                           \n"
        "   uniform vec3 uColor;                    \n"
        "   out vec4 outColor;                      \n"
        "                                           \n"
        "   void main()                             \n"
        "   {                                       \n"
        "       outColor = vec4(uColor, 1.0);       \n"
        "   }";
};
#endif // EDITOR_VIEW_WIDGET_H

editor_view_widget.cpp

#include "editor_view_widget.h"

EditorViewWidget::EditorViewWidget(QWidget *parent)
    : QOpenGLWidget(parent)
{
    setWindowTitle("Example");
    resize(350, 350);

    // float v[] = {
    //     0.f, 0.5f, 0.f,
    //     0.5f, -0.5f, 0.f,
    //     -0.5f, -0.5f, 0.f
    // };

    float v[] = {
        0.f, 0.5f, 0.f,
        -0.5f, -0.5f, 0.f,
        0.5f, -0.5f, 0.f
    };

    for (int i = 0; i < 9; i++)
    {
        vertices[i] = v[i];
    }
}

void EditorViewWidget::initializeGL()
{
    initializeOpenGLFunctions();
    VAO.create();
    VAO.bind();

    glClearColor(0.0f, 1.0f, 0.0f, 1.0f);

    shaderProgram = new QOpenGLShaderProgram(this);
    shaderProgram->addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Vertex, vert);
    shaderProgram->addShaderFromSourceCode(QOpenGLShader::ShaderTypeBit::Fragment, frag);
    shaderProgram->link();
    shaderProgram->bind();

    aPositionLocation = shaderProgram->attributeLocation("aPosition");
    uColorLocation = shaderProgram->uniformLocation("uColor");
    shaderProgram->setUniformValue(uColorLocation, 1.0f, 1.0f, 1.0f);

    VBO.create();
    VBO.bind();
    VBO.allocate(vertices, sizeof(vertices));
    shaderProgram->setAttributeBuffer(aPositionLocation, GL_FLOAT, 0, 2);
    shaderProgram->enableAttributeArray(aPositionLocation);
    VBO.release();
    VAO.release();
}

void EditorViewWidget::resizeGL(int w, int h)
{
    Q_UNUSED(w);
    Q_UNUSED(h);
}

void EditorViewWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT);
    VAO.bind();
    shaderProgram->bind();
    glDrawArrays(GL_TRIANGLES, 0, 3);
    VAO.release();
}

Upvotes: 0

steventaitinger
steventaitinger

Reputation: 402

You are allocating and setting the attributes of your VBO everytime you call paintGL. VBOs are so that you can just initialize them once and then use them many times. Then you can just bind your VAO in your paintGL, call glDrawArrays and then unbind your VAO. Also, unbinding/releasing your VBO and VAO should be done after the glDrawArrays and after you first set the attribute data. You don't need a VAO if you are only using one VBO. VAOs only purpose is to hold multiple VBOs.

You are calling enableAttributeArray instead of setAttributeBuffer.

I am not sure which of the above caused your triangle not to draw properly but I am almost certain it was one of them :).

Upvotes: 1

Schusy
Schusy

Reputation: 36

You specified the vertices of your triangle in clockwise order. OpenGL expects them in counterclockwise order by default. Switch the 2nd and 3rd vertex and you should see your triangle

Upvotes: 2

Related Questions