3D C/C++ tutorials - OpenGL 2.1 - Deferred rendering - Shadow cube mapping
3D C/C++ tutorials -> OpenGL 2.1 -> Deferred rendering - Shadow cube mapping
Use for personal or educational purposes only. Commercial and other profit uses strictly prohibited. Exploitation of content on a website or in a publication prohibited.
To compile and run these tutorials some or all of these libraries are required: FreeImage 3.16.0, GLEW 1.11.0, GLUT 3.7.6 / GLUT for Dev-C++, GLM 0.9.5.4
opengl_21_tutorials_win32_framework.h
...

#define SHADOW_CUBE_MAP_SIZE 512

class COpenGLRenderer
{
protected:
    ...
    mat4x4 ..., ViewMatrixInverse, ..., ProjectionBiasMatrixInverse, LightViewMatrices[24], LightProjectionMatrix, ShadowMatrices[24];

protected:
    CTexture Texture[3];
    CShaderProgram Preprocess, SSAO, SSAOFilterH, SSAOFilterV, DeferredLighting, Antialiasing;
    GLuint RotationTexture, ShadowCubeMaps, ColorBuffers[2], NormalBuffer, DepthBuffer, SSAOBuffers[2];
    GLuint VBO, FBO;

public:
    bool CalculateAntialiasing, CalculateSSAO, CalculateShadows, ShowSSAO, BlurSSAO, Pause;
    vec3 LightColors[4], LightPositions[4];

public:
    ...

protected:
    void InitArrayBuffers();
};

...
opengl_21_tutorials_win32_framework.cpp
...

COpenGLRenderer::COpenGLRenderer()
{
    CalculateAntialiasing = true;
    CalculateSSAO = true;
    CalculateShadows = true;

    ShowSSAO = false;
    BlurSSAO = true;

    Pause = false;

    Camera.SetViewMatrixPointer(&ViewMatrix, &ViewMatrixInverse);
}

COpenGLRenderer::~COpenGLRenderer()
{
}

bool COpenGLRenderer::Init()
{
    // ------------------------------------------------------------------------------------------------------------------------

    bool Error = false;

    // ------------------------------------------------------------------------------------------------------------------------

    if(!GLEW_ARB_texture_non_power_of_two)
    {
        ErrorLog.Append("GL_ARB_texture_non_power_of_two not supported!\r\n");
        Error = true;
    }

    if(!GLEW_ARB_depth_texture)
    {
        ErrorLog.Append("GLEW_ARB_depth_texture not supported!\r\n");
        Error = true;
    }

    if(!GLEW_EXT_framebuffer_object)
    {
        ErrorLog.Append("GL_EXT_framebuffer_object not supported!\r\n");
        Error = true;
    }

    if(!GLEW_EXT_texture_array)
    {
        ErrorLog.Append("GL_EXT_texture_array not supported!\r\n");
        Error = true;
    }

    // ------------------------------------------------------------------------------------------------------------------------

    char *TextureFileName[] = {"cube.jpg", "floor.jpg", "wall.jpg"};

    for(int i = 0; i < 3; i++)
    {
        Error |= !Texture[i].LoadTexture2D(TextureFileName[i]);
    }

    // ------------------------------------------------------------------------------------------------------------------------

    Error |= !Preprocess.Load("preprocess.vs", "preprocess.fs");
    Error |= !SSAO.Load("ssao.vs", "ssao.fs");
    Error |= !SSAOFilterH.Load("ssaofilter.vs", "ssaofilterh.fs");
    Error |= !SSAOFilterV.Load("ssaofilter.vs", "ssaofilterv.fs");
    Error |= !DeferredLighting.Load("deferredlighting.vs", "deferredlighting.fs");
    Error |= !Antialiasing.Load("antialiasing.vs", "antialiasing.fs");

    // ------------------------------------------------------------------------------------------------------------------------

    if(Error)
    {
        return false;
    }

    // ------------------------------------------------------------------------------------------------------------------------

    Preprocess.UniformLocations = new GLuint[1];
    Preprocess.UniformLocations[0] = glGetUniformLocation(Preprocess, "Texturing");

    SSAO.UniformLocations = new GLuint[2];
    SSAO.UniformLocations[0] = glGetUniformLocation(SSAO, "Scale");
    SSAO.UniformLocations[1] = glGetUniformLocation(SSAO, "ProjectionBiasMatrixInverse");

    SSAOFilterH.UniformLocations = new GLuint[1];
    SSAOFilterH.UniformLocations[0] = glGetUniformLocation(SSAOFilterH, "PixelSizeX");

    SSAOFilterV.UniformLocations = new GLuint[1];
    SSAOFilterV.UniformLocations[0] = glGetUniformLocation(SSAOFilterV, "PixelSizeY");
    
    DeferredLighting.UniformLocations = new GLuint[5];
    DeferredLighting.UniformLocations[0] = glGetUniformLocation(DeferredLighting, "ProjectionBiasMatrixInverse");
    DeferredLighting.UniformLocations[1] = glGetUniformLocation(DeferredLighting, "ViewMatrixInverse");
    DeferredLighting.UniformLocations[2] = glGetUniformLocation(DeferredLighting, "ShadowMatrices");
    DeferredLighting.UniformLocations[3] = glGetUniformLocation(DeferredLighting, "CalculateSSAO");
    DeferredLighting.UniformLocations[4] = glGetUniformLocation(DeferredLighting, "CalculateShadows");

    Antialiasing.UniformLocations = new GLuint[1];
    Antialiasing.UniformLocations[0] = glGetUniformLocation(Antialiasing, "PixelSize");

    // ------------------------------------------------------------------------------------------------------------------------

    glUseProgram(SSAO);
    glUniform1i(glGetUniformLocation(SSAO, "NormalBuffer"), 0);
    glUniform1i(glGetUniformLocation(SSAO, "DepthBuffer"), 1);
    glUniform1i(glGetUniformLocation(SSAO, "RotationTexture"), 2);
    glUseProgram(0);

    float s = 128.0f, e = 131070.0f, fs = 1.0f / s, fe = 1.0f / e, fd = fs - fe;

    glUseProgram(SSAOFilterH);
    glUniform1i(glGetUniformLocation(SSAOFilterH, "SSAOBuffer"), 0);
    glUniform1i(glGetUniformLocation(SSAOFilterH, "DepthBuffer"), 1);
    glUniform1f(glGetUniformLocation(SSAOFilterH, "fs"), fs);
    glUniform1f(glGetUniformLocation(SSAOFilterH, "fd"), fd);
    glUseProgram(0);

    glUseProgram(SSAOFilterV);
    glUniform1i(glGetUniformLocation(SSAOFilterV, "SSAOBuffer"), 0);
    glUniform1i(glGetUniformLocation(SSAOFilterV, "DepthBuffer"), 1);
    glUniform1f(glGetUniformLocation(SSAOFilterV, "fs"), fs);
    glUniform1f(glGetUniformLocation(SSAOFilterV, "fd"), fd);
    glUseProgram(0);
    
    glUseProgram(DeferredLighting);
    glUniform1i(glGetUniformLocation(DeferredLighting, "ColorBuffer"), 0);
    glUniform1i(glGetUniformLocation(DeferredLighting, "NormalBuffer"), 1);
    glUniform1i(glGetUniformLocation(DeferredLighting, "DepthBuffer"), 2);
    glUniform1i(glGetUniformLocation(DeferredLighting, "SSAOBuffer"), 3);
    glUniform1i(glGetUniformLocation(DeferredLighting, "ShadowCubeMaps"), 4);
    glUseProgram(0);
    
    glUseProgram(Antialiasing);
    glUniform1i(glGetUniformLocation(Antialiasing, "ColorBuffer"), 0);
    glUniform1i(glGetUniformLocation(Antialiasing, "NormalBuffer"), 1);
    glUniform1i(glGetUniformLocation(Antialiasing, "DepthBuffer"), 2);
    glUseProgram(0);

    // ------------------------------------------------------------------------------------------------------------------------

    srand(GetTickCount());

    vec2 *Samples = new vec2[16];
    float RandomAngle = (float)M_PI_4, Radius = 1.0f;

    for(int i = 0; i < 16; i++)
    {
        Samples[i].x = cos(RandomAngle) * (float)(i + 1) / 16.0f * Radius;
        Samples[i].y = sin(RandomAngle) * (float)(i + 1) / 16.0f * Radius;

        RandomAngle += (float)M_PI_2;

        if(((i + 1) % 4) == 0) RandomAngle += (float)M_PI_4;
    }

    glUseProgram(SSAO);
    glUniform2fv(glGetUniformLocation(SSAO, "Samples"), 16, (float*)Samples);
    glUseProgram(0);

    delete [] Samples;

    // ------------------------------------------------------------------------------------------------------------------------

    vec4 *RotationTextureData = new vec4[64 * 64];

    RandomAngle = (float)rand() / (float)RAND_MAX * (float)M_PI * 2.0f;
    
    for(int i = 0; i < 64 * 64; i++)
    {
        RotationTextureData[i].x = cos(RandomAngle) * 0.5f + 0.5f;
        RotationTextureData[i].y = sin(RandomAngle) * 0.5f + 0.5f;
        RotationTextureData[i].z = -sin(RandomAngle) * 0.5f + 0.5f;
        RotationTextureData[i].w = cos(RandomAngle) * 0.5f + 0.5f;

        RandomAngle += (float)rand() / (float)RAND_MAX * (float)M_PI * 2.0f;
    }

    glGenTextures(1, &RotationTexture);
    glBindTexture(GL_TEXTURE_2D, RotationTexture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 64, 64, 0, GL_RGBA, GL_FLOAT, (float*)RotationTextureData);

    delete [] RotationTextureData;
    
    // ------------------------------------------------------------------------------------------------------------------------

    LightProjectionMatrix = perspective(90.0f, 1.0f, 0.03125f, 32.0f);

    // ------------------------------------------------------------------------------------------------------------------------

    glGenTextures(1, &ShadowCubeMaps);
    glBindTexture(GL_TEXTURE_2D_ARRAY_EXT, ShadowCubeMaps);
    glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
    glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
    glTexParameteri(GL_TEXTURE_2D_ARRAY_EXT, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
    glTexImage3D(GL_TEXTURE_2D_ARRAY_EXT, 0, GL_DEPTH_COMPONENT24, SHADOW_CUBE_MAP_SIZE, SHADOW_CUBE_MAP_SIZE, 24, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
    glBindTexture(GL_TEXTURE_2D_ARRAY_EXT, 0);

    // ------------------------------------------------------------------------------------------------------------------------

    glGenTextures(2, ColorBuffers);
    glGenTextures(1, &NormalBuffer);
    glGenTextures(1, &DepthBuffer);
    glGenTextures(2, SSAOBuffers);

    // ------------------------------------------------------------------------------------------------------------------------

    glGenBuffers(1, &VBO);

    InitArrayBuffers();

    // ------------------------------------------------------------------------------------------------------------------------

    glGenFramebuffersEXT(1, &FBO);

    // ------------------------------------------------------------------------------------------------------------------------

    LightColors[0] = vec3(1.0f, 0.0f, 0.0f);
    LightPositions[0] = vec3(0.0f, 1.5f, 0.33f);
    LightColors[1] = vec3(0.0f, 1.0f, 0.0f);
    LightPositions[1] = rotate(LightPositions[0], 120.0f, vec3(0.0f, 1.0f, 0.0f));
    LightColors[2] = vec3(0.0f, 0.0f, 1.0f);
    LightPositions[2] = rotate(LightPositions[1], 120.0f, vec3(0.0f, 1.0f, 0.0f));
    LightColors[3] = vec3(1.0f, 1.0f, 1.0f);
    LightPositions[3] = vec3(0.0f, 2.75f, -4.75f);

    for(int i = 0; i < 3; i++)
    {
        glLightfv(GL_LIGHT0 + i, GL_AMBIENT, &vec4(LightColors[i] * 0.125f, 1.0f));
        glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, &vec4(LightColors[i] * 0.875f, 1.0f));
        glLightf(GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, 1.0f);
        glLightf(GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, 1.0f);
    }

    glLightfv(GL_LIGHT3, GL_AMBIENT, &vec4(LightColors[3] * 0.25f, 1.0f));
    glLightfv(GL_LIGHT3, GL_DIFFUSE, &vec4(LightColors[3] * 0.75f, 1.0f));
    glLightf(GL_LIGHT3, GL_LINEAR_ATTENUATION, 1.0f / 32.0f);
    glLightf(GL_LIGHT3, GL_QUADRATIC_ATTENUATION, 1.0f / 64.0f);

    // ------------------------------------------------------------------------------------------------------------------------

    Camera.Look(vec3(0.0f, 1.75f, 1.875f), vec3(0.0f, 1.5f, 0.0f));

    // ------------------------------------------------------------------------------------------------------------------------

    return true;

    // ------------------------------------------------------------------------------------------------------------------------
}

void COpenGLRenderer::Render(float FrameTime)
{
    // ------------------------------------------------------------------------------------------------------------------------

    GLenum Buffers[] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};

    // render scene to textures -----------------------------------------------------------------------------------------------

    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBO);
    glDrawBuffers(2, Buffers); glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, ColorBuffers[0], 0);
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, NormalBuffer, 0);
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, DepthBuffer, 0);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadMatrixf(&ProjectionMatrix);

    glMatrixMode(GL_MODELVIEW);
    glLoadMatrixf(&ViewMatrix);

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);

    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glTexCoordPointer(2, GL_FLOAT, 32, (void*)0);

    glEnableClientState(GL_NORMAL_ARRAY);
    glNormalPointer(GL_FLOAT, 32, (void*)8);

    glEnableClientState(GL_VERTEX_ARRAY);
    glVertexPointer(3, GL_FLOAT, 32, (void*)20);

    glUseProgram(Preprocess);
    
    glUniform1i(Preprocess.UniformLocations[0], true);

    glColor3f(1.0f, 1.0f, 1.0f);

    glBindTexture(GL_TEXTURE_2D, Texture[0]);
    glDrawArrays(GL_QUADS, 0, 96);

    glBindTexture(GL_TEXTURE_2D, Texture[1]);
    glDrawArrays(GL_QUADS, 96, 4);

    glBindTexture(GL_TEXTURE_2D, Texture[2]);
    glDrawArrays(GL_QUADS, 100, 80);

    glBindTexture(GL_TEXTURE_2D, 0);

    glUniform1i(Preprocess.UniformLocations[0], false);

    glDrawArrays(GL_QUADS, 180, 4);

    glMultMatrixf(&ModelMatrix);
    glColor3f(0.33f, 0.66f, 1.0f);
    glDrawArrays(GL_QUADS, 184, 72);

    glUseProgram(0);

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glDisable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);

    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

    // calculate shadow cube maps matrices ------------------------------------------------------------------------------------

    if(CalculateShadows && !ShowSSAO)
    {
        for(int i = 0; i < 4; i++)
        {
            LightViewMatrices[i * 6 + 0] = look(LightPositions[i], LightPositions[i] + vec3( 1.0f, 0.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f));
            LightViewMatrices[i * 6 + 1] = look(LightPositions[i], LightPositions[i] + vec3(-1.0f, 0.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f));
            LightViewMatrices[i * 6 + 2] = look(LightPositions[i], LightPositions[i] + vec3( 0.0f, 1.0f, 0.0f), vec3(0.0f, 0.0f, 1.0f));
            LightViewMatrices[i * 6 + 3] = look(LightPositions[i], LightPositions[i] + vec3( 0.0f,-1.0f, 0.0f), vec3(0.0f, 0.0f,-1.0f));
            LightViewMatrices[i * 6 + 4] = look(LightPositions[i], LightPositions[i] + vec3( 0.0f, 0.0f, 1.0f), vec3(0.0f, 1.0f, 0.0f));
            LightViewMatrices[i * 6 + 5] = look(LightPositions[i], LightPositions[i] + vec3( 0.0f, 0.0f,-1.0f), vec3(0.0f, 1.0f, 0.0f));

            for(int ii = 0; ii < 6; ii++)
            {
                ShadowMatrices[i * 6 + ii] = BiasMatrix * LightProjectionMatrix * LightViewMatrices[i * 6 + ii] * ViewMatrixInverse;
            }
        }
    }

    // render scene to shadow cube maps ---------------------------------------------------------------------------------------

    if(CalculateShadows && !ShowSSAO)
    {
        glViewport(0, 0, SHADOW_CUBE_MAP_SIZE, SHADOW_CUBE_MAP_SIZE);

        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBO);
        glDrawBuffers(0, NULL); glReadBuffer(GL_NONE);
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0);
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, 0, 0);
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0);

        glMatrixMode(GL_PROJECTION);
        glLoadMatrixf(&LightProjectionMatrix);

        glEnable(GL_DEPTH_TEST);
        glEnable(GL_CULL_FACE);

        glCullFace(GL_FRONT);

        glBindBuffer(GL_ARRAY_BUFFER, VBO);

        glEnableClientState(GL_VERTEX_ARRAY);
        glVertexPointer(3, GL_FLOAT, 32, (void*)20);

        for(int i = 0; i < 24; i++)
        {
            glFramebufferTextureLayerEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, ShadowCubeMaps, 0, i);

            glClear(GL_DEPTH_BUFFER_BIT);

            glMatrixMode(GL_MODELVIEW);
            glLoadMatrixf(&LightViewMatrices[i]);

            glDrawArrays(GL_QUADS, 0, 96);
            glDrawArrays(GL_QUADS, 96, 4);
            glDrawArrays(GL_QUADS, 100, 80);
            glDrawArrays(GL_QUADS, 180, 4);
            glMultMatrixf(&ModelMatrix);
            glDrawArrays(GL_QUADS, 184, 72);
        }

        glDisableClientState(GL_VERTEX_ARRAY);

        glBindBuffer(GL_ARRAY_BUFFER, 0);

        glCullFace(GL_BACK);

        glDisable(GL_CULL_FACE);
        glDisable(GL_DEPTH_TEST);

        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

        glViewport(0, 0, Width, Height);
    }

    // calculate screen space ambient occlusion -------------------------------------------------------------------------------

    if(CalculateSSAO || ShowSSAO)
    {
        glViewport(0, 0, Width / 2, Height / 2);
        
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBO);
        glDrawBuffers(1, Buffers); glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, SSAOBuffers[0], 0);
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, 0, 0);
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0);

        glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, NormalBuffer);
        glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, DepthBuffer);
        glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, RotationTexture);
        glUseProgram(SSAO);
        glBegin(GL_QUADS);
            glVertex2f(0.0f, 0.0f);
            glVertex2f(1.0f, 0.0f);
            glVertex2f(1.0f, 1.0f);
            glVertex2f(0.0f, 1.0f);
        glEnd();
        glUseProgram(0);
        glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, 0);
        glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0);
        glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0);

        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

        // blur filter with edge detection ------------------------------------------------------------------------------------

        if(BlurSSAO)
        {
            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBO);
            glDrawBuffers(1, Buffers); glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
            glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, SSAOBuffers[1], 0);
            glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, 0, 0);
            glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0);

            glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, SSAOBuffers[0]);
            glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, DepthBuffer);
            glUseProgram(SSAOFilterH);
            glBegin(GL_QUADS);
                glVertex2f(0.0f, 0.0f);
                glVertex2f(1.0f, 0.0f);
                glVertex2f(1.0f, 1.0f);
                glVertex2f(0.0f, 1.0f);
            glEnd();
            glUseProgram(0);
            glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0);
            glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0);

            glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, SSAOBuffers[0], 0);

            glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, SSAOBuffers[1]);
            glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, DepthBuffer);
            glUseProgram(SSAOFilterV);
            glBegin(GL_QUADS);
                glVertex2f(0.0f, 0.0f);
                glVertex2f(1.0f, 0.0f);
                glVertex2f(1.0f, 1.0f);
                glVertex2f(0.0f, 1.0f);
            glEnd();
            glUseProgram(0);
            glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0);
            glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0);

            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
        }

        glViewport(0, 0, Width, Height);
    }

    // set lights positions ---------------------------------------------------------------------------------------------------

    glMatrixMode(GL_MODELVIEW);
    glLoadMatrixf(&ViewMatrix);

    for(int i = 0; i < 4; i++)
    {
        glLightfv(GL_LIGHT0 + i, GL_POSITION, &vec4(LightPositions[i], 1.0f));
    }

    // ------------------------------------------------------------------------------------------------------------------------

    if(ShowSSAO)
    {
        // display SSAO -------------------------------------------------------------------------------------------------------

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        glColor3f(1.0f, 1.0f, 1.0f);

        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, SSAOBuffers[0]);
        glBegin(GL_QUADS);
            glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f);
            glTexCoord2f(1.0f, 0.0f); glVertex2f( 1.0f, -1.0f);
            glTexCoord2f(1.0f, 1.0f); glVertex2f( 1.0f,  1.0f);
            glTexCoord2f(0.0f, 1.0f); glVertex2f(-1.0f,  1.0f);
        glEnd();
        glBindTexture(GL_TEXTURE_2D, 0);
        glDisable(GL_TEXTURE_2D);
    }
    else
    {
        // calculate lighting -------------------------------------------------------------------------------------------------

        if(CalculateAntialiasing)
        {
            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBO);
            glDrawBuffers(1, Buffers); glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
            glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, ColorBuffers[1], 0);
            glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, 0, 0);
            glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0);
        }

        glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, ColorBuffers[0]);
        glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, NormalBuffer);
        glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, DepthBuffer);
        glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, SSAOBuffers[0]);
        glActiveTexture(GL_TEXTURE4); glBindTexture(GL_TEXTURE_2D_ARRAY_EXT, ShadowCubeMaps);
        glUseProgram(DeferredLighting);
        if(CalculateShadows) glUniformMatrix4fv(DeferredLighting.UniformLocations[1], 1, GL_FALSE, &ViewMatrixInverse);
        if(CalculateShadows) glUniformMatrix4fv(DeferredLighting.UniformLocations[2], 24, GL_FALSE, (float*)ShadowMatrices);
        glUniform1i(DeferredLighting.UniformLocations[3], CalculateSSAO);
        glUniform1i(DeferredLighting.UniformLocations[4], CalculateShadows);
        glBegin(GL_QUADS);
            glVertex2f(0.0f, 0.0f);
            glVertex2f(1.0f, 0.0f);
            glVertex2f(1.0f, 1.0f);
            glVertex2f(0.0f, 1.0f);
        glEnd();
        glUseProgram(0);
        glActiveTexture(GL_TEXTURE4); glBindTexture(GL_TEXTURE_2D_ARRAY_EXT, 0);
        glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, 0);
        glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, 0);
        glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0);
        glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0);
    
        if(CalculateAntialiasing)
        {
            glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
        }

        // calculate antialiasing ---------------------------------------------------------------------------------------------

        if(CalculateAntialiasing)
        {
            glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, ColorBuffers[1]);
            glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, NormalBuffer);
            glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, DepthBuffer);
            glUseProgram(Antialiasing);
            glBegin(GL_QUADS);
                glVertex2f(0.0f, 0.0f);
                glVertex2f(1.0f, 0.0f);
                glVertex2f(1.0f, 1.0f);
                glVertex2f(0.0f, 1.0f);
            glEnd();
            glUseProgram(0);
            glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, 0);
            glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0);
            glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0);
        }
    }

    // rotate object and lights -----------------------------------------------------------------------------------------------

    if(!Pause)
    {
        static float a = 0.0f;

        ModelMatrix = translate(0.0f, 1.5f, 0.0f) * rotate(a, vec3(0.0f, 1.0f, 0.0f)) * rotate(a, vec3(1.0f, 0.0f, 0.0f));

        a += 22.5f * FrameTime;

        for(int i = 0; i < 3; i++)
        {
            LightPositions[i] = rotate(LightPositions[i], -180.0f * FrameTime, vec3(0.0f, 1.0f, 0.0f));
        }
    }

    // ------------------------------------------------------------------------------------------------------------------------
}

void COpenGLRenderer::Resize(int Width, int Height)
{
    this->Width = Width;
    this->Height = Height;

    glViewport(0, 0, Width, Height);

    ProjectionMatrix = perspective(45.0f, (float)Width / (float)Height, 0.125f, 512.0f);

    ProjectionBiasMatrixInverse = inverse(ProjectionMatrix) * BiasMatrixInverse;

    for(int i = 0; i < 2; i++)
    {
        glBindTexture(GL_TEXTURE_2D, ColorBuffers[i]);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
        glBindTexture(GL_TEXTURE_2D, 0);
    }

    glBindTexture(GL_TEXTURE_2D, NormalBuffer);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glBindTexture(GL_TEXTURE_2D, 0);

    glBindTexture(GL_TEXTURE_2D, DepthBuffer);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, Width, Height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
    glBindTexture(GL_TEXTURE_2D, 0);

    for(int i = 0; i < 2; i++)
    {
        glBindTexture(GL_TEXTURE_2D, SSAOBuffers[i]);
        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_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Width / 2, Height / 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
        glBindTexture(GL_TEXTURE_2D, 0);
    }
    
    glUseProgram(SSAO);
    glUniform2f(SSAO.UniformLocations[0], (float)Width / 2.0f / 64.0f, (float)Height / 2.0f / 64.0f);
    glUniformMatrix4fv(SSAO.UniformLocations[1], 1, GL_FALSE, &ProjectionBiasMatrixInverse);
    glUseProgram(0);

    glUseProgram(SSAOFilterH);
    glUniform1f(SSAOFilterH.UniformLocations[0], 2.0f / (float)Width);
    glUseProgram(SSAOFilterV);
    glUniform1f(SSAOFilterV.UniformLocations[0], 2.0f / (float)Height);
    glUseProgram(0);
    
    glUseProgram(DeferredLighting);
    glUniformMatrix4fv(DeferredLighting.UniformLocations[0], 1, GL_FALSE, &ProjectionBiasMatrixInverse);
    glUseProgram(0);

    glUseProgram(Antialiasing);
    glUniform2f(Antialiasing.UniformLocations[0], 1.0f / (float)Width, 1.0f / (float)Height);
    glUseProgram(0);
}

void COpenGLRenderer::Destroy()
{
    for(int i = 0; i < 3; i++)
    {
        Texture[i].Destroy();
    }

    Preprocess.Destroy();
    SSAO.Destroy();
    SSAOFilterH.Destroy();
    SSAOFilterV.Destroy();
    DeferredLighting.Destroy();
    Antialiasing.Destroy();

    glDeleteBuffers(1, &VBO);

    glDeleteTextures(1, &RotationTexture);
    glDeleteTextures(1, &ShadowCubeMaps);
    glDeleteTextures(2, ColorBuffers);
    glDeleteTextures(1, &NormalBuffer);
    glDeleteTextures(1, &DepthBuffer);
    glDeleteTextures(2, SSAOBuffers);

    if(GLEW_EXT_framebuffer_object)
    {
        glDeleteFramebuffersEXT(1, &FBO);
    }
}

void COpenGLRenderer::InitArrayBuffers()
{
    CBuffer buffer;

    ...

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, buffer.GetDataSize(), buffer.GetData(), GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    buffer.Empty();
}

...

void COpenGLView::OnKeyDown(UINT Key)
{
    switch(Key)
    {
        ...

        case VK_F3:
            OpenGLRenderer.CalculateShadows = !OpenGLRenderer.CalculateShadows;
            break;

        case VK_F4:
            OpenGLRenderer.ShowSSAO = !OpenGLRenderer.ShowSSAO;
            break;

        case VK_F5:
            OpenGLRenderer.BlurSSAO = !OpenGLRenderer.BlurSSAO;
            break;

        ...
    }
}

...
deferredlighting.vs
#version 120

void main()
{
    gl_TexCoord[0] = gl_Vertex;
    gl_Position = gl_Vertex * 2.0 - 1.0;
}
deferredlighting.fs
#version 120

#extension GL_EXT_texture_array : enable

uniform sampler2D ColorBuffer, NormalBuffer, DepthBuffer, SSAOBuffer;
uniform sampler2DArrayShadow ShadowCubeMaps;
uniform mat4x4 ProjectionBiasMatrixInverse, ViewMatrixInverse, ShadowMatrices[24];
uniform bool CalculateSSAO, CalculateShadows;

void main()
{
    gl_FragColor = texture2D(ColorBuffer, gl_TexCoord[0].st);

    float Depth = texture2D(DepthBuffer, gl_TexCoord[0].st).r;

    if(Depth < 1.0)
    {
        vec3 Normal = normalize(texture2D(NormalBuffer, gl_TexCoord[0].st).rgb * 2.0 - 1.0);

        vec4 Position = ProjectionBiasMatrixInverse * vec4(gl_TexCoord[0].st, Depth, 1.0);
        Position /= Position.w;

        float SSAO = CalculateSSAO ? texture2D(SSAOBuffer, gl_TexCoord[0].st).r : 1.0;

        vec3 Light = vec3(0.0);

        for(int i = 0; i < 4; i++)
        {
            vec3 LightDirection = gl_LightSource[i].position.xyz - Position.xyz;

            float LightDistance2 = dot(LightDirection, LightDirection);
            float LightDistance = sqrt(LightDistance2);

            LightDirection /= LightDistance;

            float NdotLD = max(dot(Normal, LightDirection), 0.0);

            float Attenuation = gl_LightSource[i].constantAttenuation;

            Attenuation += gl_LightSource[i].linearAttenuation * LightDistance;
            Attenuation += gl_LightSource[i].quadraticAttenuation * LightDistance2;

            float Shadow = 1.0;

            if(CalculateShadows)
            {
                LightDirection = (ViewMatrixInverse * vec4(LightDirection, 0.0)).xyz;

                float Axis[6];

                Axis[0] = -LightDirection.x;
                Axis[1] = LightDirection.x;
                Axis[2] = -LightDirection.y;
                Axis[3] = LightDirection.y;
                Axis[4] = -LightDirection.z;
                Axis[5] = LightDirection.z;

                int MaxAxisID = 0;

                for(int ii = 1; ii < 6; ii++)
                {
                    if(Axis[ii] > Axis[MaxAxisID])
                    {
                        MaxAxisID = ii;
                    }
                }

                int Index = i * 6 + MaxAxisID;

                vec4 ShadowTexCoord = ShadowMatrices[Index] * vec4(Position.xyz, 1.0);
                ShadowTexCoord.xyz /= ShadowTexCoord.w;
                ShadowTexCoord.w = ShadowTexCoord.z;
                ShadowTexCoord.z = float(Index);

                Shadow = shadow2DArray(ShadowCubeMaps, ShadowTexCoord).r;
            }

            Light += (gl_LightSource[i].ambient.rgb * SSAO + gl_LightSource[i].diffuse.rgb * NdotLD * Shadow) / Attenuation;
        }

        gl_FragColor.rgb *= Light;
    }
}
Download
deferred_rendering_shadow_cube_mapping.zip (Visual Studio 2005 Professional)

© 2010 - 2016 Bc. Michal Belanec, michalbelanec (at) centrum (dot) sk
Last update June 25, 2016
OpenGL® is a registered trademark of Silicon Graphics Inc.