1
votes

I recently needed to implement a function in the QT+OPENGL environment, that is, I drew a cube (presumably in the center of the view) in my own defined framebuffer (I defined it as fbo) and colored it in red. And nothing is drawn in the default buffer, so I can't see my cube in the view (but it is drawn in the framebuffer fbo)

I hope that when I click in the middle of the view (the position of the cube), I can display the color of the cube----red instead of the color of the background of the view.

Here are the problems I have encountered: I can only get the color of the background of the view with the mouse, and the cube drawn in the frame buffer is not picked up (the cube is red).

In the initializeGL() function, I initialized and configured the framebuffer fbo and some of the configuration required to draw the cube.

In the paintGL() function, I bind my defined framebuffer to GL_FRAMEBUFFER and then do the drawing.

In the mousePressEvent(QMouseEvent *e) function, I did the picking work. This is the response function of the QT mouse click. I put the information read by glReadPixels into the array pix and print it out.

void OpenglWidget::initializeGL()
{   
        core1 = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_0_Core>();    
        core = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
        core->glGenFramebuffers(1, &fbo);
        core->glBindFramebuffer(GL_FRAMEBUFFER, fbo);
        // Create the texture object for the primitive information buffer
        core->glGenTextures(1, &m_pickingTexture);
        glBindTexture(GL_TEXTURE_2D, m_pickingTexture);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32UI, SCR_WIDTH, SCR_HEIGHT,
                    0, GL_RGB_INTEGER, GL_UNSIGNED_INT, NULL);
        core1->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D,
                    m_pickingTexture, 0);
        // Create the texture object for the depth buffer
        core->glGenTextures(1, &m_depthTexture);
        core->glBindTexture(GL_TEXTURE_2D, m_depthTexture);
        core->glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SCR_WIDTH, SCR_HEIGHT,
                    0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
        core1->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
                    m_depthTexture, 0);
        // Disable reading to avoid problems with older GPUs
        core->glReadBuffer(GL_NONE);
        // Verify that the FBO is correct
        GLenum Status = core->glCheckFramebufferStatus(GL_FRAMEBUFFER);
        if (Status == GL_FRAMEBUFFER_COMPLETE) {
            qDebug() << "ok";
        }
        // Restore the default framebuffer
        core->glBindTexture(GL_TEXTURE_2D, 0);
        core->glBindFramebuffer(GL_FRAMEBUFFER, 0);

        GLfloat verticPosition[] = {
        -0.5f, -0.5f, -0.5f,
         0.5f, -0.5f, -0.5f,
         0.5f,  0.5f, -0.5f,
         0.5f,  0.5f, -0.5f,
        -0.5f,  0.5f, -0.5f,
        -0.5f, -0.5f, -0.5f,

        -0.5f, -0.5f,  0.5f,
         0.5f, -0.5f,  0.5f,
         0.5f,  0.5f,  0.5f,
         0.5f,  0.5f,  0.5f,
        -0.5f,  0.5f,  0.5f,
        -0.5f, -0.5f,  0.5f,

        -0.5f,  0.5f,  0.5f,
        -0.5f,  0.5f, -0.5f,
        -0.5f, -0.5f, -0.5f,
        -0.5f, -0.5f, -0.5f,
        -0.5f, -0.5f,  0.5f,
        -0.5f,  0.5f,  0.5f,

         0.5f,  0.5f,  0.5f,
         0.5f,  0.5f, -0.5f,
         0.5f, -0.5f, -0.5f,
         0.5f, -0.5f, -0.5f,
         0.5f, -0.5f,  0.5f,
         0.5f,  0.5f,  0.5f,

        -0.5f, -0.5f, -0.5f,
         0.5f, -0.5f, -0.5f,
         0.5f, -0.5f,  0.5f,
         0.5f, -0.5f,  0.5f,
        -0.5f, -0.5f,  0.5f,
        -0.5f, -0.5f, -0.5f,

        -0.5f,  0.5f, -0.5f,
         0.5f,  0.5f, -0.5f,
         0.5f,  0.5f,  0.5f,
         0.5f,  0.5f,  0.5f,
        -0.5f,  0.5f,  0.5f,
        -0.5f,  0.5f, -0.5f,
    };
    GLint beamIndices[] = {
        0,1,2,3,4,5,6,7
    };

    core->glGenVertexArrays(1, &VAOBeam);
    core->glGenBuffers(1, &VBOBeam);
    core->glGenBuffers(1, &EBOBeam);
    core->glBindVertexArray(VAOBeam);
    core->glBindBuffer(GL_ARRAY_BUFFER, VBOBeam);
    core->glBufferData(GL_ARRAY_BUFFER,sizeof(float) * 3 * 36, verticPosition, GL_STATIC_DRAW);
    core->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBOBeam);
    core->glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLint) * 8, beamIndices, GL_STATIC_DRAW);

    core->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    core->glEnableVertexAttribArray(0);
    core->glBindBuffer(GL_ARRAY_BUFFER, 0);
    core->glBindVertexArray(0);
}

void OpenglWidget::paintGL()
{
    core->glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    glClearColor(0,0,1,1);
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    float frametime =GetFrameTime();
    mCamera.Update(frametime);
    Shader GLprogram =  Shader("E:\\QT\\OpenglTest\\vs.vert","E:\\QT\\OpenglTest\\fs.frag");
    GLprogram.use();
    core->glBindVertexArray(VAOBeam); 
    glm::mat4 model = glm::mat4(1.0f);
    model = glm::translate(model, mCamera.TempTranslateVrc);
    glm::mat4 view = glm::mat4(1.0f);
    //view = glm::lookAt(glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.5f,0.5f,0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
    view = glm::lookAt(mCamera.mPos,mCamera.mViewCenter,mCamera.mUp);
    glm::mat4 projection = glm::mat4(1.0f);
    projection = glm::perspective(glm::radians(45.0f), (float)1.0, 0.1f, 100.0f);
    GLprogram.setMatrix4f("model",model);
    GLprogram.setMatrix4f("view",view);
    GLprogram.setMatrix4f("projection",projection);
    core->glDrawArrays(GL_TRIANGLES,0,36);
    core->glUseProgram(0);
    update();
}
void OpenglWidget::mousePressEvent(QMouseEvent *e)
{
    core1 = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_0_Core>();
    float pix[4] = {0.0};
    mCamera.getInitPos(e->x(),e->y());//This is the camera's setup function, no need to worry about it.
    core1->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
    core1->glReadBuffer(GL_COLOR_ATTACHMENT1);
    core1->glReadPixels(e->x() , 500 - e->y() + 65, 1, 1, GL_RGBA, GL_FLOAT, pix);
    qDebug() << e->x()<< 500 - e->y() <<pix[0] << pix[1] << pix[2] << pix[3];
}

I can only get the color of the background of the view with the mouse, and the cube drawn in the frame buffer is not picked up (the cube is red).

1

1 Answers

1
votes

The issue is caused, because in the color buffer attached to GLCOLOR ATTACHMENT1, never is rendered to.

The name of the enumerator constant for the 1st color buffer, which can be attached by glFramebufferTexture2D to a framebuffer is GL_COLOR_ATTACHMENT0, rather than not GL_COLOR_ATTACHMENT1:

void OpenglWidget::initializeGL()
{
    // [...]

    core1->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
        GL_COLOR_ATTACHMENT0, // <---- GL_COLOR_ATTACHMENT0 instead of GL_COLOR_ATTACHMENT1
        GL_TEXTURE_2D,
        m_pickingTexture, 0);

    // [...]
}
void OpenglWidget::mousePressEvent(QMouseEvent *e)
{
    // [...]        

    core1->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
    core1->glReadBuffer(GL_COLOR_ATTACHMENT0); // <---- GL_COLOR_ATTACHMENT0

    // [ ...]
}

Note, by default it is rendered to the first color buffer (GL_COLOR_ATTACHMENT0) of a framebuffer. If you want to render to an other color buffer, than the 1st one, then you would have to specify a color buffer (list) explicitly by glDrawBuffers.


See OpenGL 4.6 API Core Profile Specification; 17.4.1 Selecting Buffers for Writing; page 513:

17.4.1 Selecting Buffers for Writing

[...] The set of buffers of a framebuffer object to which all fragment colors are written is controlled with the commands

void DrawBuffers( sizei n, const enum *bufs );
void NamedFramebufferDrawBuffers( uint framebuffer, sizei n, const enum *bufs );

[...] For framebuffer objects, in the initial state the draw buffer for fragment color zero is COLOR_ATTACHMENT0. For both the default framebuffer and framebuffer objects, the initial state of draw buffers for fragment colors other then zero is NONE.