Я только что реализовал отложенный рендеринг и у меня проблемы с работой моего скайбокса. Я пытаюсь рендерить свой скайбокс в самом конце цикла рендеринга, и все, что я получаю, это черный экран. Вот цикл рендеринга:
//binds the fbo
gBuffer.Bind();
//the shader that writes info to gbuffer
geometryPass.Bind();
glDepthMask(GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
//draw geometry
geometryPass.SetUniform("model", transform.GetModel());
geometryPass.SetUniform("mvp", camera.GetViewProjection() * transform.GetModel());
mesh3.Draw();
geometryPass.SetUniform("model", transform2.GetModel());
geometryPass.SetUniform("mvp", camera.GetViewProjection() * transform2.GetModel());
sphere.Draw();
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT);
//shader that calculates lighting
pointLightPass.Bind();
pointLightPass.SetUniform("cameraPos", camera.GetTransform().GetPosition());
for (int i = 0; i < 2; i++)
{
pointLightPass.SetUniformPointLight("light", pointLights[i]);
pointLightPass.SetUniform("mvp", glm::mat4(1.0f));
//skybox.GetCubeMap()->Bind(9);
quad.Draw();
}
//draw skybox
glEnable(GL_DEPTH_TEST);
skybox.Render(camera);
window.Update();
window.SwapBuffers();
Ниже приведена функция рендеринга скайбокса.
glCullFace(GL_FRONT);
glDepthFunc(GL_LEQUAL);
m_transform.SetPosition(camera.GetTransform().GetPosition());
m_shader->Bind();
m_shader->SetUniform("mvp", camera.GetViewProjection() * m_transform.GetModel());
m_shader->SetUniform("cubeMap", 0);
m_cubeMap->Bind(0);
m_cubeMesh->Draw();
glDepthFunc(GL_LESS);
glCullFace(GL_BACK);
А вот вершинный шейдер скайбокса:
layout (location = 0) in vec3 position;
out vec3 TexCoord;
uniform mat4 mvp;
void main()
{
vec4 pos = mvp * vec4(position, 1.0);
gl_Position = pos.xyww;
TexCoord = position;
}
Фрагментный шейдер скайбокса просто устанавливает выходной цвет texture(cubeMap, TexCoord)
,
Как вы можете видеть из вершинного шейдера, я устанавливаю позицию z
компонент, который будет w
так что он всегда будет иметь глубину 1. Я также устанавливаю функцию глубины, чтобы GL_LEQUAL
так что он не пройдет тест глубины. Должно ли это рисовать скайбокс не только там, где другие объекты еще не нарисованы? Почему это приводит к черному экрану?
Я знаю, что правильно настроил скайбокс, потому что, если я просто нарисую скайбокс, он будет хорошо отображаться.
Я могу кратко увидеть на долю секунды геометрию, которая должна быть нарисована до того, как скайбокс будет нарисован поверх всего.
Поскольку вы используете двойную буферизацию, просмотр разных вещей должен происходить из-за того, что нарисован другой кадр. Буфер глубины в стандартном кадровом буфере не очищается, что, по-моему, является причиной временной нестабильности, по крайней мере.
В вашем случае вы хотите, чтобы буфер глубины по умолчанию был таким же, как буфер GBuffer при рисовании скайбокса. Быстрый способ достичь этого с glBlitFramebuffer, Также избегая необходимости очищать это:
glBindFramebuffer(GL_READ_FRAMEBUFFER, gbuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(..., GL_DEPTH_BUFFER_BIT, ...);
Теперь объясним черный экран, когда скайбокс заполняет экран. Без теста глубины, конечно, скайбокс просто рисует. При проверке глубины скайбокс по-прежнему рисует первый кадр, но вскоре после второго кадра очищает только буфер цвета. Буфер глубины по-прежнему содержит устаревшие значения скайбокса, поэтому он не перерисовывается для этого кадра, и у вас остается черный …
Однако ваш проход геометрии отрисовывается без включенного тестирования глубины, так что это все равно должно быть видно, даже если не установлен скайбокс. Также это произойдет только с GL_LESS
и у тебя есть GL_LEQUAL
, А также у тебя есть glDepthMask
false, что означает, что в вашем коде ничего не должно записываться в буфер глубины по умолчанию. Это указывает на буфер глубины, содержащий другие значения, возможно, неинициализированные, но по моему опыту он изначально равен нулю. Также это все еще происходит, когда скайбокс не заполняет экран, нарисованный в виде куба от камеры, что уничтожает этот аргумент. Теперь, возможно, если геометрия не может нарисовать во втором кадре, который бы это объяснил. Впрочем, откровенные ошибки в драйвере тоже будут, но я не вижу проблем в данном коде.
TLDR: много необъяснимых вещей, так что ** я сам попробовал и не могу воспроизвести твою проблему …
Вот быстрый пример, основанный на вашем коде, и он прекрасно работает для меня …
(зеленая сфера — это геометрия, красный куб — скайбокс)
gl_Position = pos
:
Обратите внимание на желтый от аддитивного смешивания, даже если скайбокс отображается поверх. Я бы подумал, что ты тоже увидишь это.
gl_Position = pos.xyww
:
Теперь для кода …
//I haven't enabled back face culling, but that shouldn't affect anything
//binds the fbo
fbo.bind();
//the shader that writes info to gbuffer
//geometryPass.Bind(); //fixed pipeline for now
glDepthMask(GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glColor3f(0,1,0);
fly.uploadCamera(); //glLoadMatrixf
sphere.draw();
glDepthMask(GL_FALSE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);
fbo.unbind(); //glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT);
//shader that calculates lighting
drawtex.use();
//pointLightPass.SetUniform("cameraPos", camera.GetTransform().GetPosition());
drawtex.set("tex", *(Texture2D*)fbo.colour[0]);
for (int i = 0; i < 2; i++)
{
//pointLightPass.SetUniformPointLight("light", pointLights[i]);
//pointLightPass.SetUniform("mvp", glm::mat4(1.0f));
//skybox.GetCubeMap()->Bind(9);
drawtex.set("modelviewMat", mat44::identity());
quad.draw();
}
drawtex.unuse();
//draw skybox
glEnable(GL_DEPTH_TEST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, fbo.size.x, fbo.size.y, 0, 0, fbo.size.x, fbo.size.y, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
//glCullFace(GL_FRONT);
glDepthFunc(GL_LEQUAL);
//m_transform.SetPosition(camera.GetTransform().GetPosition());
skybox.use();
skybox.set("mvp", fly.camera.getProjection() * fly.camera.getInverse() * mat44::translate(1,0,0));
//m_shader->SetUniform("mvp", camera.GetViewProjection() * m_transform.GetModel());
//m_shader->SetUniform("cubeMap", 0);
//m_cubeMap->Bind(0);
cube.draw();
skybox.unuse();
glDepthFunc(GL_LESS);
//glCullFace(GL_BACK);
//window.Update();
//window.SwapBuffers();