Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 4 of 4

Thread: 2D sprite/texture is inverted when using framebuffer

  1. #1
    Newbie Newbie
    Join Date
    Sep 2018
    Posts
    2

    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/...dering-Sprites
    have a look at initRenderData()

    Code :
    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?




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

    Code :
    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

    Code :
        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

    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

    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

    Code :
       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?
    Attached Thumbnails Attached Thumbnails Click image for larger version. 

Name:	image.png.f1aaa28341d095205b8fd3d9fca88f0a.jpg 
Views:	4 
Size:	7.3 KB 
ID:	2836   Click image for larger version. 

Name:	image.png.faa640ddcf05e9992e3221026e82cffe.jpg 
Views:	6 
Size:	7.8 KB 
ID:	2837   Click image for larger version. 

Name:	image.png.44fb68ceee89a2408b460808b69085ed.jpg 
Views:	7 
Size:	9.9 KB 
ID:	2838   Click image for larger version. 

Name:	image.png.a65899c4261190da0212bf91fde61c20.jpg 
Views:	9 
Size:	8.2 KB 
ID:	2839  

  2. #2
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,926
    Quote Originally Posted by cebugdev View Post
    I know that most inverted texture issue is because of inverted coordinate system but this case maybe different.
    Inverted texture coordinates usually arise from the combination of:

    1. Window coordinates of (0,0) correspond to the lower-left corner.
    2. Texture coordinates of (0,0) correspond to the first pixel of data passed to glTex[Sub]Image*.
    3. Most texture formats store the "top" row first and the "bottom" row last.


    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.

  3. #3
    Newbie Newbie
    Join Date
    Sep 2018
    Posts
    2
    Quote Originally Posted by GClements View Post
    Inverted texture coordinates usually arise from the combination of:

    1. Window coordinates of (0,0) correspond to the lower-left corner.
    2. Texture coordinates of (0,0) correspond to the first pixel of data passed to glTex[Sub]Image*.
    3. Most texture formats store the "top" row first and the "bottom" row last.


    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.
    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?

  4. #4
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,926
    Quote Originally Posted by cebugdev View Post
    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.
    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.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •