Можно ли прочитать один образец из MSAA FBO?

Используя OpenGL для рисования объектов, а также чтобы мой фрагментный шейдер выдал скалярный целочисленный идентификатор. Для рисования объектов я использую мультисэмплинг для сглаживания, поэтому, когда я создаю буфер для целочисленного идентификатора, я должен создать его как буфер MSAA, чтобы FBO было завершено:

  glBindRenderbuffer(GL_RENDERBUFFER, rboColorId);
  glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaaSamples, GL_RGBA8,
                        cam.getWidth(), cam.getHeight());
  glBindRenderbuffer(GL_RENDERBUFFER, rboDepthId);
  glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaaSamples, GL_DEPTH_COMPONENT,
                        cam.getWidth(), cam.getHeight());
  glBindRenderbuffer(GL_RENDERBUFFER, rboObjId);
  glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaaSamples, GL_R32UI,
                        cam.getWidth(), cam.getHeight());
  glBindRenderbuffer(GL_RENDERBUFFER, rboColorNoMsaaId);
  glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8,
                        cam.getWidth(), cam.getHeight());
  glBindRenderbuffer(GL_RENDERBUFFER, rboObjNoMsaaId);
  glRenderbufferStorage(GL_RENDERBUFFER, GL_R32UI,
                        cam.getWidth(), cam.getHeight());

  glBindRenderbuffer(GL_RENDERBUFFER, 0);
  glBindFramebuffer(GL_FRAMEBUFFER, fboId);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rboColorId);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,  GL_RENDERBUFFER, rboDepthId);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, rboObjId);
  glBindFramebuffer(GL_FRAMEBUFFER, fboNoMsaaId);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rboColorNoMsaaId);
  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, rboObjNoMsaaId);

Как вы можете видеть в коде выше, у меня есть 2 FBO. Первый - это MSAA, в котором есть буфер для рисования сцены, буфер глубины и целочисленный буфер для идентификаторов. Второе FBO с одиночной выборкой (не MSAA) и имеет только буфер сцены рисования и буфер целых чисел. После того, как я нарисовал все (фрагментный шейдер устанавливает значения для каждого пикселя), я прочитал буфер целочисленного идентификатора (GL_COLOR_ATTACHMENT1), сначала перетащив его в одиночный FBO выборки, чтобы я мог получить из него glReadPixels. В этом конкретном коде я просто читаю 1 пиксель, на который указывает мышь:

  glBindFramebuffer(GL_READ_FRAMEBUFFER, fboId);
  glReadBuffer(GL_COLOR_ATTACHMENT1);
  glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboNoMsaaId);
  glDrawBuffer(GL_COLOR_ATTACHMENT1);
  glBlitFramebuffer(mouse_x_pos, cam.getHeight() - mouse_y_pos, mouse_x_pos+1, cam.getHeight() - mouse_y_pos + 1,
                    0, 0, 1, 1,
                    GL_COLOR_BUFFER_BIT, GL_NEAREST);
  glBindFramebuffer(GL_READ_FRAMEBUFFER, fboNoMsaaId);
  glReadBuffer(GL_COLOR_ATTACHMENT1);
  GLuint objectId;
  glReadPixels(0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, &objectId);

Моя проблема в том, что когда я блею, мультисэмплы для нужного пикселя интерполируются в один пиксель, который я получаю для чтения. Я хочу это для цветового буфера, который я использую для рисования сцены, но я не хочу этого для целочисленных идентификаторов, которые я читаю. Если я читаю пиксель, который содержит фрагменты как для идентификатора 50, так и для идентификатора 100, я хочу прочитать либо 50, либо 100 (все равно, какие). Но то, что я получаю, это какое-то значение между 50 и 100, например 75. 75 на самом деле может быть совершенно другим пикселем, поэтому я не хочу этого вообще.

Что я могу сделать, чтобы прочитать один образец для целочисленного идентификатора вместо интерполяции нескольких образцов?

1 ответ

Решение

Вместо того, чтобы разрешать текстуру мультисэмпла путем блиттинга, вы можете реализовать собственное разрешение мультисэмпла на этапе рендеринга в текстуру. Вы можете использовать сэмплер типа sampler2DMS и использовать это texelFetch( variant:

gvec4 texelFetch( gsampler2DMS sampler, ivec2 P, int sample);

так P являются 2D ненормализованными текселевыми координатами, и sample это идентификатор образца. Если вы действительно не заботитесь о том, какое из значений вы получаете, вы можете просто использовать образец 0 все время. Но вы также можете, например, перебрать все образцы и взять тот, который встречается чаще всего, или любой другой, который соответствует вашим потребностям.

Чтобы это работало, вам придется переключиться с рендеринга буфера для прикрепления идентификатора на многосэмплированную 2D текстуру.

Таким образом, по сути, вы можете привязать немультисэмплированный FBO как рисовать FBO, сделать стандартный блик для текстур глубины и цвета, а также выполнить полноэкранный рендеринг с текстурой мультисэмплированного идентификатора, записав в цветовое приложение немультисэмплированного идентификатора.

Другие вопросы по тегам