如何调试默认帧和深度缓冲区?
Posted
技术标签:
【中文标题】如何调试默认帧和深度缓冲区?【英文标题】:How to debug default frame and depth buffers? 【发布时间】:2020-05-14 02:31:06 【问题描述】:我正在尝试通过动态阴影映射和前向渲染在我的自定义渲染器上实现阴影(稍后会实现延迟渲染)。例如,一切都正确渲染到用于生成阴影贴图的帧缓冲区。但是,当使用默认帧缓冲区正常渲染场景时,只会渲染天空盒(这意味着使用了默认帧缓冲区),我唯一的假设是问题与深度缓冲区有关,因为禁用了对 DrawActors(.. .)(在 ForwardRenderShadows 中)似乎可以解决问题,但如果这样做,我将无法生成深度图。对此事有何建议?
代码:
void Scene::DrawActors(const graphics::Shader& shader)
for(const auto& actor : actors_)
actor->Draw(shader);
template <typename T>
void ForwardRenderShadows(const graphics::Shader& shadow_shader, const std::vector<T>& lights)
for(const auto& light : lights)
if(light->Shadow())
light->DrawShadows(shadow_shader);
DrawActors(shadow_shader); //removing this line "solves the problem"
glBindFramebuffer(GL_FRAMEBUFFER, 0);
/*
shadow mapping is only implemented on directional lights for the moment, and that is the
relevant code that gets called when the process starts, more code details at the end of code
snippet.
*/
void DirectionalLight::SetupShadows()
glGenFramebuffers(1, &framebuffer_);
glGenTextures(1, &shadow_map_);
glBindTexture(GL_TEXTURE_2D, shadow_map_);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, constants::SHADOW_WIDTH, constants::SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadow_map_, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
throw std::runtime_error("Directional light framebuffer is not complete \n");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
ShadowSetup(true);
void DirectionalLight::DrawShadows(const graphics::Shader& shader)
if(!ShadowSetup())
SetupShadows();
glViewport(0, 0, constants::SHADOW_WIDTH, constants::SHADOW_HEIGHT);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_);
glClear(GL_DEPTH_BUFFER_BIT);
shader.Use();
projection_ = clutch::Orthopraphic(-10.0f, 10.0f, -10.0f, 10.0f, 1.0f, 100.0f);
transform_ = clutch::LookAt(direction_ * -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
shader.SetUniformMat4("light_transform", projection_ * transform_);
void DirectionalLight::Draw(const graphics::Shader& shader)
shader.SetUniform4f("light_dir", direction_);
shader.SetUniform4f("light_color", color_);
shader.SetUniformMat4("light_transform", transform_);
shader.SetUniformMat4("light_projection", projection_);
shader.SetUniformInt("cast_shadow", shadows_);
glActiveTexture(GL_TEXTURE12);
shader.SetUniformInt("shadow_map", 12);
glBindTexture(GL_TEXTURE_2D, shadow_map_);
对 repo 进行编码:https://github.com/rxwp5657/Nitro
问题的相关文件:
include/core/scene.hpp include/core/directional_light.hpp include/core/light_shadow.hpp include/core/directional_light.hppinclude/graphics/mesh.hpp
src/core/scene.cpp
src/core/directional_light.cpp src/core/light_shadow.cpp src/core/directional_light.cpp src/graphics/mesh.cpp最后,我到目前为止尝试的是:
使用 glDepthMask(GL_FALSE) 和 glDisable(GL_DEPTH_TEST) 停用深度测试 //同样的问题。 将深度函数更改为 glDepthFunc(GL_ALWAYS); // 没有想要的结果;【问题讨论】:
OpenGL 调试很繁琐。大多数情况下,我试图通过代码凝视来解决我的问题(并且它以某种方式主要工作)但这真的......很乏味。通过google "opengl debugger",我发现了这个:Debugging Tools on khronos.org,Learn OpenGL - Debugging。我记得一位同事曾经用一个工具支持我,其中所有的 GL 状态变化都在一个工具中直观地显示出来(但不幸的是,我忘记了他用于此操作的内容)。 嗨,谢夫,感谢您的评论。是的,OpenGL 调试真的很乏味,到目前为止我遇到的大多数问题都是因为缓冲区布局不正确,即使在那些情况下,您也知道问题可能就在那里,甚至会生成一些颜色输出来调试着色器,但在这种情况下,我甚至不能那样做。例如,我的开发环境是在 MacOS 上,但似乎我必须稍微改变一下 Windows 才能充分利用这些工具,每当我有任何进展时,我都会再次发表评论。谢谢;)。 我问了我的同事。他告诉我这个工具是apitrace。在其文档中。它声称也支持 OS/X。 Scheff,感谢您的工具,我刚刚发现了错误,apitrace 确实有效。所以,问题是我的顶点数据被擦除或其他东西,通常一个顶点是由一个位置、法线、切线、纹理坐标等形成的,但是当使用帧缓冲区时,数据被“覆盖”,现在缓冲区只有法线。然而,这并不是最奇怪的事情,法线顶点数据被位置数据覆盖,其他属性(切线、真实法线等)消失了。我将不得不回顾发生了什么,因为这只发生在帧缓冲区中。谢谢:) 【参考方案1】:如果您有 NVIDIA 显卡,您可以查看Nsight。您可以捕获一帧并查看所有发生的 GL 调用。
然后,您可以选择一个事件,例如我的示例中的事件 22,并检查所有纹理、颜色缓冲区、深度缓冲区和模板缓冲区。
此外,您可以在一个事件中查看所有 GL 状态参数。
【讨论】:
您好 DasElias!,感谢您的回答。目前,我正在使用我的 Mac,因为它有我的开发环境,是的,我的装备上有 NVIDIA 显卡,但它目前正在运行 Windows,所以我必须在那里构建项目才能使用该工具。此外,这个工具看起来很棒,一旦有可用的调试结果,我会评论。谢谢;)。【参考方案2】:好的,在使用 apitrace 之后,我发现从自定义帧缓冲区切换到默认帧缓冲区时 VBO 会发生变化。正因如此,解决问题的方法是切换到默认帧缓冲后重新设置VBO。
根据项目代码,解决方法是切换到默认Framebuffer后再次调用Setup函数。
Mesh类的设置函数:
void Mesh::Setup(const Shader& shader)
glGenVertexArrays(1, &vao_);
glBindVertexArray(vao_);
glGenBuffers(1, &elementbuffer_);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementbuffer_);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_.size() * sizeof(unsigned int), &indices_[0], GL_STATIC_DRAW);
glGenBuffers(1, &vbo_);
glBindBuffer(GL_ARRAY_BUFFER, vbo_);
glBufferData(GL_ARRAY_BUFFER, vertices_.size() * sizeof(Vertex), &vertices_[0], GL_STATIC_DRAW);
shader.PosAttrib("aPosition", 3, GL_FLOAT, sizeof(Vertex), 0);
shader.PosAttrib("aNormal", 3, GL_FLOAT, sizeof(Vertex), offsetof(Vertex, normal));
shader.PosAttrib("aTexCoord", 2, GL_FLOAT, sizeof(Vertex), offsetof(Vertex, tex_coord));
shader.PosAttrib("aTangent", 3, GL_FLOAT, sizeof(Vertex), offsetof(Vertex, tangent));
shader.PosAttrib("aBitangent",3, GL_FLOAT, sizeof(Vertex), offsetof(Vertex, bitangent));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
loaded_ = true;
Vertices buffer after switching to default frame buffer
Vertices buffer with no Framebuffer switching (no shadow map generated)
【讨论】:
以上是关于如何调试默认帧和深度缓冲区?的主要内容,如果未能解决你的问题,请参考以下文章