Разрешение буфера кадров с несколькими выборками с несколькими цветными вложениями - PullRequest
2 голосов
/ 19 июня 2019

Пытаясь реализовать сглаживание поверх отложенного затенения, я пытаюсь использовать буферы рендеринга с несколькими выборками, а затем разрешать выборки с помощью прохода буфера-блита.

  1. Как обычно в отложенном затенении, я рендерил сцену с выделенным шейдером, выдавая 3 цветовых выхода:

    • Должность
    • нормали
    • Диффузный и зеркальный
  2. Затем они используются в проходе вычисления освещения, что приводит к окончательной текстуре сцены

  3. Текстура сцены отображается на экране в полноэкранном четырехугольнике с использованием упрощенного шейдера

Как вы, вероятно, догадались, экранное MSAA не применяется к содержимому текстуры сцены при визуализации на экране: таким образом, чтобы добиться сглаживания, я решил использовать буферы рендеринга с несколькими выборками на шаге 1) и ввел дополнительный шаг 1.1) для разрешения. Конечно, мультисэмплинг необходим / полезен только для цветовой карты, а не для 2 других карт.

Моя проблема и вопрос в том, что, очевидно, кадровый буфер с несколькими буферами рендеринга / цветными вложениями может быть определен только для одних и тех же типов вложений; Это означает, что если одно вложение является множественным, то все остальные должны быть.

Это становится проблемой для буферов положений и нормалей во время разрешения, потому что на геометрию и освещение влияет сглаживание.

  • Является ли мое понимание верным в отношении вложений кадрового буфера?
  • Есть ли способ обойти это, чтобы по-прежнему иметь множественную выборку на карте Diffuse & Specular, но не влиять на другие карты?
    // Create the frame buffer for deferred shading: 3 color attachments and a depth buffer
    glGenFramebuffers(1, &gBuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, gBuffer);
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    {
        // - Position color buffer
        glGenRenderbuffers(1, &gPosition);
        glBindRenderbuffer(GL_RENDERBUFFER, gPosition);
        glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_RGBA16F, w, h);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, gPosition);

        // - Normal color buffer
        glGenRenderbuffers(1, &gNormal);
        glBindRenderbuffer(GL_RENDERBUFFER, gNormal);
        glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_RGBA16F, w, h);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, gNormal);

        // - Color + specular color buffer
        glGenRenderbuffers(1, &gColorSpec);
        glBindRenderbuffer(GL_RENDERBUFFER, gColorSpec);
        glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_RGBA, w, h);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_RENDERBUFFER, gColorSpec);

        unsigned int attachments[3] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
        glDrawBuffers(3, attachments);

        // - Generate the depth buffer for rendering
        glGenRenderbuffers(1, &sceneDepth);
        glBindRenderbuffer(GL_RENDERBUFFER, sceneDepth);
        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h);
        glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_DEPTH_COMPONENT, w, h);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, sceneDepth);
    }
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    // Create a frame buffer with 3 attachments for sample resolution
    glGenFramebuffers(1, &gFrameRes);
    glBindFramebuffer(GL_FRAMEBUFFER, gFrameRes);
    {
        glGenTextures(1, &gPositionRes);
        glBindTexture(GL_TEXTURE_2D, gPositionRes);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, w, h, 0, GL_RGB, GL_FLOAT, nullptr);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gPositionRes, 0);

        glGenTextures(1, &gNormalRes);
        glBindTexture(GL_TEXTURE_2D, gNormalRes);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, w, h, 0, GL_RGBA, GL_FLOAT, nullptr);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, gNormalRes, 0);

        glGenTextures(1, &gColorSpecRes);
        glBindTexture(GL_TEXTURE_2D, gColorSpecRes);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, gColorSpecRes, 0);
    }
    glBindFramebuffer(GL_FRAMEBUFFER, 0);


    // ...
    //
    // Once the scene is rendered, resolve:
    glBindFramebuffer(GL_READ_FRAMEBUFFER, gBuffer);
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gFrameRes);
    glReadBuffer(GL_COLOR_ATTACHMENT0);
    glDrawBuffer(GL_COLOR_ATTACHMENT0);
    glBlitFramebuffer(0, 0, sw, sh, 0, 0, sw, sh, GL_COLOR_BUFFER_BIT, GL_LINEAR);
    glReadBuffer(GL_COLOR_ATTACHMENT1);
    glDrawBuffer(GL_COLOR_ATTACHMENT1);
    glBlitFramebuffer(0, 0, sw, sh, 0, 0, sw, sh, GL_COLOR_BUFFER_BIT, GL_LINEAR);
    glReadBuffer(GL_COLOR_ATTACHMENT2);
    glDrawBuffer(GL_COLOR_ATTACHMENT2);
    glBlitFramebuffer(0, 0, sw, sh, 0, 0, sw, sh, GL_COLOR_BUFFER_BIT, GL_LINEAR);
    glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

Результат приведенного выше примера кода состоит в том, что на краях освещенного объекта появляются артефакты неоправданно темных / черных или ярких / белых пикселей, возможно потому, что их положение и / или нормаль были изменены в процессе.

1 Ответ

2 голосов
/ 19 июня 2019

Это становится проблемой для буферов Positions и Normals во время разрешения, потому что геометрия и освещение влияют в результате сглаживания.

Это должно быть.

Логически некогерентно иметь положения и нормали, не использующие мультисэмплинг, в то время как получаются рассеянные / зеркальные цвета.Запомните, что такое мультисэмплинг: каждый пиксель имеет несколько выборок, и разные данные из перекрывающихся треугольников могут записывать разные выборки в одном пикселе.Таким образом, вы можете иметь диффузные / зеркальные цвета из двух или более треугольников в одном пикселе.Но это также означает, что у вас также должны быть позиции и нормали, связанные с каждым из этих цветов субпикселя.В противном случае ваш проход освещения не будет иметь смысла;вы бы использовали значения положения и нормы для цветов, которые их не генерировали.

Правильная мультисэмплинг с отложенным рендерингом стоит дорого .Единственный способ заставить его работать - это сэмплировать все, а затем выполнить вычисления прохода освещения на уровне per-sample .Поскольку большая часть выигрыша в производительности мультисэмплинга по сравнению с суперсэмплингом не выполняется вычислениями для каждого сэмпла, вы получаете преимущества мультисэмплинга (а не суперсэмплинга) на проходе геометрии, а не на проходе освещения.

Вот почему люди стараются избегать мультисэмплинга при использовании отложенного рендеринга.Вот почему существуют методы псевдо-сглаживания, такие как FXAA и все остальное.

...