Странное поведение Z-Buffer

Я использую метод Deferred Shading для рендеринга сцены, но у меня проблема с техникой Skybox из-за странного поведения Z-Buffer. Я создал дополнительный Framebuffer и прикрепил 5 текстур, одна из которых используется в качестве буфера глубины. Первый проход — это геометрический проход, который заполняет текстуры необходимыми данными, второй проход визуализирует конечные объекты с текстурами и молниями, примененными к основному кадровому буферу, последний проход визуализирует Skybox. Проблема в том, что Skybox игнорируется (проверка Z-Buffer не проходит, поэтому она невидима).

При рендеринге Skybox я отображаю вторичный кадровый буфер как GL_READ_FRAMEBUFFER, а основной кадровый буфер (экран) — как GL_DRAW_FRAMEBUFFER, так что можно использовать буфер глубины вторичного кадрового буфера, затем я устанавливаю функцию глубины в GL_LEQUAL. И только если я изменю функцию глубины на GL_GREATER (или GL_ALWAYS), скайбокс можно будет увидеть, однако он рендерится поверх объектов.

Вершинный шейдер:

#version 330

layout (location = 0) in vec3 Position;

uniform mat4 M;
uniform mat4 V;
uniform mat4 P;

out vec3 TexCoord0;

void main()
{
vec4 MVP_Pos = P * V * M * vec4(Position, 1.0);
gl_Position = MVP_Pos.xyww;
TexCoord0 = Position;
}

Модель матрицы является продуктом перевода Skybox в координаты камеры.

Для glDepthFunction установлено значение GL_LEQUAL:
GL_LEQUAL

Для glDepthFunction установлено значение GL_GREATER:
GL_GREATER

Содержимое Z-буфера:
Z-буфер

ОБНОВЛЕНИЕ 1: я попытался использовать glBlitFramebuffer так:

glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo); //Additional framebuffer
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glDepthMask(GL_TRUE);
glBlitFramebuffer(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, GL_DEPTH_BUFFER_BIT, GL_NEAREST);

Но это не работает. Основной буфер глубины содержит массив черных пикселей.

ОБНОВЛЕНИЕ 2:

//FBO initialization
glGenFramebuffers(1, &m_fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo);

// Create gbuffer textures
glGenTextures(ARRAY_SIZE_IN_ELEMENTS(m_textures), m_textures);
glGenTextures(1, &m_depthTexture);

for (unsigned int i = 0; i < ARRAY_SIZE_IN_ELEMENTS(m_textures); i++) {
glBindTexture(GL_TEXTURE_2D, m_textures[i]);

glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, WindowWidth, WindowHeight, 0, GL_RGB, GL_FLOAT, NULL);

glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, m_textures[i], 0);
}

// depth buffer
glBindTexture(GL_TEXTURE_2D, m_depthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, WindowWidth, WindowHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT,
NULL);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_depthTexture, 0);

GLenum DrawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 };
glDrawBuffers(ARRAY_SIZE_IN_ELEMENTS(DrawBuffers), DrawBuffers);

GLenum Status = glCheckFramebufferStatus(GL_FRAMEBUFFER);

if (Status != GL_FRAMEBUFFER_COMPLETE) {
fprintf(stderr, "FB error, status: 0x%x\n", Status);
return false;
}

Буферы Skybox:

GLfloat cube_vertices[] = {
// front
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
// back
-1.0, -1.0, -1.0,
1.0, -1.0, -1.0,
1.0, 1.0, -1.0,
-1.0, 1.0, -1.0,
};

GLushort cube_elements[] = {
// front
0, 1, 2,
2, 3, 0,
// top
3, 2, 6,
6, 7, 3,
// back
7, 6, 5,
5, 4, 7,
// bottom
4, 5, 1,
1, 0, 4,
// left
4, 0, 3,
3, 7, 4,
// right
1, 5, 6,
6, 2, 1,
};

0

Решение

При рендеринге Skybox я сопоставляю вторичный кадровый буфер как
GL_READ_FRAMEBUFFER и основной кадровый буфер (экран) в виде
GL_DRAW_FRAMEBUFFERТаким образом, глубина буфера вторичного кадрового буфера
может быть использован,

Это не так, как все работает. GL_READ_FRAMEBUFFER не относится к тесту на глубину. Он используется в качестве источника для операций, таких как glReadPixels или же glBlitFramebuffer, Но для любого вида рендеринга, только GL_DRAW_FRAMEBUFFER актуально. Это включает в себя тест глубины.

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

2

Другие решения

Я нашел решение. Дополнительный кадровый буфер имел 32 бит / пиксель, но основной кадровый буфер имел только 24, что мешало glBlitFramebuffer с работы. Таким образом, правильная инициализация Framebuffer будет выглядеть так:

glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, WindowWidth, WindowHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT,
NULL);
0

По вопросам рекламы [email protected]