C++ 延迟渲染不显示GBuffer纹理

C++ 延迟渲染不显示GBuffer纹理,c++,opengl,graphics,deferred-rendering,C++,Opengl,Graphics,Deferred Rendering,我试图在我作为个人学习开发的引擎中实现延迟渲染,但我无法理解在渲染GBuffer中的所有纹理以检查实现是否正常时我做错了什么 问题是,我目前有一个帧缓冲区,其中有3个颜色附件,用于GBuffer的不同纹理(颜色、法线和位置),我初始化如下: glCreateFramebuffers(1, &id); glBindFramebuffer(GL_FRAMEBUFFER, id); std::vector<uint> textures; textures.resi

我试图在我作为个人学习开发的引擎中实现延迟渲染,但我无法理解在渲染GBuffer中的所有纹理以检查实现是否正常时我做错了什么

问题是,我目前有一个帧缓冲区,其中有3个颜色附件,用于GBuffer的不同纹理(颜色、法线和位置),我初始化如下:

  glCreateFramebuffers(1, &id);
  glBindFramebuffer(GL_FRAMEBUFFER, id);

  std::vector<uint> textures;
  textures.resize(3);
  glCreateTextures(GL_TEXTURE_2D, 3, textures.data());
  
  for(size_t i = 0; i < 3; ++i)
  {
     glBindTexture(GL_TEXTURE_2D, textures[i]);

     if(i == 0)   // For Color Buffer
       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
     else
       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, nullptr);

     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, textures[i], 0);
  }

  GLenum color_buffers[3] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
  glDrawBuffers((GLsizei)textures.size(), color_buffers);

  uint depth_texture;
  glCreateTextures(GL_TEXTURE_2D, 1, &depth_texture);
  glBindTexture(GL_TEXTURE_2D, depth_texture);
  glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH24_STENCIL8, width, height);

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depth_texture, 0);

  bool fbo_status = glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
  ASSERT(fbo_status, "Framebuffer Incompleted!");
  glBindFramebuffer(GL_FRAMEBUFFER, 0);
因此,在这段代码中,我通过在0、1或2之间切换纹理索引来渲染使用ImGui::Image函数创建的3个纹理,作为下一个:

  layout(location = 0) in vec3 a_Position;
  layout(location = 1) in vec2 a_TexCoord;
  layout(location = 2) in vec3 a_Normal;

  out IBlock
  {
    vec2 TexCoord;
    vec3 FragPos;
    vec3 Normal;
  } v_VertexData;

  layout(std140, binding = 0) uniform ub_CameraData
  {
    mat4 ViewProjection;
    vec3 CamPosition;
  };

  uniform mat4 u_ViewProjection = mat4(1.0);
  uniform mat4 u_Model = mat4(1.0);

  void main()
  {
    vec4 world_pos = u_Model * vec4(a_Position, 1.0);
    
    v_VertexData.TexCoord = a_TexCoord;
    v_VertexData.FragPos = world_pos.xyz;
    v_VertexData.Normal = transpose(inverse(mat3(u_Model))) * a_Normal;
    
    gl_Position = ViewProjection * u_Model * vec4(a_Position, 1.0);
  }
ImGui::Image((ImTextureID)(fbo->textures[0]),视口大小,ImVec2(0,1),ImVec2(1,0))

现在,颜色纹理(索引为0)工作正常,如下图所示:

但是在渲染法线和位置纹理(索引2和3)时,我没有结果:

有人知道我做错了什么吗?因为我已经花了好几个小时看不见了。我在RenderDoc上运行了这个程序,没有发现任何错误,RenderDoc中显示的纹理与引擎中的纹理相同

渲染实体时使用的顶点着色器是下一个:

  layout(location = 0) in vec3 a_Position;
  layout(location = 1) in vec2 a_TexCoord;
  layout(location = 2) in vec3 a_Normal;

  out IBlock
  {
    vec2 TexCoord;
    vec3 FragPos;
    vec3 Normal;
  } v_VertexData;

  layout(std140, binding = 0) uniform ub_CameraData
  {
    mat4 ViewProjection;
    vec3 CamPosition;
  };

  uniform mat4 u_ViewProjection = mat4(1.0);
  uniform mat4 u_Model = mat4(1.0);

  void main()
  {
    vec4 world_pos = u_Model * vec4(a_Position, 1.0);
    
    v_VertexData.TexCoord = a_TexCoord;
    v_VertexData.FragPos = world_pos.xyz;
    v_VertexData.Normal = transpose(inverse(mat3(u_Model))) * a_Normal;
    
    gl_Position = ViewProjection * u_Model * vec4(a_Position, 1.0);
  }
片段一是下一个,它们都很简单:

  layout(location = 0) out vec4 gBuff_Color;
  layout(location = 1) out vec3 gBuff_Normal;
  layout(location = 2) out vec3 gBuff_Position;

  in IBlock
  {
    vec2 TexCoord;
    vec3 FragPos;
    vec3 Normal;
  } v_VertexData;

  struct Material
  {
    float Smoothness;
    vec4 AlbedoColor;
  };

  uniform Material u_Material = Material(1.0, vec4(1.0));
  uniform sampler2D u_Albedo, u_Normal;

  void main()
  {
    gBuff_Color = texture(u_Albedo, v_VertexData.TexCoord) * u_Material.AlbedoColor;
    gBuff_Normal = normalize(v_VertexData.Normal);
    gBuff_Position = v_VertexData.FragPos;
  }

这个问题并不清楚这里到底会发生什么,因为很多GL状态——无论是在渲染到gbuffer时,还是在渲染gbuffer纹理进行可视化时——都是未知的。然而,从问题中给出的图像来看,不能断定附件1和附件2的实际颜色输出不起作用

想到的一个问题是alpha混合。顶点着色器之后由逐片段操作处理的颜色值始终使用RGBA值-尽管通道的值仅在启用混合并使用某种程度上取决于源alpha的混合函数时才起作用

如果将自定义片段着色器输出声明为
float
vec2
vec3
,则其余组件保持未定义状态(未定义值,而不是未定义行为)。除非您确实依赖于这些值,否则这不会造成问题

我们这里还有一个
GL_RGBA16F
输出格式(这是正确的选择,因为规范不要求三分量RGB格式作为颜色渲染)

这里可能发生的情况是:

  • Alpha混合在渲染到g缓冲区期间已启用。片段着色器的alpha输出恰好为零,因此它显示为100%透明,并且纹理的内容不会更改
  • 在渲染到g缓冲区期间不使用Alpha混合,因此正确的内容最终出现在纹理中,Alpha通道恰好以全零结束。现在,纹理可以通过alpha混合enbaled可视化,最终显示在100%透明的视图中
如果是第一个选项,则在渲染到g缓冲区时禁用混合。无论如何,延迟着色都不起作用。您可能仍然会遇到第二个选项

如果这是第二个选项,则根本没有问题-接下来的照明通道将读取所需的数据(最终,您将希望将有用的信息放入alpha通道,以避免浪费,并能够减少附件的数量)。只是您的可视化(我认为这只是为了调试目的)是错误的。您可以尝试修复可视化


作为旁注:在G缓冲区中存储世界空间位置是对带宽的巨大浪费。重建世界空间位置所需的只是深度值以及视图和投影矩阵的倒数。如果您将相机从世界空间原点移开,在
GL_RGB16F
中存储世界空间位置将很容易遇到精度问题。

也许您可以尝试在RenderDoc中运行应用程序,它可能会为您提供出错的线索是,在这个问题上,我已经说过我使用RenderDoc来调试它,但我找不到任何东西,请提供一个。正如目前所写的问题,绘制时几乎所有的GL状态都是未知的。此外,如果您已经使用了renderdoc,请查看实际的纹理内容。用Imgui呈现这一点只会增加更多的未知数。顺便说一句,它可能像你的alpha通道结束于0一样简单。“关于alpha的东西,颜色纹理正在工作,其他的是vec3”。正因为如此,我才谈到alpha值。您的附件是
GL_RGBA16F
(应该是这样的,因为
GL_RGB16F
不是必需的颜色可渲染格式),所以您认为alpha通道会出现在这里吗?提示:片段着色器颜色输出始终为vec4(在片段着色器对RGBA值进行所有操作之后的固定函数片段处理阶段),如果不写入所有元素,则该值只是未定义。感谢您的解释!出于好奇,你知道位置或法线更喜欢使用哪些其他格伦值吗?正如我所说:你不存储位置。要存储法线,有几个选项,请参见以获取一些选项。