Incomplete framebuffer error

I am using pyopengl (using Opengl version 3.3)

I have the following code (part of a larger codeset where I project the depth around a location onto a cubemap). When I run the entire code it runs fine. However, now that I am tidying up and completing the code I run into a problem of an incomplete framebuffer.

The code is as follows:

# CREATE EMPTY CUBEMAP
######################
side = 2000

# create framebuffer for cube face
depth_map_fbo = glGenFramebuffers(1)
glBindFramebuffer(GL_FRAMEBUFFER, depth_map_fbo)

# CREATING A TEXTURE FOR THE ENTIRE CUBE
distance_cube_tex = glGenTextures(1)
glBindTexture(GL_TEXTURE_CUBE_MAP, distance_cube_tex)

for i in range(6):
    glTexImage2D(
        GL_TEXTURE_CUBE_MAP_POSITIVE_X+i, 0, GL_R32F, side, side, 0, GL_RED, GL_FLOAT, None
                )
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST) # or GL_LINEAR?
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE)

# attach depth texture to fbo depth buffer
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, distance_cube_tex, 0)


# CREATING A TEXTURE FOR A CUBE FACE
depth_cube_face_tex = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, depth_cube_face_tex)

glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, side, side,
                    0, GL_DEPTH_COMPONENT, GL_FLOAT, None)

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) # or GL_LINEAR?
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)

# attach texture(=image) to the framebuffer
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depth_cube_face_tex, 0)

# check for errors *ERROR*
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE):
    print(glCheckFramebufferStatus(GL_FRAMEBUFFER))
    raise RuntimeError("ERROR.FRAMEBUFFER. Framebuffer is not complete!")

# unbind depth map framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0)

The code blows up when it gets to the ERROR checking. Now, in order to find the exact nature of the error I printed glCheckFramebufferStatus(GL_FRAMEBUFFER) (as shown in the code). I get a value of 36264 which in hex is 8DA8. Unfortunately when I look through the opengl codes I get no match for this hexadecimal value??

Can anyone see something obvious that I am missing?

From glext.h:

#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8

Related:

  • Framebuffer Object : Completeness Rules (OpenGL Wiki)
  • glCheckFramebufferStatus()

Thanks @Dark_Photon this is very helpful. For some reason I am still not able to find this error in my installation (though it obviously must be there).

What do you mean? Your code above illustrates this problem.

FWIW, you’re calling glFramebufferTexture() which binds the “entire” cubemap as a layered attachment. If you want to bind “a specific face” of the cubemap, that’s a different GL call (glFramebufferTexture2D()).

The fact that you’re binding a 2D texture to the depth attachment makes me think that this is what you intended to do.

Thanks @Dark_Photon

It is likely that I am thoroughly confused as I have struggled with this and managed to get some result (through a lot of patch work) without entirely understanding why things worked. To be totally frank, I was unaware what was a ‘layered image’. So I apologize for this.

Again, my intention is to project the depth buffer (in reality the distance from camera location to each pixel) surrounding my camera onto a cubemap.

my vertex shader is very simple:

#version 330 core
layout (location = 0) in vec3 aPos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
out vec4 pos;

void main()
{ pos = view * model * vec4(aPos, 1.0);
gl_Position = projection * view * model * vec4(aPos, 1.0); }

and fragment shader:

#version 330 core
in vec4 pos;
out float frag_depth;

void main(){ frag_depth = length(pos.xyz); }

If I only attached a texture_cube_map as a depth component and attach it to the my framebuffer (so no color attachments). The output for one of my faces (similar to the rest) is as follows be:
image
Here the depth appears between between 0 to 1

If instead I attach the texture cube_map as a color attachment, and create in addition a 2D texture as a depth attachment. And finally attach both textures (the cubemap and the 2d texture) to the framebuffer. I get the following result,
image

And finally, if I attach the texture cube_map as a color attachment (same a previous) BUT do not attach an additional 2D texture as a depth attachment. I get the following result, which in addition to showing a lot of gaps, it does not consider any occlusions.

image

My goal is to achieve a result similar to the second case but it is obvious that when I check whether the framebuffer is complete I get an error. How can I achieve this correctly? i.e., how can I come up with framebuffer that is complete and get the same type of output as in the second case?

Again I am sorry for such a long message.

In case it is useful, I am including the code I am using to render.

# activate cubemap shader
cubemap_shader.use()

# create a projection matrix
projection = glm.perspective(glm.radians(90.0), 1.0, 0.1, 4000.0)
cubemap_shader.set_uniform_mat4('projection', projection)   

# loop through each face
for i in range(6):
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X+i,
                           distance_cube_tex, 0)
    
    # clear colors and buffers
    glClearColor(0.1,0.1,0.1,0.1)
    glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT)

    # rotate camera
    terrain_camera.pitch = rotation_dict[i][0]
    terrain_camera.yaw =  rotation_dict[i][1]
    terrain_camera.update_camera_vectors()
    
    # update view (lookat) matrix
    view = terrain_camera.get_matrix_view()
    cubemap_shader.set_uniform_mat4('view', view)
    
   # bind vao with terrain information
    glBindVertexArray(tin_vao)

    # draw terrain
    glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, None)
 
    # remove binding
    glBindVertexArray(0)

    #save output ?
    zbuffer = glReadPixelsf(0, 0, side, side, GL_RED, GL_FLOAT)
    np.save(f'{rotation_dict[i][3]}_terrain', np.flipud(zbuffer))

# unbind fbo
glBindFramebuffer(GL_FRAMEBUFFER, 0)

@Dark_Photon I refer to the following thread from Aug 23, see @carsten_neumann response.

Following this advice I attached a the texture_2D in order to take care of the problems I was having with occlusion. Perhaps I did this incorrectly and now I am not able to complete the framebuffer? But this is the reason why I have this texture_2d attached to the framebuffer.

Here at render time, you are rendering each 2D face of the cubemap with its own pass. So in each pass, one 2D face of the cubemap is individually bound as GL_COLOR_ATTACHMENT0. This is fine. Notice: You called glFramebufferTexture2D() here.

On init however:

you are binding the “entire” cube map (all 6 faces) to GL_COLOR_ATTACHMENT0. Notice: You called glFramebufferTexture() here (different API call). This would also be fine, … except that immediately after that you do this:

which you said “blows up” with GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS (0x8DA8). Which makes sense! You told GL to bind:

  1. A cubemap as a layered attachment to GL_COLOR_ATTACHMENT0, and
  2. A 2D texture as a layered attachment to GL_DEPTH_ATTACHMENT
  3. And then asked GL if this FBO config was OK.

The answer is of course no (because of #2). Because a 2D texture can’t be used as a layered attachment. Those links I posted above tell you this:

Thanks @Dark_Photon . I understand now what I did wrong. However, I am not certain how to fix it?
Because I want to render my surroundings onto the cubemap, it makes sense that at render time I would use glFramebufferTexture2D given that I am rotating the camera.

Having in mind that when calculating the distance from camera location I want to respect depth occlusions.

When initializing the cubemap:
would I need to not to use glFramebufferTexture outside the loop and instead use glFramebufferTexture2D inside the the loop for each cubemap face?
would I need to generate 6 X 2D textures with GL_DEPTH_COMPONENT inside the loop as well?

Many thanks,

M

Yes. Or glFramebufferTextureLayer. You only use glFramebufferTexture with a cube map if you want a layered framebuffer, which requires writing to gl_Layer within a geometry shader. It also requires all attachments to be layered (and, realistically, to have the same number of layers).

No. You can use one texture and clear the depth buffer between faces.

Note that you can create depth-format cube maps, which have some practical applications (e.g. shadow maps). But if you aren’t going to need the depth buffer once you’ve finished rendering a face, you should just use a single 2D texture.

1 Like

Thanks @GClements for your email.

I think that I managed to get this. Here is what I ended up doing (I hope it might help someone else). I use the following code when initializing my cubemap,

# CREATE EMPTY CUBEMAP
######################
side = 2000

# create framebuffer for cube face
depth_map_fbo = glGenFramebuffers(1)
glBindFramebuffer(GL_FRAMEBUFFER, depth_map_fbo)

# CREATING A TEXTURE FOR THE ENTIRE CUBE
distance_cube_tex = glGenTextures(1)
glBindTexture(GL_TEXTURE_CUBE_MAP, distance_cube_tex)

# initialize cubemap
for i in range(6):
    glTexImage2D(
        GL_TEXTURE_CUBE_MAP_POSITIVE_X+i, 0, GL_R32F, side, side, 0, GL_RED, GL_FLOAT, None
                )

glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST) 
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE)

# attach depth texture to fbo depth buffer
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, distance_cube_tex, 0)

# check for errors (after attaching a texture)
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE):
    print(glCheckFramebufferStatus(GL_FRAMEBUFFER))
    raise RuntimeError("ERROR.FRAMEBUFFER. Framebuffer is not complete!")

# unbind depth map framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0)

Then when rendering I used the following,

# RENDER TO DEPTH CUBEMAP
##########################

# create texture for cube face
depth_cube_face_tex = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, depth_cube_face_tex)

glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, side, side,
                    0, GL_DEPTH_COMPONENT, GL_FLOAT, None)

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)

# activate cubemap shader
cubemap_shader.use()

# create a projection matrix
projection = glm.perspective(glm.radians(90.0), 1.0, 0.1, 4000.0)
cubemap_shader.set_uniform_mat4('projection', projection)   

for i in range(6):
    glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, distance_cube_tex, 0, i)
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,  depth_cube_face_tex, 0)
    glClearDepth(depth_cube_face_tex)
    
    # clear colors and buffers
    glClearColor(0.1,0.1,0.1,0.1)
    glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT)

    # rotate camera
    
    # CODE HERE TO ROTATE CAMERA AND UPDATE VIEW MATRIX
    
    # update view matrix in shader
    cubemap_shader.set_uniform_mat4('view', view)
    
     # RENDER SCENE

    #save output ?
    zbuffer = glReadPixelsf(0, 0, side, side, GL_RED, GL_FLOAT)
    np.save(f' terrain_{i}', np.flipud(zbuffer))

# unbind fbo
glBindFramebuffer(GL_FRAMEBUFFER, 0)

This seems to work without any FRAMEBUFFER completion errors!
Thanks for all your comments.