Search code examples
c++opengltextures

How can I read the texture data so I can edit it?


I'm using OpenGL and I've defined a texture in a framebuffer object with the following lines of code :

glGenFramebuffers(1, &ssaoFBO);
glBindFramebuffer(GL_FRAMEBUFFER, ssaoFBO);
glActiveTexture(GL_TEXTURE27);
glGenTextures(1, &ssaoTexture);
glBindTexture(GL_TEXTURE_2D, ssaoTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WG, WG, 0, GL_RGBA, 
    GL_UNSIGNED_BYTE,NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
    ssaoTexture, 0);

glDrawBuffer(GL_FRONT);
glReadBuffer(GL_NONE);

In the end I want to apply anti-aliasing to my texture. In order to do that it would be very helpful if I had the pixel data in an array.

How can I read the texture and place its data in an array? I think the function glGetBufferSubData might be helpful but I can't find a tutorial with a full example to use it properly.

Also, when I do edit the array, how can I put the new data in my texture?

Update:
If anyone else is having issues, this is how it worked for me :

std::vector<GLubyte> pixels(1024* 1024* 4);
glActiveTexture(GL_TEXTURE27);
glBindTexture(GL_TEXTURE_2D, ssaoTexture);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data()); 
// Now pixels vector contains the pixel data

//...
//Pixel editing goes here...
//...

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WG, WG, 0, GL_RGBA, GL_UNSIGNED_BYTE,
        &pixels[0]); //Sending the updated pixels to the texture

Solution

  • You've 2 possibilities. The texture is attached to a framebuffer. Either read the pixels from the framebuffer or read the texture image from the texture.

    The pixels of the framebuffer can be read by glReadPixels. Bind the framebuffer for reading and read the pixels:

    glBindFramebuffer(GL_FRAMEBUFFER, ssaoFBO);
    glReadBuffer(GL_FRONT);
    glReadPixels(0, 0, width, height, format, type, pixels);
    

    The texture image can be read by glGetTexImage. Bind the texture and read the data:

    glBindTexture(GL_TEXTURE_2D, ssaoTexture);
    glGetTexImage(GL_TEXTURE_2D, 0, format, type, pixels);
    

    In both cases format and type define the pixel format of the target data.
    e.g. If you want to store the pixels to an buffer with 4 color channels which 1 byte for each channel then format = GL_RGBA and type = GL_UNSIGNED_BYTE.
    The size of the target buffer has to be widht * height * 4.

    e.g.

    #include <vector>
    
    int width = ...;
    int height = ...;
    std::vector<GLbyte> pixels(width * height * 4); // 4 because of RGBA * 1 byte
    
    glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
    

    or

    glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
    

    Note, if the size in bytes of 1 row of the image, is not dividable by 4, then the GL_PACK_ALIGNMENT parameter has to be set, to adapt the alignment requirements for the start of each pixel row.

    e.g. for an tightly packed GL_RGB image:

    int width = ...;
    int height = ...;
    std::vector<GLbyte> pixels(width * height * 3); // 3 because of RGB * 1 byte
    
    glPixelStorei(GL_PACK_ALIGNMENT, 1);
    glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels.data());