Search code examples
androidopengl-estexturesopengl-es-2.0

Render to texture attached to Frame Buffer Object (texture appears black)


I have generated a frame buffer object(FBO), bind it, attached a texture to its GL_COLOR_ATTACHMENT0. Then ensure that I get its status as GL_FRAMEBUFFER_COMPLETE. I have another texture(which is displaying on display), let's call it workingTexture. Now I want to render this workingTexture onto FBO, so I bind this FBO and then render workingTexture. Then I bind default frame buffer(reserved for display) and try to render the texture attached to FBO, thinking that I will get my texture onto display, but I get black texture.

Relevant code

code to generate workingTexture...

int[] workingTexture = new int[1];

glGenTextures(1, workingTexture, 0); // generate workingTexture
glActiveTexture(GL_TEXTURE0);  // attach it to TEXTURE_UNIT0
glBindTexture(GL_TEXTURE_2D, workingTexture[0]);
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_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);

code to generate fbo

int[] fboName = new int[1];
int[] fboTextureName = new int[1];
final int fboTextureUnit = 1;  // attach this texture to texture unit GL_TEXTURE1
glGenFramebuffers(1, fboName, 0);

int generatedTextureNameForFBO =
                generateTextureForFBO(fboTextureUnit,
                        width, height);
fboTextureName[0] = generatedTextureNameForFBO;

glBindFramebuffer(GL_FRAMEBUFFER, fboName[0]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                GL_TEXTURE_2D, generatedTextureNameForFBO, 0);

if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
            // created FBO is not complete
            throw new RuntimeException("FBO status INCOMPLETE 😔😔");

        }

method used to generate texture attached to fbo

 private int generateTextureForFBO(@IntRange(from = 0) final int textureUnit,
                                  @IntRange(from = 1) final int width,
                                  @IntRange(from = 1) final int height) {
    int[] textureName = new int[1];
    glGenTextures(1, textureName, 0);
    glActiveTexture(GL_TEXTURE0 + textureUnit);
    glBindTexture(GL_TEXTURE_2D, textureName[0]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null);
  //        glBindTexture(GL_TEXTURE_2D, 0);
  //        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_MIRRORED_REPEAT);
  //        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
  //        glBindTexture(GL_TEXTURE_2D, 0);
    return textureName[0];
}

Now coming to drawing part...

@Override
public void onDrawFrame(GL10 unused) {
    glClear(GL_COLOR_BUFFER_BIT);
    //renderTex(mViewMatrix, 0, texProgram);  // this texture is drawing on screen

    glBindFramebuffer(GL_FRAMEBUFFER, fboName[0]);
    renderTex(mViewMatrix, 0, texProgram);   // rendering workingTexture onto FBO

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    renderTex(mViewMatrix, fboTextureUnit[0], texProgram);  // texture appears black

}

renderTex is a simple method to render texture. It is working fine.

Also I have checked for GL_ERROR but there is no error.

My understanding of application created FBO is that every read and write glCall will happen on currently bound FBO, so is my understanding of FBO incorrect, or is there some error in my code.

Platform OpenGL|es 20 on Android


Solution

  • The texture which is generated in generateTextureForFBO is mipmap incomplete.

    If you do not generate mipmaps (by glGenerateMipmap), then setting the GL_TEXTURE_MIN_FILTER is important. Since the default filter is GL_NEAREST_MIPMAP_LINEAR the texture would be mipmap incomplete, if you don not change the minifying function to GL_NEAREST or GL_LINEAR.

    Set the texture minifying function (GL_TEXTURE_MIN_FILTER) by glTexParameter:

    glBindTexture(GL_TEXTURE_2D, textureName[0]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, null);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);