QOpenGLShaderProgram — несколько экземпляров дают поврежденные результаты

У меня есть QGLWidget (Qt 5.2.1).

GLWidget создает экземпляры двух других классов, каждый из которых содержит свои собственные QOpenGLShaderPrograms, загружает свои собственные шейдеры и обрабатывает собственное отрисовку. Это делает для хорошей инкапсуляции.

ОДНАКО -- проблема в том, что данные из осевой сетки (первая инициализируется) появляются в шейдере второго класса. Таким образом, он никогда не рисует свой объект собственным шейдером. Если я изменю порядок вызовов init(), произойдет то же самое в обратном порядке.

Два класса рисования имеют идентичную структуру, поэтому для краткости я включаю только класс Mesh.

Вот результат. AxisMesh, который рисует линии, рисует их поверх класса Scatter тем же цветом, а не их собственным цветом и там, где они должны быть нарисованы.

Линии на этой картинке должны быть другого цвета и в другом месте: Линии на этой картинке должны быть другого цвета и  другое место

ВОПРОСЫ:

Можно ли иметь две QOpenGLShaderPrograms в QGLWidget?

Что-то не так с подходом ниже?

Метод инициализации GLWidget:

void GLWidget::initializeGL()
{
    // Instantiate our drawing objects
    m_axisMesh       = new PlotItemAxisMesh(m_plotManager, m_plotSelection, &m_axisScale);
    m_surfaceScatter = new PlotItemSurfaceScatter(m_plotManager, m_plotSelection, &m_axisScale);

...

    // Initialize the axis mesh class
    m_axisMesh->init();

    // Initialize the scatter points class
    m_surfaceScatter->init();
}

Метод GLWidget paintGL:

void GLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

...

    // Draw the mesh
    m_axisMesh->draw(m_camera.data(), modelMatrix);

    // Draw the points
    m_surfaceScatter->draw(m_camera.data(), modelMatrix);
}

Метод инициализации осевой сетки:

void PlotItemAxisMesh::init()
{
    initializeOpenGLFunctions();

    // Initialize the shaders
    initShaders();

    m_program->link();
    m_program->bind();

    // Load the data into the local VBO
    build();

    // Release (unbind) all
    m_program->release();
}

Метод построения осевой сетки:

void PlotItemAxisMesh::build()
{
    ShmooPlotMatrix *matrix = m_plotManager->getPlotPointMatrix();

    // Calculate the y-axis height in OpenGL terms
    uint32_t yHeight = (m_xMax + m_yMax)/2;
    float yScale     = yHeight / fabs(m_axisScale->getMax() - m_axisScale->getMin());
    float yOffset    = 0 ? m_axisScale->getMin() > 0 : -m_axisScale->getMin();

    // Since we swept X/Y but are plotting the points as X/Z, then Y becomes the value
    m_xMax = matrix->getXMax();
    m_yMax = yHeight;
    m_zMax = matrix->getYMax();

    m_vertexArray.clear();
    m_vertexArray.reserve(4*(m_xMax + m_yMax));

... (load vertexAray with data)

    m_vertexBuffer.create();
    m_vertexBuffer.bind();
    m_vertexBuffer.setUsagePattern(QOpenGLBuffer::DynamicDraw);
    m_vertexBuffer.allocate(&(m_vertexArray.front()), vertexSize);

    // Tell VBO how to read the data
    m_positionAttrIndex = m_program->attributeLocation(m_positionAttr);
    m_colorAttrIndex    = m_program->attributeLocation(m_colorAttr);

    int offset = 0;
    m_program->enableAttributeArray(m_positionAttrIndex);
    m_program->setAttributeBuffer(m_positionAttrIndex, GL_FLOAT, offset, 3, sizeof(VertexData));

    offset = sizeof(QVector3D);
    m_program->enableAttributeArray(m_colorAttrIndex);
    m_program->setAttributeBuffer(m_colorAttrIndex, GL_FLOAT, offset, 3, sizeof(VertexData));

    // Release (unbind) all
    m_vertexBuffer.release();
}

Метод рисования осевой сетки:

void PlotItemAxisMesh::draw(PlotCamera *camera, const QMatrix4x4 &modelMatrix)
{

    m_program->bind();
    {
        // Set modelview-projection matrix
        m_program->setUniformValue("mvpMatrix",  camera->getProjection() * camera->getView() * modelMatrix);
        m_vertexBuffer.bind();
        glDrawArrays(GL_LINES, 0, m_vertexArray.size());
        m_vertexBuffer.release();
    }
    m_program->release();
}

person Alchete    schedule 26.04.2015    source источник
comment
Я не знаком с Qt, но подозреваю, что проблема связана с тем, как вы настраиваете атрибуты вершин. Состояние настройки вершины не является частью программы. Поскольку у вас есть методы для настройки состояния вершины в классе программы, похоже, что это так, что, вероятно, сбивает вас с толку. Программа и состояние вершины не связаны между собой, и наличие методов для их установки в одном классе выглядит неудачно.   -  person Reto Koradi    schedule 26.04.2015
comment
Спасибо Рето. С точки зрения дизайна, если у меня есть два объекта, для которых требуются разные шейдеры, как бы вы их настроили? Если не инкапсулировать шейдерную программу как часть объекта, что бы вы порекомендовали?   -  person Alchete    schedule 26.04.2015
comment
Если моя теория верна, вы, вероятно, сможете заставить ее работать, выполнив вызовы enableAttributeArray() и setAttributeBuffer() в методе draw().   -  person Reto Koradi    schedule 26.04.2015
comment
Более эффективной альтернативой настройке атрибутов вершин в каждом вызове draw является использование объектов массива вершин GL (VAO). Вы устанавливаете несколько VAO в методе initializeGL, когда переключаетесь между ними в методе draw. В Qt есть оболочка QOpenGLVertexArrayObject.   -  person seva titov    schedule 26.04.2015
comment
Рето, твое объяснение наконец-то стало для меня понятным, и твое предложение сработало! Если вы хотите опубликовать это как решение, я отмечу его как принятое. Спасибо и С.Т. для вашей помощи! Ваше здоровье.   -  person Alchete    schedule 26.04.2015


Ответы (1)


Спасибо @Reto Koradi за решение

Исправление заключалось в том, чтобы изменить методы отрисовки, чтобы включить/установить буферы атрибутов во время отрисовки.

void PlotItemAxisMesh::draw(PlotCamera *camera, const QMatrix4x4 &modelMatrix)
{
    m_program->bind();
    {
        m_vertexBuffer.bind();

        int offset = 0;
        m_program->enableAttributeArray(m_positionAttrIndex);
        m_program->setAttributeBuffer(m_positionAttrIndex, GL_FLOAT, offset, 3, sizeof(VertexData));

        offset = sizeof(QVector3D);
        m_program->enableAttributeArray(m_colorAttrIndex);
        m_program->setAttributeBuffer(m_colorAttrIndex, GL_FLOAT, offset, 3, sizeof(VertexData));

        // Set modelview-projection matrix
        m_program->setUniformValue("mvpMatrix",  camera->getProjection() * camera->getView() * modelMatrix);

        glDrawArrays(GL_LINES, 0, m_vertexArray.size());
        m_vertexBuffer.release();
    }
    m_program->release();
}

Правильный рисунок

введите здесь описание изображения

person Alchete    schedule 26.04.2015