У меня есть простая сцена, которая отображает сетку, плоскость и куб. У меня также есть два разных шейдера. Один - плоский шейдер, который отображает объекты случайным цветом, другой - шумовой шейдер, который отображает объекты с эффектом шума. Я хочу иметь возможность:
- Рендеринг плоскости и куба с помощью шумового шейдера и сетки с плоским шейдером.
- Как только пользователь щелкнет сцену, я хочу рендеринг всей сцены в (закадровый) рендер-буфер, используя только плоский шейдер, и распечатывать выбранный цвет, полученный с помощью
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
, сцена выглядит следующим образом (нормально рендеринг):
Вот как выглядит сцена, когда 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);
}
Как я вижу после привязки буфера, он должен быть целью рендеринга и содержать плоские цвета для плоскости и куба. На самом деле он всегда печатает оттенки серого, как в шейдерном шуме.
Я думаю, что что-то не так с моей настройкой или использованием fbo (может быть, и то, и другое). Чего мне не хватает?