繁体   English   中英

离屏渲染到帧缓冲区

[英]Offscreen rendering to Framebuffer

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

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

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

这是我的绘图程序的样子:

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的,场景看起来像这样(正常渲染):

在此处输入图像描述

这就是offscreen幕外为true时场景的样子:

在此处输入图像描述

这就是我创建 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);
}

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

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

glReadPixels从帧缓冲区读取日期,因此帧缓冲区绑定的目标必须是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);

我建议启用调试 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);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM