延迟渲染 Skybox OpenGL
Deferred Rendering Skybox OpenGL
我刚刚实施了延迟渲染,但我无法让我的天空盒正常工作。我尝试在渲染循环的最后渲染我的天空盒,但我得到的只是一个黑屏。这是渲染循环:
//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
这样它就无法通过深度测试。这不应该只在其他对象尚未绘制的地方绘制天空盒吗?为什么会导致黑屏?
我知道我已经正确设置了天空盒,因为如果我自己绘制天空盒,它就会显示得很好。
I can briefly see for a split second the geometry that should be drawn before the skybox is drawn on top of everything.
由于您使用的是双缓冲,看到不同的东西一定是由于绘制了不同的帧。默认帧缓冲区中的深度缓冲区未被清除,我认为这至少是时间不稳定的原因。
在您的情况下,您希望默认深度缓冲区与绘制天空盒时的 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();
我刚刚实施了延迟渲染,但我无法让我的天空盒正常工作。我尝试在渲染循环的最后渲染我的天空盒,但我得到的只是一个黑屏。这是渲染循环:
//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
这样它就无法通过深度测试。这不应该只在其他对象尚未绘制的地方绘制天空盒吗?为什么会导致黑屏?
我知道我已经正确设置了天空盒,因为如果我自己绘制天空盒,它就会显示得很好。
I can briefly see for a split second the geometry that should be drawn before the skybox is drawn on top of everything.
由于您使用的是双缓冲,看到不同的东西一定是由于绘制了不同的帧。默认帧缓冲区中的深度缓冲区未被清除,我认为这至少是时间不稳定的原因。
在您的情况下,您希望默认深度缓冲区与绘制天空盒时的 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();