Как визуализировать некоторые вершины в буфере как точки, а остальные, используя линии в qopenglwidget?

У меня есть набор вершин и нормалей, хранящихся в буфере. Я хочу отобразить большинство вершин в виде точек, но я хочу нарисовать линии для оставшихся нескольких вершин. Все они хранятся внутри одного вектора с частью точек спереди, и я знаю местоположение буфера, пока они не будут отображены с использованием точек. Я также знаю количество элементов для каждой задачи рисования. Для этой задачи я использую только один объект vao и один буфер.

Я инициализирую GLWidget с помощью следующего кода:

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();
}

Где функции setupBuffer() setupVertexAtrribs() выполняют те же задачи, что и их имена. Вершины располагаются в буфере с позициями xyz вершины, за которыми следует xyz соответствующей нормали. Они реализованы следующим образом

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();
}

Теперь вершины QVector - это буфер, который передается в opengl. Последние несколько записей в этом векторе - это вершины, которые нужно нарисовать с помощью GL_LINES.

Моя функция paintGL() выглядит примерно так:

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 - это еще один вектор, содержащий точки, которые необходимо нарисовать с использованием линий. Данные в camVertices добавляются в конец вектора "Вершины" перед рендерингом. Как видно из приведенного выше кода, я вызываю функцию glDrawArrays дважды - во-первых, начиная с 0 индекса буфера, во-вторых, начиная с того места, где завершился предыдущий вызов, чтобы отобразить оставшиеся точки.

Проблема в том, что точки отображаются нормально. Однако второй вызов отображает только точки, но не рисует никаких линий.

Вот ссылка на снимок экрана с отображаемым выводом - https://drive.google.com/open?id=1i7CjO1qkBALw78KKYGvBteydhfAWh3wh

На рисунке показан пример отображения, где ярко-зеленые точки, видимые на верхних участках от остальных (прямоугольник с множеством точек), - это те, которые должны быть нарисованы линиями. Однако я вижу только точки, но не линии.

1 ответ

Решение

Я сделал простой тест, и я могу рисовать точки и линии, используя следующий код:

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

Который не сильно отличается от вашего, за исключением переменных. Я также использую 1 ВАО. Так что, безусловно, можно рисовать линии после точек, как мы и ожидали.

Не могли бы вы попробовать то же самое (используя целое число вместо ваших переменных)

Можете ли вы показать отладочную информацию на ваших вершинах?

Можете ли вы загрузить минимальный компилируемый пример?

Другие вопросы по тегам