连接到帧缓冲区的OpenGL多采样整数纹理未能正确解析。

3

所以,我正在使用多重渲染目标帧缓冲区,其中第一个颜色附件是颜色纹理(RGBA8),而第二个绘制缓冲区(颜色附件1)是索引纹理(R32UI)。

gl::BindTexture(gl::TEXTURE_2D_MULTISAMPLE, m_Textures[eTEXTURE_COLORBUFFER]);
gl::TexParameteri(gl::TEXTURE_2D_MULTISAMPLE, gl::TEXTURE_BASE_LEVEL, 0);
gl::TexParameteri(gl::TEXTURE_2D_MULTISAMPLE, gl::TEXTURE_MAX_LEVEL, 0);
gl::TexImage2DMultisample(gl::TEXTURE_2D_MULTISAMPLE, m_Multisample,gl::RGBA8,width,height,gl::FALSE_);

gl::BindTexture(gl::TEXTURE_2D_MULTISAMPLE, m_Textures[eTEXTURE_CLASSBUFFER]);
gl::TexParameteri(gl::TEXTURE_2D_MULTISAMPLE, gl::TEXTURE_BASE_LEVEL, 0);
gl::TexParameteri(gl::TEXTURE_2D_MULTISAMPLE, gl::TEXTURE_MAX_LEVEL, 0);
gl::TexImage2DMultisample(gl::TEXTURE_2D_MULTISAMPLE, m_Multisample,gl::R32UI,width,height,gl::FALSE_);

这两个纹理都是多重采样的,我希望在渲染完成后能够在CPU上下载它们。但是,当我将多重采样FBO复制到单重采样FBO时,索引纹理数据返回的全是零,而颜色纹理则被正确解析。

// Resolve multisampling
if ( m_Multisample > 0 )
{
    gl::BindFramebuffer(gl::READ_FRAMEBUFFER, m_Framebuffers[eFBO_RENDERBUFFER]);
    gl::BindFramebuffer(gl::DRAW_FRAMEBUFFER, m_Framebuffers[eFBO_RESOLVEBUFFER]);
    gl::BlitFramebuffer(0, 0, m_FrameDims, m_FrameDims, 0, 0, m_FrameDims, m_FrameDims, 
        gl::COLOR_BUFFER_BIT, gl::NEAREST);

    gl::enum_t blit_error = gl::NO_ERROR_;
    blit_error = gl::GetError();
    if ( blit_error != gl::NO_ERROR_ )
    {
        throw framebuffer_error(string::format<128>(
            "BlitFramebuffer failed with error: %d",blit_error));
    }

    gl::BindFramebuffer(gl::READ_FRAMEBUFFER, m_Framebuffers[eFBO_RESOLVEBUFFER]);
}

我使用NEAREST标志,因为整数纹理似乎不能与LINEAR插值一起使用。
以下是我用于下载图像的代码。
uint32_t* tex_data = new uint32_t[query.m_FrameDims*query.m_FrameDims];
memset(tex_data,0,sizeof(uint32_t)*query.m_FrameDims*query.m_FrameDims);
gl::BindTexture(gl::TEXTURE_2D,query.m_DestColorTexture);
{
    // Copy color texture
    gl::ReadBuffer(gl::COLOR_ATTACHMENT0);
    gl::ReadPixels(0,0,query.m_FrameDims,query.m_FrameDims,
        gl::RGBA,gl::UNSIGNED_BYTE,tex_data);
    gl::TexSubImage2D(gl::TEXTURE_2D,0,0,0,query.m_FrameDims,query.m_FrameDims,
        gl::RGBA,gl::UNSIGNED_BYTE,tex_data);
}

gl::BindTexture(gl::TEXTURE_2D,query.m_DestClassTexture);
{
    // Copy class texture
    gl::ReadBuffer(gl::COLOR_ATTACHMENT1);                      
    gl::ReadPixels(0,0,query.m_FrameDims,query.m_FrameDims,
            gl::RED_INTEGER,gl::UNSIGNED_INT,tex_data);
    gl::TexSubImage2D(gl::TEXTURE_2D,0,0,0,query.m_FrameDims,query.m_FrameDims,
            gl::RED_INTEGER,gl::UNSIGNED_INT,tex_data);
}

delete[] tex_data;

如果我禁用多样本FBO,避免调用gl::BlitFramebuffer()函数,一切都正常工作。
我没有看到任何文档说明整数纹理不能进行多重采样,但即使如此,我也不确定它们是否有意义。
你有什么线索吗?我可能犯了什么错误吗?

整数 + 多重采样?听起来不太合理,让我们先看看是否支持...好的,似乎是支持的,但 GL_MAX_INTEGER_SAMPLES 的值是多少(因为它可能与 GL_MAX_SAMPLES 不同)?它大于1吗? - Christian Rau
嗯,不错的尝试,但是我的GTX 660似乎只能支持32个最大整数样本 :(。 无论如何,还是谢谢。 - 3Nu
1
你知道在你粘贴的代码中,你只从两个颜色缓冲区附件中的一个上进行blit吗?看看我的更新答案,它应该能解决你的问题。 - Andon M. Coleman
1个回答

1
当你进行帧缓冲复制时,一次只能从单个颜色缓冲区读取;你可以向多个绘图缓冲区写入(技术上最多可同时写入GL_MAX_DRAW_BUFFERS个)。问题在于你想从两个不同的颜色缓冲区中读取,并且你试图在单个复制操作中完成。

OpenGL 4.4 Core Specification - 18.3. 复制像素 - (pp. 483)

当传输颜色缓冲区时,值将从读取帧缓冲区的读取缓冲区中获取,并写入到绘制帧缓冲区的每个绘图缓冲区中。


你的代码告诉我你忘记了为第二个颜色附件执行第二个复制操作,这就是为什么它为空的原因。
为了纠正这个问题,我期望看到类似以下的代码:
// Resolve multisampling
if ( m_Multisample > 0 )
{
  //
  // Do the first resolve (COLOR_ATTACHMENT0)
  //
  gl::BindFramebuffer(gl::READ_FRAMEBUFFER,m_Framebuffers[eFBO_RENDERBUFFER]);
  gl::ReadBuffer     (gl::COLOR_ATTACHMENT0); // Read:  Attachment 0 (MSAA)

  gl::BindFramebuffer(gl::DRAW_FRAMEBUFFER,m_Framebuffers[eFBO_RESOLVEBUFFER]);
  gl::DrawBuffer     (gl::COLOR_ATTACHMENT0); // Write: Attachment 0 (Resolve)

  gl::BlitFramebuffer(0, 0, m_FrameDims, m_FrameDims, 0, 0, m_FrameDims,
      m_FrameDims, gl::COLOR_BUFFER_BIT, gl::NEAREST);

  gl::enum_t blit_error = gl::NO_ERROR_;
  blit_error = gl::GetError();
  if ( blit_error != gl::NO_ERROR_ )
  {
      throw framebuffer_error(string::format<128>(
          "BlitFramebuffer failed with error: %d",blit_error));
  }

  //
  // Do the second resolve (COLOR_ATTACHMENT1)
  //
  gl::BindFramebuffer(gl::READ_FRAMEBUFFER,m_Framebuffers[eFBO_RENDERBUFFER]);
  gl::ReadBuffer     (gl::COLOR_ATTACHMENT1); // Read:  Attachment 1 (MSAA)

  gl::BindFramebuffer(gl::DRAW_FRAMEBUFFER,m_Framebuffers[eFBO_RESOLVEBUFFER]);
  gl::DrawBuffer     (gl::COLOR_ATTACHMENT1); // Write: Attachment 1 (Resolve)

  gl::BlitFramebuffer(0, 0, m_FrameDims, m_FrameDims, 0, 0, m_FrameDims,
      m_FrameDims, gl::COLOR_BUFFER_BIT, gl::NEAREST);

  gl::enum_t blit_error = gl::NO_ERROR_;
  blit_error = gl::GetError();
  if ( blit_error != gl::NO_ERROR_ )
  {
      throw framebuffer_error(string::format<128>(
          "BlitFramebuffer failed with error: %d",blit_error));
  }

  gl::BindFramebuffer(gl::READ_FRAMEBUFFER,m_Framebuffers[eFBO_RESOLVEBUFFER]);
}

假定你要从/向复制的纹理/渲染缓冲具有相同的附着点。如果不是,则可以调整gl::ReadBuffer(...)gl::DrawBuffer(...)


@AndomM.Coleman 这完全合理,尽管不太直观。我将尝试这个并告诉你。谢谢! - 3Nu
@AndomM.Coleman 没错,这就是问题所在。非常感谢!也许这种方法比一次性解决所有问题的效率稍低,但正如你指出的,这样做能够提供更多的灵活性。 - 3Nu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接