Search code examples
c++openglglslshadermirror

Render inverted scene to framebuffer


I need some help with rendering inverted scene to framebuffer. I want to make a mirror effect. What i have in result: My result Initializing frame buffer:

GLuint FramebufferName = 0;
glGenFramebuffers(1, &FramebufferName);
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);

GLuint renderedTexture;
glGenTextures(1, &renderedTexture);
glBindTexture(GL_TEXTURE_2D, renderedTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SCREEN_WIDTH, SCREEN_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderedTexture, 0);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glReadBuffer(GL_NONE);

Draw scene to frame buffer:

    mView = camera.getViewMatrix();
    mProjection = perspective(45.0f, 4.0f / 3.0f, 0.1f, 300.0f) * scale(mat4(1.0f), vec3(1.0f, -1.0f, 1.0f)); 
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FramebufferName);
    glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glCullFace(GL_FRONT);
    glEnable(GL_CULL_FACE);
    mWorld = rotate(mWorld, -15.0f, vec3(1, 0, 0));
    mWorld = rotate(mWorld, -30.0f, vec3(0, 1, 0));
    cubemap.Draw(mView, mProjection, mWorld);
    glDisable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);
    glUseProgram(program);
    mWorld = translate(mat4(1.0f), vec3(0, -10, 0));
    glUniformMatrix4fv(mvp_object, 1, GL_FALSE, value_ptr(mProjection * mView * mWorld * scale(mat4(1.0f), vec3(10.0f))));
    cannon.Draw(program);

    mWorld = mat4(1.0f);
    mWorld = translate(mat4(1.0f), vec3(50, -10, 0));
    mWorld = rotate(mWorld, 90.0f, vec3(0, 1, 0));
    glUniformMatrix4fv(mvp_object, 1, GL_FALSE, value_ptr(mProjection * mView * mWorld * scale(mat4(1.0f), vec3(10.0f))));
    cannon.Draw(program);

    mWorld = mat4(1.0f);
    mWorld = translate(mat4(1.0f), vec3(0, -10, 50));
    mWorld = rotate(mWorld, 140.0f, vec3(0, 1, 0));
    glUniformMatrix4fv(mvp_object, 1, GL_FALSE, value_ptr(mProjection * mView * mWorld * scale(mat4(1.0f), vec3(10.0f))));
    cannon.Draw(program);

    glDisable(GL_DEPTH_TEST);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

I saw some tutorials where used glScalef(1.0, -1.0, 1.0) to invert scene. glScalef was used in old versions of opengl. How can i invert scene in new versions of opengl? I've multiplied projection matrix on scale(mat4(1.0f), vec3(1.0, -1.0, 1.0)) for this effect. Is it right?


Solution

  • Here is the vertex shader written in GLSL.

    void main(void)
    {
       // Clean up inaccuracies
       vec2 Pos = sign(gl_Vertex.xy);
    
       gl_Position = vec4(Pos.xy, 0.0, 1.0);
       // Image-space
       gl_TexCoord[0].xy = vec2(-Pos.x, Pos.y) * 0.5 + 0.5; // x texture coord is inverted       
    }
    

    Pos refers to screen aligned quad for framebuffer output.

    Fragment shader

    uniform sampler2D framebufferSampler;
    
    void main(void)
    {
       gl_FragColor = texture2D(framebufferSampler, gl_TexCoord[0].xy);
    }
    

    Screen aligned quad can be drawn

    glBegin(GL_QUADS)
    {
        glVertex2f(-1.0f, -1.0f);
        glVertex2f(1.0f, -1.0f);
        glVertex2f(1.0f, 1.0f);
        glVertex2f(-1.0f, 1.0f);
    }
    glEnd();
    

    or using vertex arrays.

    GLfloat vertices[] = {
        -1.0f, -1.0f,
        1.0f, -1.0f,
        1.0f, 1.0f,
        -1.0f, 1.0f
    };
    
    glEnableClientState(GL_VERTEX_ARRAY);
    
    glVertexPointer(2, GL_FLOAT, 0, (void*)vertices);
    
    glDrawArrays(GL_QUADS, 0, 4);
    
    glDisableClientState(GL_VERTEX_ARRAY);
    

    texture that is used to be wraped to the quad, is the framebuffer info with previous rendered content (multipass shader technique).

    You can also do so with others 2D texture coords or images instead of framebuffer and screen align quads.

    Original image.

    enter image description here

    Inverted image.

    enter image description here

    More info can be found in Learn OpenGL.