2D sprite/texture is inverted when using framebuffer

Hi all,
I know that most inverted texture issue is because of inverted coordinate system but this case maybe different.
so here are the facts.

  1. I am rendering a 2D sprite using a quad and a texture in orthographic projection.
    I was just following the code from learnopengl.com here
    https://learnopengl.com/In-Practice/2D-Game/Rendering-Sprites
    have a look at initRenderData()
void SpriteRenderer::initRenderData()
{
    // Configure VAO/VBO
    GLuint VBO;
    GLfloat vertices[] = { 
        // Pos      // Tex
        0.0f, 1.0f, 0.0f, 1.0f,
        1.0f, 0.0f, 1.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 0.0f, 
    
        0.0f, 1.0f, 0.0f, 1.0f,
        1.0f, 1.0f, 1.0f, 1.0f,
        1.0f, 0.0f, 1.0f, 0.0f
    };

  ...
}

Please take note that this was rendered in orthographic projection,
which means the coordinates of this quads are in screenspace (top left are 0,0 and bottom right are width,height)
and please observed the texture coordinate as well, instead of 0,0 at the bottom left, with width, height at top right
the coordinates is inverted instead.
SO if we are using orthographic projection, does this mean texture coordinates are inverted as well?
Is this assumption correct?


  1. When rendering this quad straight, everything is OK and rendered with proper orientation

void Sprite2D_Draw(int x, int y, int width, int height, GLuint texture)
{
    // Prepare transformations
    glm::mat4 model = glm::mat4(1.0f);    //initialize to identity

                                        // First translate (transformations are: scale happens first,
                                        // then rotation and then finall translation happens; reversed order)

    model = glm::translate(model, glm::vec3(x, y, 0.0f));

    //Resize to current scale
    model = glm::scale(model, glm::vec3(width, height, 1.0f));

    spriteShader.Use();

    int projmtx = spriteShader.GetUniformLocation("projection");
    spriteShader.SetUniformMatrix(projmtx, projection);

    int modelmtx = spriteShader.GetUniformLocation("model");
    spriteShader.SetUniformMatrix(modelmtx, model);

    int textureID = spriteShader.GetUniformLocation("texture");
    glUniform1i(textureID, 0);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);

    glBindVertexArray(_quadVAO);

    glBindBuffer(GL_ARRAY_BUFFER, _VBO);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)0);

    glDrawArrays(GL_TRIANGLES, 0, 6);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

draw call

    
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    //display to main screen
    Sprite2D_Draw(0, 0, 500, 376, _spriteTexture);

result


BUT

when rendering that image into a frame buffer, the result is inverted!

here is the code


#if 1
        frameBuffer.Bind();

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        //... display backbuffer contents here
        //draw sprite at backbuffer 0,0
        Sprite2D_Draw(0, 0, 1000, 750, _spriteTexture);

        //-----------------------------------------------------------------------------
        // Restore frame buffer        
        frameBuffer.Unbind(SCR_WIDTH, SCR_HEIGHT);
#endif

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        //display to main screen
        Sprite2D_Draw(0, 0, 500, 376, frameBuffer.GetColorTexture());

result, why?

for reference here is the FBO code

int    FBO::Initialize(int width, int height, bool createDepthStencil)
{
    int error = 0;

    _width = width;
    _height = height;

    // 1. create frame buffer
    glGenFramebuffers(1, &_frameBuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);

    // 2. create a blank texture which will contain the RGB output of our shader.
    // data is set to NULL
    glGenTextures(1, &_texColorBuffer);
    glBindTexture(GL_TEXTURE_2D, _texColorBuffer);

    glTexImage2D(
        GL_TEXTURE_2D, 0, GL_RGB, _width, _height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL
    );

    error = glGetError();

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    // 3. attached our texture to the frame buffer, note that our custom frame buffer is already active
    // by glBindFramebuffer
    glFramebufferTexture2D(
        GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texColorBuffer, 0
    );

    error = glGetError();

    // 4. we create the depth and stencil buffer also, (this is optional)
    if (createDepthStencil) {
        GLuint rboDepthStencil;
        glGenRenderbuffers(1, &rboDepthStencil);
        glBindRenderbuffer(GL_RENDERBUFFER, rboDepthStencil);
        glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, _width, _height);
    }

    error = glGetError();

    // Set the list of draw buffers. this is not needed?
    //GLenum DrawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
    //glDrawBuffers(1, DrawBuffers); // "1" is the size of DrawBuffers
    error = glGetError();
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
    {
        return -1;
    }
    // Restore frame buffer
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    return glGetError();;
}

void FBO::Bind()
{
    // Render to our frame buffer
    glBindFramebuffer(GL_FRAMEBUFFER, _frameBuffer);
    glViewport(0, 0, _width, _height);                        // use the entire texture,
                                                            // this means that use the dimension set as our total 
                                                            // display area
}

void FBO::Unbind(int width, int height)
{
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glViewport(0, 0, width, height);
}

int FBO::GetColorTexture()
{
    return _texColorBuffer;
}

this is how it was initialized

   FBO frameBuffer;
    frameBuffer.Initialize(1024, 1080);    

    spriteShader.Init();
    spriteShader.LoadVertexShaderFromFile("./shaders/basic_vshader.txt");
    spriteShader.LoadFragmentShaderFromFile("./shaders/basic_fshader.txt");
    spriteShader.Build();

    hayleyTex = LoadTexture("./textures/smiley.jpg");
    Sprite2D_InitData();

Any one knows what is going on in here?

Inverted texture coordinates usually arise from the combination of:

[ol]
[li] Window coordinates of (0,0) correspond to the lower-left corner.
[/li][li] Texture coordinates of (0,0) correspond to the first pixel of data passed to glTex[Sub]Image*.
[/li][li] Most texture formats store the “top” row first and the “bottom” row last.
[/li][/ol]

So if you draw a quad where texture coordinates of (0,0) are mapped to window coordinates of (0,0) and the texture data was supplied in top-row-first order, the image will be inverted.

Either invert the texture coordinates, invert the projection transformation (so (0,0) is at the top of the viewport), or re-order the texture data so that it starts with the bottom row. Re-ordering the texture data is time-consuming but it provides consistency with data retrieved from glReadPixels() and rendering to textures via FBOs.

[QUOTE=GClements;1292516]Inverted texture coordinates usually arise from the combination of:

[ol]
[li] Window coordinates of (0,0) correspond to the lower-left corner.[/li][li] Texture coordinates of (0,0) correspond to the first pixel of data passed to glTex[Sub]Image*.[/li][li] Most texture formats store the “top” row first and the “bottom” row last.[/li][/ol]

So if you draw a quad where texture coordinates of (0,0) are mapped to window coordinates of (0,0) and the texture data was supplied in top-row-first order, the image will be inverted.

Either invert the texture coordinates, invert the projection transformation (so (0,0) is at the top of the viewport), or re-order the texture data so that it starts with the bottom row. Re-ordering the texture data is time-consuming but it provides consistency with data retrieved from glReadPixels() and rendering to textures via FBOs.[/QUOTE]

Hi, Thank you for giving me more information on the cause of inverted coordinates,
but i think my problem here is when it is rendered in a frame buffer object (see my orig) post,
the quad with texture when rendered normally is ok, but when rendered into a frame buffer object it became inverted, that is my issue.

DO you know any explanation to this as to why?

How does rendering to framebuffers differ form rendering to main render target and why was it inverted during the render?

[QUOTE=cebugdev;1292520]Hi, Thank you for giving me more information on the cause of inverted coordinates,
but i think my problem here is when it is rendered in a frame buffer object (see my orig) post,
the quad with texture when rendered normally is ok, but when rendered into a frame buffer object it became inverted, that is my issue.
[/QUOTE]
Are you rendering to a framebuffer then rendering the framebuffer’s texture to the screen? If so, then you’re using inverted texture coordinates for the latter (bear in mind that texture coordinates of 0,0 will be the bottom-left corner of the framebuffer’s texture).

Or are you rendering to the framebuffer then retrieving the pixel data? If so, bear in mind that data returned by glReadPixels() or glGetTexImage() starts with the bottom row.