c++ - 离屏渲染到帧缓冲区

标签 c++ opengl glfw framebuffer

我有一个简单的场景,它渲染了一个网格、一个平面和一个立方体。我也有两个不同的着色器。一个是平面着色器,它以随机颜色渲染对象,另一个是噪声着色器,它渲染具有噪声效果的对象。我希望能够:

  • 通过噪声着色器渲染平面和立方体,使用平面着色器渲染网格。
  • 一旦用户单击场景,我想仅使用平面着色器将整个场景渲染到(屏幕外)渲染缓冲区并打印通过 glReadPixels 获取的单击颜色.
  • 继续使用两个着色器渲染场景。

  • 基本上我想实现颜色选择。不过,它似乎不适用于立方体和飞机。像素值始终是来自噪声着色器的灰度值。

    这是我的绘图程序的样子:
    void Draw(const bool offscreen = false)
    {
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        glm::mat4 projection = glm::perspective(glm::radians(camera.zoom), (float)viewport_width / (float)viewport_height, 0.1f, 100.0f);
        glm::mat4 view = camera.get_view_matrix();
    
        if (offscreen)
        {
            flat_shader.use();
            flat_shader.set_mat4("projection", projection);
            flat_shader.set_mat4("view", view);
            grid.Draw(&flat_shader);
            box.Draw_offscreen(&flat_shader);
            plane.Draw_offscreen(&flat_shader);
        }
        else
        {
            noise_shader.use();
            noise_shader.set_mat4("projection", projection);
            noise_shader.set_mat4("view", view);
            noise_shader.set_float("iTime", delta_time);
            plane.Draw(&noise_shader);
            box.Draw(&noise_shader);
    
            flat_shader.use();
            flat_shader.set_mat4("projection", projection);
            flat_shader.set_mat4("view", view);
            grid.Draw(&flat_shader);
        }
    
        glfwSwapBuffers(window);
    }
    

    所以如果屏幕外是 false场景看起来像这样(正常渲染):

    enter image description here

    这就是 offscreen 时的场景。是 true :

    enter image description here

    这就是我创建 fbo 的方式:
    void init_offscreen_buffer()
    {
        glGenFramebuffers(1, &fbo_off);
        glGenRenderbuffers(1, &render_buf);
        glBindRenderbuffer(GL_RENDERBUFFER, render_buf);
        glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, viewport_width, viewport_height);
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_off);
        glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, render_buf);
        // I also checked for FRAMEBUFFER_COMPLETE
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
    }
    

    现在当用户点击我运行的场景时 pick_color_id在点击的像素上打印颜色。
    void pick_color_id(double x, double y)
    {
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_off);
    
        Draw(true);
    
        GLubyte pixel_color[4];
        glReadBuffer(GL_COLOR_ATTACHMENT0);
        glReadPixels(x, 800 - y - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel_color);
        cout << "---------------------------------------------------------" << endl;
        cout << "Mouse click position:  " << x << "; " << y << endl;
        cout << "Target pixel color:    " << (unsigned int)pixel_color[0] << ";" << (unsigned int)pixel_color[1] << ";" << (unsigned int)pixel_color[2] << endl;
        cout << "---------------------------------------------------------" << endl;
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
    }
    

    正如我在绑定(bind)缓冲区后看到的那样,它应该是渲染目标,它应该包含平面和立方体的平面颜色。实际上,它总是像在噪声着色器中一样打印灰度颜色。

    我认为我的 fbo 设置或使用有问题(可能两者都有)。我错过了什么?

    最佳答案

    glReadPixels从帧缓冲区读取日期,因此帧缓冲区绑定(bind)的目标必须是 GL_READ_FRAMEBUFFER不是 GL_DRAW_FRAMEBUFFER :

    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_off);
    
    Draw(true);
    
    GLubyte pixel_color[4];
    
    glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_off);
    glReadBuffer(GL_COLOR_ATTACHMENT0);
    glReadPixels(x, 800 - y - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel_color);
    

    分别

    glBindFramebuffer(GL_FRAMEBUFFER, fbo_off);
    
    Draw(true);
    
    GLubyte pixel_color[4];
    
    glReadBuffer(GL_COLOR_ATTACHMENT0);
    glReadPixels(x, 800 - y - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel_color);
    

    我建议启用 Debug Output用于查找 OpenGL 错误。例如:

    #include <iostream>
    
    void GLAPIENTRY DebugCallback( 
        unsigned int  source,
        unsigned int  type,
        unsigned int  id,
        unsigned int  severity, 
        int           length,
        const char   *message,
        const void   *userParam )
    {
       std::cout << message << std::endl;
    }
    
    void init_opengl_debug() {
        glDebugMessageCallback(&DebugCallback, nullptr );
        glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE);
        glEnable(GL_DEBUG_OUTPUT);
        glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
    }
    

    关于c++ - 离屏渲染到帧缓冲区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61046598/

    相关文章:

    c++ - 在 gcc linux x86-64 C++ 中,(p+x)-x 是否总是为指针 p 和整数 x 生成 p

    c++ - 声明和使用静态列表以打印对象(在 C++ 中)

    C++速度比较迭代器与索引

    java - 在java程序中运行OpenGL命令

    c++ - GLM Math lib 使用 GCC 编译错误

    d - 使用 GLFW 设置 Derelict3

    c# - C++ 中的 Google ProtoBuf 与 C# 中的 Protobuf-net 聊天(UDP)

    c++ - GLFW setUserPointer/getUserPointer 发送/访问类崩溃

    c++ - 使用键旋转对象

    Cmake 正在将某些内容安装到/usr/local/include 和/usr/lib 而不是/usr/include