0

I want to place in QGraphicsScene several items that draw lines using opengl, when I draw these lines with painter or without shaders, using glBegin(GL_LINES) everything works fine, and the lines are drawn each in its own item. But when I draw with glDrawArrays, the lines of all the items overlap each other and are located in the center of the scene.

I have simple line drawing shaders:

Vertex shader:

attribute vec2 position;
attribute vec4 f_color;
uniform float drw;
uniform float drh;
varying vec4 color;

void main(void) {
    color = f_color;
    gl_Position = vec4((position.x / drw) * 2.0, (position.y / drh) * 2.0, -1.0, 1.0);
}

Fragment shader:

varying vec4 color;

void main(void) {
    gl_FragColor = color;
}

Next I create my graphics item class:

#include <QGraphicsItem>
#include <QGraphicsLayoutItem>
#include <QOpenGLBuffer>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>

class MyItem : public QGraphicsItem, public QGraphicsLayoutItem {

public:
    MyItem(QGraphicsItem *parent = nullptr);
    ~ MyItem();
    QRectF boundingRect() const override;
protected:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
    // Inherited from QGraphicsLayoutItem
    void   setGeometry(const QRectF &geom) override;
    QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const override;

private:
    QOpenGLBuffer            m_vertexBuffer;
    QVector<QVector2D>       m_vertices;
    QOpenGLVertexArrayObject m_vao;
    QOpenGLShaderProgram    *m_program;
    QOpenGLBuffer      m_colorBuffer;
    QVector<QVector4D> m_colors;
    QVector<QVector4D> m_colorVBuffer;
};

Constructor:

MyItem::MyItem(QGraphicsItem *parent): QGraphicsItem(parent)
{
    m_program = new QOpenGLShaderProgram();
    m_vertices = QVector<QVector2D>();

    m_vao.create();
    m_vao.bind();

    m_vertexBuffer = QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
    m_vertexBuffer.create();
    m_vertexBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
    m_vertexBuffer.bind();
    m_vertexBuffer.allocate(m_vertices.constData(), m_vertices.size() * sizeof(QVector2D));
    m_colorBuffer = QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
    m_colorBuffer.create();
    m_colorBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
    m_colorBuffer.bind();
    m_colorBuffer.allocate(m_vertices.constData(), m_colorVBuffer.size() * sizeof(QVector4D));

    m_vao.release();

    m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/vertexShader.vert")

    m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/fragmentShader.frag")

    m_program->link()
    m_program->bind()
    program->enableAttributeArray(0);
    program->setAttributeBuffer(0, GL_FLOAT, 0, 2);
    program->release();
    setGraphicsItem(this);
}

And in the paint function I draw an array of lines:

void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
    
    painter->beginNativePainting();

    m_program->bind();
    m_vao.bind();
    m_vertexBuffer.bind();
    m_vertexBuffer.allocate(m_vertices.constData(), m_vertices.size() * sizeof(QVector2D));

    m_program->enableAttributeArray("position");
    m_program->setAttributeBuffer("position", GL_FLOAT, 0, 2);

    m_program->setUniformValue("drw", static_cast<GLfloat>(boundingRect().width()));
    m_program->setUniformValue("drh", static_cast<GLfloat>(boundingRect().height()));

    m_program->enableAttributeArray("f_color");
    m_program->setAttributeBuffer("f_color", GL_FLOAT, 0, 4);

    glLineWidth(2);
    glDrawArrays(GL_LINES, 0, m_vertices.size());

    m_vao.release();
    m_program->release();

    painter->endNativePainting();
}

Overrided methods:

void PolarItem::setGeometry(const QRectF &geom)
{
    prepareGeometryChange();
    QGraphicsLayoutItem::setGeometry(geom);
    setPos(geom.topLeft());
}

QSizeF PolarItem::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
    switch (which) {
    case Qt::MinimumSize:
    case Qt::PreferredSize:
        return QSize(400, 400);
    case Qt::MaximumSize:
        return QSizeF(400, 400);
    default:
        break;
    }
    return constraint;
}

QRectF PolarItem::boundingRect() const
{
    return QRectF(0, 0, 400, 400);
}

Then I add 5 of these items to the scene and then to the graphics view:

#include "mainwindow.h"
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QOpenGLWidget>
#include <QGraphicsWidget>
#include <QGraphicsLinearLayout>
#include <QSurfaceFormat>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QGraphicsScene * scene = new QGraphicsScene(this);
    QGraphicsView *  view  = new QGraphicsView(scene);
    QGraphicsWidget *form  = new QGraphicsWidget();

    QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(form);
    layout->setOrientation(Qt::Vertical);

    for (int i(0); i < 5; ++i) {
            QSharedPointer<MyItem> item(new MyItem());
            layout->addItem(item.data());
    }
    scene->addItem(form);
    QOpenGLWidget *myGLWidget = new QOpenGLWidget();

    QSurfaceFormat format;
    format.setProfile(QSurfaceFormat::CompatibilityProfile);
    format.setSamples(8);
    QSurfaceFormat::setDefaultFormat(format);
    view->setBackgroundBrush(QColor(255, 255, 255));
    myGLWidget->setFormat(format);

    view->setViewport(myGLWidget);
    setCentralWidget(view);
}

And in the end I get this result, where the lines from all the items overlap each other in the center of the scene: Result

I tried to use glViewport with scenePos() before glDrawArrays but that also doesn't work correctly. What am I doing wrong?

  • I'm not sure I understand your code -- it's missing a lot of context. Can you please provide a [mcve] that shows all code for your `QGraphicsItem` derived class. – G.M. Aug 07 '23 at 18:57
  • Please read and understand what is meant by a [mcve]. Your code is far from complete and, given obvious mistakes such as returning `true` from a constructor, I don't understand how it can even compile. You code needs to be complete with a `main`, `#include` directives etc. Where do you create the OpenGL context? – G.M. Aug 09 '23 at 15:23
  • Updated my question, I am not creating QOpenGLContext, I am using viewport in QGraphicsView. – Ivan Ugrumov Aug 10 '23 at 09:51

0 Answers0