合并OpenGl和QML时,在glDrawArrays上的Segfault
我试图编写一个应用程序,通过OpenGL渲染纹理到QML项目中。 在网上搜索并尝试各种各样的东西之后(感觉像猜测很多,我对OpenGl的理解非常有限),我最终通过Valgrind运行该程序并发现非法内存访问,这意味着我没有初始化所需的所有内容OpenGl绘制正确。 我希望有人可以看看我粗略的代码,并告诉我我忘记了哪一步。
我试图关注并结合QT文档中的两个教程,这个教程(http://doc.qt.io/qt-5/qtquick-scenegraph-openglunderqml-example.html)显示了QML和OpenGl,以及这个(http://doc.qt.io/qt-5/qtopengl-textures-example.html)演示了如何使用OpenGl和QT渲染纹理。 我稍微改变了它,因为我的纹理只是我希望展示的二维图像。 我能够成功地跟随后者,将我的纹理渲染到视口并在屏幕上绘制,不幸的是,当尝试集成QML的东西变得越来越慢时,
我的绘画功能如下:
void glViewer::paint()
{
// program is type QOpenGLShaderProgram *
if (!program) initializeGL();
if (!program->bind()) std::cerr << "Error: Program failed to bindn";
glViewport(0, 0, _viewportSize.width(), _viewportSize.height());
glClearColor(clearColor.redF(), clearColor.greenF(), clearColor.blackF(), clearColor.alphaF());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QMatrix4x4 m;
m.ortho(0.0f, 1.0f, 1.0f, 0.0f, 4.0f, 15.0f);
m.translate(0.0f, 0.0f, -10.0f);
program->setUniformValue("matrix", m);
program->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
program->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
program->setAttributeBuffer(PROGRAM_VERTEX_ATTRIBUTE, GL_FLOAT, 0, 3, 5 * sizeof(GLfloat));
program->setAttributeBuffer(PROGRAM_TEXCOORD_ATTRIBUTE, GL_FLOAT, 3 * sizeof(GLfloat), 2, 5 * sizeof(GLfloat));
texture->bind();
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
program->disableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
program->disableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
program->release();
// _window refers the QQuickWindow generated by the QApplication
_window->resetOpenGLState();
}
如果没有着色器程序,第一行调用intializeGL(),这是我相信问题所在。 该功能定义如下:
void glViewer::initializeGL()
{
initializeOpenGLFunctions();
texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
texture->setSize(imageDisplayResolution.x,imageDisplayResolution.y,1);
texture->setMinMagFilters(QOpenGLTexture::Nearest, QOpenGLTexture::Nearest);
texture->setWrapMode(QOpenGLTexture::ClampToBorder);
texture->setFormat(QOpenGLTexture::TextureFormat::R32F);
texture->allocateStorage(QOpenGLTexture::Luminance, QOpenGLTexture::Float32);
if (!texture->isStorageAllocated()) std::cerr << "Error: Failed to allocate texture!n";
QVector<GLfloat> vertData;
// vertex position
vertData.append(0);
vertData.append(0);
vertData.append(0);
// texture coordinate
vertData.append(0);
vertData.append(0);
// vertex position
vertData.append(0);
vertData.append(1);
vertData.append(0);
// texture coordinate
vertData.append(0);
vertData.append(1);
// vertex position
vertData.append(1);
vertData.append(1);
vertData.append(0);
// texture coordinate
vertData.append(1);
vertData.append(1);
// vertex position
vertData.append(1);
vertData.append(0);
vertData.append(0);
// texture coordinate
vertData.append(1);
vertData.append(0);
vbo.create();
if (!vbo.bind()) std::cerr << "Error: VBO bind has failedn";
vbo.allocate(vertData.constData(), vertData.count() * sizeof(GLfloat));
// Enable or disable server-side GL capabilities.
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
#define PROGRAM_VERTEX_ATTRIBUTE 0
#define PROGRAM_TEXCOORD_ATTRIBUTE 1
program = new QOpenGLShaderProgram;
if (!program->addShaderFromSourceCode(QOpenGLShader::Vertex,
"attribute highp vec4 vertex;n"
"attribute mediump vec4 texCoord;n"
"varying mediump vec4 texc;n"
"uniform mediump mat4 matrix;n"
"void main(void)n"
"{n"
" gl_Position = matrix * vertex;n"
" texc = texCoord;n"
"}n")) { std::cerr << "Error: Vertex shader failed to compile!n"; }
if (!program->addShaderFromSourceCode(QOpenGLShader::Fragment,
"uniform sampler2D texture;n"
"varying mediump vec4 texc;n"
"void main(void)n"
"{n"
" gl_FragColor = texture2D(texture, texc.st).rrra;n"
"}n")) { std::cerr << "Error: Fragment shader failed to compile!n"; }
// Binds the attribute name to the specified location.
program->bindAttributeLocation("vertex", PROGRAM_VERTEX_ATTRIBUTE);
program->bindAttributeLocation("texCoord", PROGRAM_TEXCOORD_ATTRIBUTE);
if (!program->link()) std::cerr << "Error: Program shaders failed to linkn";
if (!program->bind()) std::cerr << "Error: Program failed to bindn";
program->setUniformValue("texture", 0);
}
paint()是一个连接到QQuickWindow :: beforeRendering信号的插槽。 使用调试器进行调试告诉我,paint()被调用时,所有指针(纹理,程序)都不为空。 没有一个OpenGL调用会抛出错误,程序只是在glDrawArrays的paint()中进行段错误。
谢谢!
编辑:进一步的调试已经教会了我,它成功地通过了paint函数一次,它在第二次传递失败。 但是,我从来没有看到完全绘制的纹理,只是填充了应用程序背景。
绘图函数应该写成如下以保持状态并防止绘图上的段错误:
if (!program) initializeGL();
program->bindAttributeLocation("vertex", PROGRAM_VERTEX_ATTRIBUTE);
program->bindAttributeLocation("texCoord", PROGRAM_TEXCOORD_ATTRIBUTE);
if (!program->bind()) std::cerr << "Error: Program failed to bindn";
texture->bind();
vbo.bind();
glClearColor(_clearColor.redF(), _clearColor.greenF(), _clearColor.blackF(), _clearColor.alphaF());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(viewportPosition.x(), viewportPosition.y(), viewportSize.width(), viewportSize.height());
QMatrix4x4 m;
m.ortho(0.0f, 1.0f, 1.0f, 0.0f, 4.0f, 15.0f);
m.translate(0.0f, 0.0f, -10.0f);
program->setUniformValue("matrix", m);
program->setUniformValue("texture", 0);
program->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
program->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
program->setAttributeBuffer(PROGRAM_VERTEX_ATTRIBUTE, GL_FLOAT, 0, 3, 5 * sizeof(GLfloat));
program->setAttributeBuffer(PROGRAM_TEXCOORD_ATTRIBUTE, GL_FLOAT, 3 * sizeof(GLfloat), 2, 5 * sizeof(GLfloat));
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
program->disableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
program->disableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
program->disableAttributeArray(0);
program->release();
texture->release();
vbo.release();
_window->resetOpenGLState();
链接地址: http://www.djcxy.com/p/63883.html