c++qtopenglqt5qopenglwidget

How to render some vertices in a buffer as points and the rest using lines in qopenglwidget?


I have a set of vertices and normals stored in a buffer. I want to display most of the vertices as points but i want draw lines for the remaining few vertices. These are all stored inside one vector with the points part in the front and i know the location of the buffer until they are to be displayed using points. I also know the count of elements for each drawing task. I am using only one vao and one buffer object for this task.

I initialize the GLWidget with the following code:

void GLWidget::initializeGL()
{
    connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &GLWidget::cleanup);

    initializeOpenGLFunctions();
    glClearColor(0, 0, 0, m_transparent ? 0 : 1);

    m_program = new QOpenGLShaderProgram;
    m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, m_core ? vertexShaderSourceCore : vertexShaderSource);
    m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, m_core ? fragmentShaderSourceCore : fragmentShaderSource);
    m_program->bindAttributeLocation("vertex", 0);
    m_program->bindAttributeLocation("normal", 1);
    m_program->link();

    m_program->bind();
    m_projMatrixLoc = m_program->uniformLocation("projMatrix");
    m_mvMatrixLoc = m_program->uniformLocation("mvMatrix");
    m_normalMatrixLoc = m_program->uniformLocation("normalMatrix");
    m_lightPosLoc = m_program->uniformLocation("lightPos");
    m_vao.create();
    QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
    m_obj.create();
    setupBuffer();
    setupVertexAttribs();
    m_camera.setToIdentity();

    QVector3D camPos = QVector3D(0.0, 0.0, 15.0);
    m_camera.translate(-camPos);

    QVector3D camTarget = QVector3D(0.0, 0.0, 0.0);
    QVector3D camDirection = QVector3D(camPos - camTarget).normalized();
    QVector3D worldUp = QVector3D(0.0, 1.0, 0.0);
    QVector3D camRight = QVector3D::crossProduct(worldUp, camDirection).normalized();
    QVector3D camUp = QVector3D::crossProduct(camDirection, camRight);

    m_camera.lookAt(camPos, camTarget, camUp);
    // Light position is fixed.
    m_program->setUniformValue(m_lightPosLoc, QVector3D(0, 0, 200));

    m_program->release();
}

Where the functions setupBuffer() setupVertexAtrribs() do the same tasks as their names imply. The vertices are layed out in the buffer with xyz positions of the vertex followed by the xyz of its associated normal. They are implemented as follows

void GLWidget::setupBuffer()
{
    m_obj.bind();
    m_obj.allocate(vertices.constData(), vertices.size() * sizeof(GLfloat));
}

void GLWidget::setupVertexAttribs()
{
    m_obj.bind();
    QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
    f->glEnableVertexAttribArray(0);
    f->glEnableVertexAttribArray(1);
    f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), reinterpret_cast<void *>(0));
    f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), reinterpret_cast<void *>(3 * sizeof(GLfloat)));
    m_obj.release();
}

Now, the QVector vertices is the buffer that is being passed to opengl. The last few entries in this vector are the vertices that need to be drawn using GL_LINES.

My paintGL() function looks something like this:

void GLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
    glEnable(GL_POINT_SIZE);
    glEnable(GL_LINE_WIDTH);
    glPointSize(2);
    glLineWidth(10);

    m_world.setToIdentity();
    m_world.rotate(180.0f - (m_xRot / 16.0f), 1, 0, 0);
    m_world.rotate(m_yRot / 16.0f, 0, 1, 0);
    m_world.rotate(m_zRot / 16.0f, 0, 0, 1);
    m_world.scale(m_dispScale);

    QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
    m_program->bind();
    m_program->setUniformValue(m_projMatrixLoc, m_proj);
    m_program->setUniformValue(m_mvMatrixLoc, m_camera * m_world);
    QMatrix3x3 normalMatrix = m_world.normalMatrix();
    m_program->setUniformValue(m_normalMatrixLoc, normalMatrix);

    glDrawArrays(GL_POINTS, 0, vertices.size() - camVertices.size());
    // Draw camera frustums
    glDrawArrays(GL_LINES, vertices.size() - camVertices.size(), camVertices.size());
    //glDrawElements(GL_POINTS, vecIndices.size(), GL_UNSIGNED_INT, 0);

    m_program->release();
}

QVector camVertices is another vector that contains points that need to be drawn using lines. The data in camVertices is appended to the end of the vector 'Vertices' before rendering. As seen in the above code, I call glDrawArrays function twice - first, starting from 0 index of the buffer, second, starting from where the previous call ended to display the remaining of the points.

The problem is that the points are being displayed fine. However the second call only displays the points but does not draw any lines.

Here's a link to a screenshot of the displayed output - https://drive.google.com/open?id=1i7CjO1qkBALw78KKYGvBteydhfAWh3wh

The picture shows an example of the displayed out where the bright green points seen on the top outlying from the rest (box of many points) are the ones that are to be drawn with lines. However, I only see points but not any lines.


Solution

  • i did a simple test and i'm able to draw points and lines using the following code:

            glDrawArrays(GL_POINTS, 0, verticesCount() - 10);
            glDrawArrays(GL_LINES, 10, 10);
    

    Which is not very different from yours except for the variables. I'm also using 1 VAO. So it's definitely possible to draw lines after points as we would expect.

    Could you try the same (using an integer instead of your variables)

    Can you show the debug information on your vertices?

    Can you upload a minimal compilable example?