Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Error when use stencil buffer in FBO(QOpenGLFramebufferObject)



  • I try to draw concave polygon in a fbo like this(which is simply a triangle in a square), and I successfully draw it in QOpenGLWidget:
    test_openglwidget_render_m663gaaEPU.png
    However when I want to draw it in a FBO and convert it to an image to save, the result is always wrong( just a black image).I draw the concave polygon with stencil buffer enabled, here is all code(project package download):


    main.cpp:

    #include <QApplication>
    #include "renderwidget.h"
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        RenderWidget pw;
        pw.show();
    
        return a.exec();
    }
    

    renderwidget.h:

    #ifndef RENDERWIDGET_H
    #define RENDERWIDGET_H
    
    #include <QOpenGLWidget>
    #include <QOpenGLFunctions_3_3_Compatibility>
    #include <QOpenGLShaderProgram>
    #include <QOpenGLFramebufferObject>
    
    class RenderWidget : public QOpenGLWidget, protected QOpenGLFunctions_3_3_Compatibility
    {
    public:
        RenderWidget(QWidget *parent = nullptr);
    
    protected:
        void initializeGL() override;
        void paintGL() override;
    
    private:
        QSharedPointer<QOpenGLShaderProgram> mProgram = nullptr;
        QSharedPointer<QOpenGLFramebufferObject> mFBO = nullptr;
        GLuint mPosAttr;
        GLuint mColAttr;
        GLuint mMatrixUniform;
    };
    
    #endif // RENDERWIDGET_H
    

    renderwidget.cpp:

    #include "renderwidget.h"
    #include <QDebug>
    
    RenderWidget::RenderWidget(QWidget *parent) : QOpenGLWidget(parent)
    {
        this->resize(800, 600);
    }
    
    void RenderWidget::initializeGL()
    {
        initializeOpenGLFunctions();
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    
        if (mProgram.isNull())
        {
            mProgram.reset(new QOpenGLShaderProgram(this));
            mProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/vertex.vert");
            mProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/frag.frag");
            if (!mProgram->link())
            {
                qDebug() << "Program was not linked right ";
            }
            else
            {
                mPosAttr = mProgram->attributeLocation("posAttr");
                mColAttr = mProgram->attributeLocation("colAttr");
                mMatrixUniform = mProgram->uniformLocation("matrix");
            }
        }
    
        if (mFBO.isNull())
        {
            QOpenGLFramebufferObjectFormat format;
            format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
            format.setSamples(0);
            mFBO.reset(new QOpenGLFramebufferObject(1920, 1080, format));
            qDebug() << QString("FBO attachment is %1, texture target is %2")
                        .arg(mFBO->format().attachment())
                        .arg(mFBO->format().textureTarget());
        }
    }
    
    void RenderWidget::paintGL()
    {
        mFBO->bind();   //If u want to see the effect without fbo, comment this line
    
        glViewport(0, 0, 1920, 1080);
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
    
        glFrontFace(GL_CW);
        glCullFace(GL_FRONT);
        glEnable(GL_CULL_FACE);
        glEnable(GL_DEPTH_TEST);
    
        mProgram->bind();
    
        QMatrix4x4 matrix;
        matrix.setToIdentity();
        matrix.ortho(0.0f, 1920.0f, 0.0f, 1080.0f, -1.0f, 1.0f);
        mProgram->setUniformValue(mMatrixUniform, matrix);
    
        QVector<float> pts;
        pts << 300 << 300
            << 900 << 300
            << 900 << 900
            << 300 << 900;
        pts << 750 << 750
            << 450 << 750
            << 450 << 450;
        QVector<int> startPosVec;
        startPosVec << 0
                    << 4
                       ;
        QVector<int> countVec;
        countVec << 4
                 << 3
                    ;
    
        QVector<float> colVec;
        for (const auto &c : countVec)
            for (int i = 0; i < c; i++)
                colVec << float(1.0f) << float(1.0f) << float(1.0f);
    
        this->glVertexAttribPointer(mPosAttr, 2, GL_FLOAT, GL_FALSE, 0, pts.data());
        this->glVertexAttribPointer(mColAttr, 3, GL_FLOAT, GL_FALSE, 0, colVec.data());
        this->glEnableVertexAttribArray(mPosAttr);
        this->glEnableVertexAttribArray(mColAttr);
    
        this->glClear(GL_STENCIL_BUFFER_BIT);
        this->glClearStencil(0x0);
        this->glEnable(GL_STENCIL_TEST);
        this->glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
        this->glStencilFunc(GL_ALWAYS, 0x1, 0x1);
        this->glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT);
        this->glDisable(GL_DEPTH_TEST);
    
        this->glMultiDrawArrays(GL_TRIANGLE_FAN, startPosVec.data() , countVec.data(), countVec.size());
    
        this->glEnable(GL_DEPTH_TEST);
        this->glStencilFunc(GL_NOTEQUAL, 0, 0x1);
        this->glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
        this->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    
        //this->glMultiDrawArrays(GL_TRIANGLE_FAN, startPosVec.data() , countVec.data(), countVec.size());
        GLfloat vertices[] = {
            100.0f, 100.0f,
            1900.0f, 100.0f,
            1900.0f, 1000.0f,
            100.0f, 1000.0f
        };
        GLfloat colors[] = {
            1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f
        };
        this->glDisableVertexAttribArray(mPosAttr);
        this->glDisableVertexAttribArray(mColAttr);
        this->glVertexAttribPointer(mPosAttr, 2, GL_FLOAT, GL_FALSE, 0, vertices);
        this->glVertexAttribPointer(mColAttr, 3, GL_FLOAT, GL_FALSE, 0, colors);
        this->glEnableVertexAttribArray(mPosAttr);
        this->glEnableVertexAttribArray(mColAttr);
        this->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
    
        this->glDisable(GL_STENCIL_TEST);
        this->glDisableVertexAttribArray(mPosAttr);
        this->glDisableVertexAttribArray(mColAttr);
    
        mFBO->release();
        mProgram->release();
    
        glDisable(GL_CULL_FACE);
        glDisable(GL_DEPTH_TEST);
        this->glFlush();
    
        mFBO->toImage().save("./test.png");
    }
    

    vertex.vert:

    attribute highp vec4 posAttr;
    attribute lowp vec4 colAttr;
    varying lowp vec4 col;
    uniform highp mat4 matrix;
    void main() {
        col = colAttr;
        gl_Position = matrix * posAttr;
    }
    

    frag.frag:

    varying lowp vec4 col;
    void main() {
       gl_FragColor = col;
    }
    

    reference:
    Stackoverflow: Draw a concave polygon in OpenGL



  • So could anyone give some advice? :(


Log in to reply