I have a QGLWidget (Qt 5.2.1).
The GLWidget instantiates two other classes that each contain their own QOpenGLShaderPrograms, load their own shaders, and handle their own drawing. This makes for a nice encapsulation.
HOWEVER -- the issue is that the data from the axis mesh (first one being initialized) is appearing in the second class's shader. So, it never draws its own object with its own shader. If I reverse the order of init() calls, the same thing happens in reverse.
The two drawing classes are structured identically, so I'm including only the Mesh class for brevity.
Here's the result. The AxisMesh, which draws lines, is drawing them over the Scatter class, with the same color, instead of in their own color and where they're supposed to be drawn.
The lines in this picture should be a different color and a different location:
QUESTIONS:
Is it allowed to have two QOpenGLShaderPrograms in a QGLWidget?
Is there something wrong with the approach below?
GLWidget initialzeGL method:
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 method:
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);
}
Axis Mesh init method:
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();
}
Axis Mesh build method:
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();
}
Axis Mesh draw method:
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();
}
Thank you to @Reto Koradi for the solution
The fix was to change the draw methods to enable/set the attribute buffers at draw-time.
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();
}
Proper drawing