OpenGL реализует скайбокс в отложенном рендерере

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

1: (привязать FBO) Визуализация геометрии в цвете, нормальное положение текстурных вложений FBO (отменить привязку FBO).

2: (связать FBO) Отрисовать сцену и рассчитать освещение в пространстве экрана.(Убрать привязку FBO)

3: (привязать FBO) применить эффекты постобработки (отменить привязку FBO)

4: перевести буфер глубины Geometry FBO в буфер кадров по умолчанию

5: отрендерить скайбокс.

Я попытался переключить шаг 5 с 3, как это:

2: (связать FBO) Отрисовать сцену и рассчитать освещение в пространстве экрана.

5: рендерить скайбокс

(уберите FBO)

3: (привязать FBO) применить эффекты постобработки (отменить привязку FBO)

4: перевести буфер глубины Geometry FBO в буфер кадров по умолчанию

но, очевидно, скайбокс не имеет информации о глубине сцены и визуализирует поверх сцены освещения. И если я попытаюсь сделать какое-либо углубление глубины между 2 и 5, я думаю, что я делаю недопустимые вызовы GL, потому что я уже связан с FBO во время вызова

 GL30.glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, DeferredFBO.fbo_handle);
 GL30.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, 0); // Write to default
                                                            // framebuffer or a skybox framebuffer    


    GL30.glBlitFramebuffer(0, 0, DisplayManager.Width,
            DisplayManager.Height, 0, 0, DisplayManager.Width,
            DisplayManager.Height, GL11.GL_DEPTH_BUFFER_BIT,
            GL11.GL_NEAREST);

2 ответа

Решение

Затем предоставьте ему информацию о глубине, которой ему не хватает.

Когда вы визуализировали свою сцену на шаге 1, вы использовали буфер глубины. Поэтому, когда вы рисуете свой скайбокс, вам нужен FBO, который использует тот же буфер глубины. Но этому FBO также нужно использовать цветное изображение, которое вы визуализировали на шаге 2.

Теперь это FBO не может быть тем же FBO, которое вы использовали в шаге 2. Почему?

Потому что это было бы неопределенным поведением. Предположительно, шаг 2 считывает данные из буфера глубины, чтобы восстановить позицию (если это не так, тогда вы можете просто прикрепить буфер глубины к FBO из шага 2. Но опять же, вы также теряете массу производительности). Но этот буфер глубины также прикреплен к FBO. И это делает его неопределенным поведением. Даже если вы не пишете в глубину, это все еще не определено в OpenGL.

Таким образом, вам понадобится другое FBO, которое имеет буфер глубины из шага 1 с буфером цвета из шага 2.

Если у вас нет доступа к OpenGL 4.5 / ARB_texture_barrier / NV_texture_barrier. С этой функцией становится определенным поведение, если вы используете маски записи для отключения записи в буфер глубины. Все, что вам нужно сделать, это выдать glTextureBarrier перед выполнением шага 2. Так что вам не нужно другое FBO, если у вас есть.

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

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

Я фактически рендерил геометрию Skybox на этапе Geometry процесса отложенного рендеринга, я рендерил skybox и установил флаг в фрагментном шейдере, чтобы закрасить мой skybox, не забывая изменить матрицу вида, чтобы удалить перевод с другим унифицированным флагом в вершине. Shader. В фрагментном шейдере я установил цвет скайбокса как таковой. Вот основная сводка без вставки всего кода.

layout (binding = 4) uniform samplerCube cubeMap;
uniform float SkyRender;
void main(){
if(SkyRender){
vec4 SkyColor = texture(cubeMap, skyTexCoords);
gAlbedoSpec.rgb = SkyColor.rgb;
gAlbedoSpec.a = -1;
}else{
gAlbedoSpec.rgb = texture(DiffuseTexture, TexCoords);
gAlbedoSpec.a =   texture(SpecularTexture, TexCoords).r;
}

Я установил альфа-компонент моего скайбокса в буфере цвета как флаг для моего прохода освещения. Здесь я установил его на -1.

В моем проходе освещения я просто выбираю, чтобы окрасить свой блок Diffuse Only вместо добавления расчетов освещения, если мое альфа-значение gAlbedoSpec равно -1.

if(Diffuse.a > -1){
FragColor = SphereNormal * vec4(Dlighting, 1.0)+vec4(Slighting, 1.0);
}else{
FragColor = Diffuse ;
}

Это довольно просто и не требует много кода и выполняет свою работу.

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