QOpenGLShaderProgram - 多个实例产生损坏的结果
QOpenGLShaderProgram - multiple instances yield corrupt results
我有一个 QGLWidget (Qt 5.2.1)。
GLWidget 实例化另外两个 classes,每个都包含自己的 QOpenGLShaderPrograms,加载自己的着色器,并处理自己的绘图。这是一个很好的封装。
但是——问题是轴网格(第一个被初始化)的数据出现在第二个 class 的着色器中。因此,它从不使用自己的着色器绘制自己的对象。如果我颠倒 init() 调用的顺序,同样的事情也会反过来发生。
这两张图 class 的结构完全相同,因此为了简洁起见,我只包含网格 class。
这是结果。绘制线条的 AxisMesh 正在使用相同的颜色在散点图 class 上绘制它们,而不是使用它们自己的颜色和它们应该绘制的位置。
这张图片中的线条应该是不同的颜色和不同的位置:
问题:
一个QGLWidget可以有两个QOpenGLShaderProgram吗?
下面的方法有问题吗?
GLWidget初始化GL方法:
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();
}
Axis Mesh 构建方法:
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绘制方法:
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();
}
感谢@Reto Koradi 的解决方案
解决方法是将绘制方法更改为 enable/set 绘制时的属性缓冲区。
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();
}
正确绘图
我有一个 QGLWidget (Qt 5.2.1)。
GLWidget 实例化另外两个 classes,每个都包含自己的 QOpenGLShaderPrograms,加载自己的着色器,并处理自己的绘图。这是一个很好的封装。
但是——问题是轴网格(第一个被初始化)的数据出现在第二个 class 的着色器中。因此,它从不使用自己的着色器绘制自己的对象。如果我颠倒 init() 调用的顺序,同样的事情也会反过来发生。
这两张图 class 的结构完全相同,因此为了简洁起见,我只包含网格 class。
这是结果。绘制线条的 AxisMesh 正在使用相同的颜色在散点图 class 上绘制它们,而不是使用它们自己的颜色和它们应该绘制的位置。
这张图片中的线条应该是不同的颜色和不同的位置:
问题:
一个QGLWidget可以有两个QOpenGLShaderProgram吗?
下面的方法有问题吗?
GLWidget初始化GL方法:
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();
}
Axis Mesh 构建方法:
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绘制方法:
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();
}
感谢@Reto Koradi 的解决方案
解决方法是将绘制方法更改为 enable/set 绘制时的属性缓冲区。
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();
}
正确绘图