Search code examples
openglfborender-to-texture

Using a single FBO to draw a single scene from multiple viewpoints into multiple textures (1 per viewpoint) yields only one valid texture


I am currently working on an assignment that requires us to generate a cube map that will be used for environment mapping (without using any built-in OpenGL cube mapping functionality). Currently only the last image rendered is valid. The rest are entirely black, regardless of the clear color I have set.

It appears as though detaching a texture from an FBO is invalidating it (clearing it to black). If I draw to one texture, then detach the texture from the fbo by calling glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, 0, 0), the texture I just wrote to is black.


Psuedo code:

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

Is this a reasonable method for rendering the same scene to multiple textures, or should I use multiple FBOs? What is the recommended method of doing this (again, avoiding OpenGL cube map functionality)?


C++ code:

Initializing 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!");

Initializing Textures

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);

Inside Render Loop

// 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

Some more information in-case it is useful:

  • I'm checking the results of rendering using gDEBugger.
  • The textures should not be bound anywhere else when they are being used here.

Solution

  • It appears as though my method does work. I was putting a little too much faith in gDEBugger. Drawing the textures to the HUD I see the output I expect.

    My results results gDEBugger