2017-02-15 47 views
0

我想写一个应用程序,通过OpenGL渲染纹理到QML项目中。在网上搜索并尝试各种各样的东西之后(感觉像猜测很多,我对OpenGl的理解非常有限),我最终通过Valgrind运行该程序并发现非法内存访问,这意味着我没有初始化所需的所有内容OpenGl绘制正确。我希望有人可以看看我粗略的代码,并告诉我我忘记了哪一步。合并OpenGl和QML时在glDrawArrays上的Segfault

我试着跟上,在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 bind\n"; 

     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 failed\n"; 
     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 link\n"; 
     if (!program->bind()) std::cerr << "Error: Program failed to bind\n"; 
     program->setUniformValue("texture", 0); 
    } 

paint()是一个连接到QQuickWindow :: beforeRendering信号的插槽。使用调试器进行调试告诉我,paint()被调用时,所有指针(纹理,程序)都不为空。没有一个OpenGL调用会抛出错误,程序只是在glDrawArrays的paint()中进行段错误。

谢谢!

编辑:进一步的调试教会了我,它成功地通过了paint函数一次,它在第二次通过时失败了。但是,我从来没有看到完全绘制纹理,只是应用背景填充

回答

0

涂料功能应该写成如下保持状态,并防止在图纸上段错误:

if (!program) initializeGL(); 
    program->bindAttributeLocation("vertex", PROGRAM_VERTEX_ATTRIBUTE); 
    program->bindAttributeLocation("texCoord", PROGRAM_TEXCOORD_ATTRIBUTE); 
    if (!program->bind()) std::cerr << "Error: Program failed to bind\n"; 
    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();