OpenGL ES 3.2 Attaching color and render textures

Good Afternoon,

I am working with OpenGL ES version 3.2 and OpenGL EGL to provide a headless rendering. I would like to attach a color and depth texture to a single custom framebuffer object (FBO) and then write the resulting pixels as either PPM or PNG image file.

I am able to successfully retrieve an image file using only a render buffer object (RBO) attached to the custom FBO with the following code snippet:

...
GLuint fbo_id;
glGenFramebuffers(1, &fbo_id);
glBindFramebuffer(GL_FRAMEBUFFER, fbo_id);

GLuint rbo_id;
glGenRenderbuffers(1, & rbo_id);
glBindRenderbuffer(GL_RENDERBUFFER, rbo_id);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA32F, col_width, col_height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo_id);
...

However, when I try the same using a depth and color texture with the following code snippet, I get a black image file:

...
GLuint fbo_id;
glGenFramebuffers(1, & fbo_id);
glBindFramebuffer(GL_FRAMEBUFFER, fbo_id);

// Color texture where col_tex_id was already generated successfully
glBindTexture(GL_TEXTURE_2D, col_tex_id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, col_width, col_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 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, GL_TEXTURE_2D, col_tex_id, 0);

// Depth texture where depth_id was already generated successfully 
glBindTexture(GL_TEXTURE_2D, depth_id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, depth_width, depth_height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 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_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_id, 0);

GLenum draw_buffers[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, draw_buffers);

auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
    std::err << "Framebuffer NOT complete!\n";
    exit(1);
}

glBindFramebuffer(GL_FRAMEBUFFER, 0);
...

Is there something obviously wrong that I am missing, or is this an issue with GLES 3.2 and EGL?

The code snippet for color and depth textures work with standard OpenGL but not with GLES which is weird.

Thank you in advance for any hints or ideas.

Does glGetError report any error?

Are you clearing the depth buffer before rendering?

Thank you @GClements for the reply.

Doesn’t the line:
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, depth_width, depth_height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
clear out the depth buffer?

I rewrote the code such that it follows the example on glTexParameter - OpenGL ES 3 - docs.gl so that the following code snippet results:

...
// Build color texture
glBindTexture(GL_TEXTURE_2D, col_tex_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, col_width, col_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);

// Build depth texture
glBindTexture(GL_TEXTURE_2D, depth_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, depth_width, depth_height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 0);
glBindTexture(GL_TEXTURE_2D, 0);

// Generate and build framebuffer
GLuint fbo_id;
glGenFramebuffers(1, & fbo_id);
glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)fbo_id);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, col_tex_id, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_id, 0);

GLenum draw_buffers[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, draw_buffers);

auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
    std::err < "Framebuffer NOT complete!\n";
    exit(1);
}

glBindFramebuffer(GL_FRAMEBUFFER, 0);
...

Still a black screen results.

No. If the data pointer is null, the texture contents are undefined. The buffer needs to be cleared with glClear before rendering a frame.

1 Like

Okay. Thanks for clearing that up.

I call the following just prior to calling glViewport(…) then rendering:

...
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
....

Still a black screen - weird

Interestingly, I added the GL debug callback and get the following error message:

GL_INVALID_OPERATION error generated. Invalid <type> parameter for current read framebuffer

Just fixed the problem. Turns out the data types between what I was retrieving from the glReadPixels(...) function and what my color texture were not matching. I pulled the values from glReadPixels(...) as a GL_FLOAT but was storing the texture as GL_UNSIGNED_BYTE. Changing the glTexImage2D(...) for color buffer to the following worked:

...
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, col_width, col_height, 0, GL_RGBA, GL_FLOAT, 0);
...

Hope this helps someone else who may have a similar issue. Thank you @GClements for help.