使用单个 FBO 将单个场景从多个视点绘制到多个纹理中(每个视点 1 个)仅产生一个有效纹理

Posted

技术标签:

【中文标题】使用单个 FBO 将单个场景从多个视点绘制到多个纹理中(每个视点 1 个)仅产生一个有效纹理【英文标题】:Using a single FBO to draw a single scene from multiple viewpoints into multiple textures (1 per viewpoint) yields only one valid texture 【发布时间】:2013-11-26 04:53:07 【问题描述】:

我目前正在处理一项任务,该任务要求我们生成用于环境映射的立方体贴图(不使用任何内置的 OpenGL 立方体映射功能)。目前只有最后渲染的图像是有效的。其余的全是黑色的,不管我设置了什么清晰的颜色。

似乎从 FBO 中分离纹理会使其无效(将其清除为黑色)。如果我绘制到一个纹理,然后通过调用glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 0, 0) 将纹理从 fbo 中分离出来,我刚刚写入的纹理是黑色的。


伪代码:

bind FBO

for each viewpoint to be rendered (+- each axis, 6 total)
  calculate transformation matrices needed for viewpoint
  attach next texture to FBO at GL_COLOR_ATTACHMENT0
  clear color and depth
  render scene

unbind FBO

这是将同一场景渲染到多个纹理的合理方法,还是应该使用多个 FBO? 推荐的方法是什么(再次,避免使用 OpenGL 立方体贴图功能)?


C++ 代码:

初始化 FBO

// Setup FBO
glGenFramebuffers(1, &_env_map_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, _env_map_fbo);

// Setup depth buffer
glGenTextures(1, &_env_map_depth);
glBindTexture(GL_TEXTURE_2D, _env_map_depth);

glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, 512, 512, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0); // unbind depth texture

// Attach depth buffer to FBO
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, _env_map_depth, 0);

// Configure FBO
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glReadBuffer(GL_NONE);

glViewport(0, 0, 512, 512);

// Verify framebuffer is complete
GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);(void)fb_status;
pcerror_if(fb_status != GL_FRAMEBUFFER_COMPLETE, "Error setting up FBO!");

初始化纹理

glGenTextures(6, _tex_ids);

for(uint i = 0; i < 6; ++i)  

  glBindTexture(GL_TEXTURE_2D, _tex_ids[i]);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 512, 512, 0, GL_RGB, GL_FLOAT, nullptr);

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);


glBindTexture(GL_TEXTURE_2D, 0);

内部渲染循环

// Bind frame buffer
glBindFramebuffer(GL_FRAMEBUFFER, _env_map_fbo);    
glDrawBuffer(GL_COLOR_ATTACHMENT0);

// Calculate transformation matrices for viewpoint 1
// ...

glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _tex_ids[0], 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
_graphics.render(); // Render entire scene using the same code I normally use.

// Calculate transformation matrices for viewpoint 2
// ...

glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _tex_ids[1], 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
_graphics.render();

// Etc. for each viewpoint

glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDrawBuffer(GL_BACK);

// Draw scene as normal

如果有用,请提供更多信息:

我正在使用 gDEBugger 检查渲染结果。 纹理在此处使用时不应绑定到其他任何地方。

【问题讨论】:

【参考方案1】:

看来我的方法确实有效。我对 gDEBugger 过于信任了。将纹理绘制到 HUD 我看到了我期望的输出。

我的结果 gDEBugger

【讨论】:

【参考方案2】:

您没有完全初始化纹理。在调用glTexImage…glTexStorage… 之前,纹理对象不会完全初始化。在将纹理的层/面绑定到 FBO 之前,您必须这样做。同样对于渲染到立方体贴图,您需要创建一个立方体贴图纹理,并且只将其每个面依次绑定到 FBO。

【讨论】:

我为所有纹理调用 glTexImage2D:glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 512, 512, 0, GL_RGB, GL_FLOAT, nullptr); // Color attachments, glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, 512, 512, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); // Depth buffer 就立方体贴图部分而言,我确实声明我正在处理的任务要求我们“不使用任何内置的 OpenGL 立方体贴图功能”,即我们必须制作 6 种不同的纹理,然后选择我们要在片段着色器中使用哪一种(效率不高,仅用于学习目的)。

以上是关于使用单个 FBO 将单个场景从多个视点绘制到多个纹理中(每个视点 1 个)仅产生一个有效纹理的主要内容,如果未能解决你的问题,请参考以下文章

带有 FBO 的 OpenGL 阴影映射 - 多个拖尾绘制

如何将多个图像绘制到单个画布上?

从单个 jupyter/ipython 单元格绘制多个 python-igraph 图

为啥从 FBO 解除绑定纹理会清除纹理?

如何使用 VBO 和单个 OpenGL drawelements 调用绘制多个对象?

使用 JSON 绘制具有多条线的单个 Google 折线图