3D C/C++ tutorials - OpenGL 2.1 - High dynamic range, bloom
3D C/C++ tutorials -> OpenGL 2.1 -> High dynamic range, bloom
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_tutorials_win32_framework.h
...

class COpenGLRenderer
{
protected:
    int Width, Height;
    mat4x4 Model, View, Projection;

    CTexture Kocka, Podlaha;
    GLuint HDRColorBuffer, DepthBuffer, LuminanceBuffer, MinificationBuffer[8], LDRColorBuffer, BrightPixelsBuffer, BloomBuffer[12];
    GLuint FBO;
    CShaderProgram PerPixelLighting, Luminance, Minification, ToneMapping, BrightPixels, BlurH, BlurV;
    float *data;

public:
    CString Text;
    float Intensity;

public:
    COpenGLRenderer();
    ~COpenGLRenderer();

    bool Init();
    void Render(float FrameTime);
    void Resize(int Width, int Height);
    void Destroy();
};

...
opengl_tutorials_win32_framework.cpp
...

COpenGLRenderer::COpenGLRenderer()
{
    Camera.SetViewMatrixPointer(&View);
}

COpenGLRenderer::~COpenGLRenderer()
{
}

bool COpenGLRenderer::Init()
{
    if(gl_version < 21)
    {
        ErrorLog.Set("OpenGL 2.1 not supported!");
        return false;
    }

    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("GL_ARB_depth_texture not supported!\r\n");
        Error = true;
    }

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

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

    Error |= !Kocka.LoadTexture2D("kocka.jpg");
    Error |= !Podlaha.LoadTexture2D("podlaha.jpg");

    Error |= !PerPixelLighting.Load("per_pixel_lighting.vs", "per_pixel_lighting.fs");
    Error |= !Luminance.Load("luminance.vs", "luminance.fs");
    Error |= !Minification.Load("minification.vs", "minification.fs");
    Error |= !ToneMapping.Load("tone_mapping.vs", "tone_mapping.fs");
    Error |= !BrightPixels.Load("bright_pixels.vs", "bright_pixels.fs");
    Error |= !BlurH.Load("blur.vs", "blurh.fs");
    Error |= !BlurV.Load("blur.vs", "blurv.fs");

    if(Error)
    {
        return false;
    }

    PerPixelLighting.UniformLocations = new GLuint[1];
    PerPixelLighting.UniformLocations[0] = glGetUniformLocation(PerPixelLighting, "CameraPosition");

    Luminance.UniformLocations = new GLuint[2];
    Luminance.UniformLocations[0] = glGetUniformLocation(Luminance, "odx");
    Luminance.UniformLocations[1] = glGetUniformLocation(Luminance, "ody");

    ToneMapping.UniformLocations = new GLuint[1];
    ToneMapping.UniformLocations[0] = glGetUniformLocation(ToneMapping, "MaxRGBValue");

    BlurH.UniformLocations = new GLuint[2];
    BlurH.UniformLocations[0] = glGetUniformLocation(BlurH, "Width");
    BlurH.UniformLocations[1] = glGetUniformLocation(BlurH, "odw");

    BlurV.UniformLocations = new GLuint[2];
    BlurV.UniformLocations[0] = glGetUniformLocation(BlurV, "Width");
    BlurV.UniformLocations[1] = glGetUniformLocation(BlurV, "odh");

    glUseProgram(BlurH);
    glUniform1i(BlurH.UniformLocations[0], 5);
    glUseProgram(BlurV);
    glUniform1i(BlurV.UniformLocations[0], 5);
    glUseProgram(0);

    glGenTextures(1, &HDRColorBuffer);
    glGenTextures(1, &DepthBuffer);
    glGenTextures(1, &LuminanceBuffer);
    glGenTextures(8, MinificationBuffer);
    glGenTextures(1, &LDRColorBuffer);
    glGenTextures(1, &BrightPixelsBuffer);
    glGenTextures(12, BloomBuffer);

    glGenFramebuffers(1, &FBO);

    data = new float[4096];

    Intensity = 2.0f;

    glLightfv(GL_LIGHT0, GL_AMBIENT, &vec4(vec3(0.25f), 1.0f));
    glLightfv(GL_LIGHT0, GL_POSITION, &vec4(-2.0f, 2.0f, -2.0f, 1.0f));

    return true;
}

void COpenGLRenderer::Render(float FrameTime)
{
    // set viewport, perspective projection and modelview matrix --------------------------------------------------------------

    glViewport(0, 0, Width, Height);

    glMatrixMode(GL_PROJECTION);
    glLoadMatrixf(&Projection);

    glMatrixMode(GL_MODELVIEW);
    glLoadMatrixf(&View);

    // set light diffuse color ------------------------------------------------------------------------------------------------

    glLightfv(GL_LIGHT0, GL_DIFFUSE, &vec4(vec3(Intensity), 1.0f));

    // render scene to HDRColorBuffer texture ---------------------------------------------------------------------------------

    glBindFramebuffer(GL_FRAMEBUFFER, FBO);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, HDRColorBuffer, 0);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, DepthBuffer, 0);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);

    glUseProgram(PerPixelLighting);
    glUniform3fv(PerPixelLighting.UniformLocations[0], 1, &Camera.Position);

    glBindTexture(GL_TEXTURE_2D, Kocka);
    glBegin(GL_QUADS);
        glNormal3f( 0.0f,  0.0f,  1.0f);
        glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5f, -0.5f,  0.5f);
        glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.5f, -0.5f,  0.5f);
        glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.5f,  0.5f,  0.5f);
        glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5f,  0.5f,  0.5f);
        glNormal3f( 0.0f,  0.0f, -1.0f);
        glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.5f, -0.5f, -0.5f);
        glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.5f, -0.5f, -0.5f);
        glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.5f,  0.5f, -0.5f);
        glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.5f,  0.5f, -0.5f);
        glNormal3f( 1.0f,  0.0f,  0.0f);
        glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.5f, -0.5f,  0.5f);
        glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.5f, -0.5f, -0.5f);
        glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.5f,  0.5f, -0.5f);
        glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.5f,  0.5f,  0.5f);
        glNormal3f(-1.0f,  0.0f,  0.0f);
        glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5f, -0.5f, -0.5f);
        glTexCoord2f(1.0f, 0.0f); glVertex3f(-0.5f, -0.5f,  0.5f);
        glTexCoord2f(1.0f, 1.0f); glVertex3f(-0.5f,  0.5f,  0.5f);
        glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5f,  0.5f, -0.5f);
        glNormal3f( 0.0f,  1.0f,  0.0f);
        glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5f,  0.5f,  0.5f);
        glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.5f,  0.5f,  0.5f);
        glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.5f,  0.5f, -0.5f);
        glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5f,  0.5f, -0.5f);
        glNormal3f( 0.0f,  -1.0f,  0.0f);
        glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5f, -0.5f, -0.5f);
        glTexCoord2f(1.0f, 0.0f); glVertex3f( 0.5f, -0.5f, -0.5f);
        glTexCoord2f(1.0f, 1.0f); glVertex3f( 0.5f, -0.5f,  0.5f);
        glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5f, -0.5f,  0.5f);
    glEnd();

    glBindTexture(GL_TEXTURE_2D, Podlaha);
    glBegin(GL_QUADS);
        glNormal3f(0.0f, 1.0f, 0.0f);
        glTexCoord2f( 0.0f,  0.0f); glVertex3f(-5.0f, -0.5f,  5.0f);
        glTexCoord2f(10.0f,  0.0f); glVertex3f( 5.0f, -0.5f,  5.0f);
        glTexCoord2f(10.0f, 10.0f); glVertex3f( 5.0f, -0.5f, -5.0f);
        glTexCoord2f( 0.0f, 10.0f); glVertex3f(-5.0f, -0.5f, -5.0f);
    glEnd();

    glUseProgram(0);
    
    glDisable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);

    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    // set orthogonal projection and reset modelview matrix -------------------------------------------------------------------

    glMatrixMode(GL_PROJECTION);
    glLoadMatrixf(&OrthogonalProjectionMatrix(0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f));

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    // get the maximal value of the RGB components of the HDR image -----------------------------------------------------------

    static float MaxRGBValue = 1.0f, maxrgbvalue = 1.0f, mrgbvi, oldmaxrgbvalue = maxrgbvalue;
    static DWORD LastTime = 0;

    DWORD Time = GetTickCount();

    if(Time - LastTime > 250) // 4 times per second only ----------------------------------------------------------------------
    {
        LastTime = Time;

        // render LiminanceBuffer texture -------------------------------------------------------------------------------------

        glBindFramebuffer(GL_FRAMEBUFFER, FBO);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, LuminanceBuffer, 0);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
        glBindTexture(GL_TEXTURE_2D, HDRColorBuffer);
        glUseProgram(Luminance);
        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);
        glBindFramebuffer(GL_FRAMEBUFFER, 0);

        int i = 0, x = Width, y = Height;
        float odx = 1.0f / (float)x, ody = 1.0f / (float)y;

        // downscale LuminanceBuffer texture to less than 32x32 pixels --------------------------------------------------------

        do
        {
            x /= 2;
            y /= 2;

            glViewport(0, 0, x, y);

            glBindFramebuffer(GL_FRAMEBUFFER, FBO);
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, MinificationBuffer[i], 0);
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
            glBindTexture(GL_TEXTURE_2D, i == 0 ? LuminanceBuffer : MinificationBuffer[i - 1]);
            glUseProgram(Minification);
            glUniform1f(Luminance.UniformLocations[0], odx);
            glUniform1f(Luminance.UniformLocations[1], ody);
            glBegin(GL_QUADS);
                glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0f, 0.0f);
                glTexCoord2f(1.0f - odx, 0.0f); glVertex2f(1.0f, 0.0f);
                glTexCoord2f(1.0f - odx, 1.0f - ody); glVertex2f(1.0f, 1.0f);
                glTexCoord2f(0.0f, 1.0f - ody); glVertex2f(0.0f, 1.0f);
            glEnd();
            glUseProgram(0);
            glBindFramebuffer(GL_FRAMEBUFFER, 0);

            odx = 1.0f / (float)x;
            ody = 1.0f / (float)y;

            i++;
        }
        while(x > 32 || y > 32);

        glViewport(0, 0, Width, Height);

        // read downscaled LuminanceBuffer texture data -----------------------------------------------------------------------

        glBindTexture(GL_TEXTURE_2D, MinificationBuffer[i - 1]);
        glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, data);
        glBindTexture(GL_TEXTURE_2D, 0);

        // get the maximal luminance value ------------------------------------------------------------------------------------

        maxrgbvalue = 0.0f;

        for(int p = 0; p < x * y * 4; p += 4)
        {
            maxrgbvalue = max(maxrgbvalue, data[p]);
        }

        if(maxrgbvalue < 1.0) maxrgbvalue = 1.0;

        if(maxrgbvalue != oldmaxrgbvalue) mrgbvi = abs(maxrgbvalue - MaxRGBValue);

        oldmaxrgbvalue = maxrgbvalue;
    }

    if(MaxRGBValue < maxrgbvalue) { MaxRGBValue += mrgbvi * FrameTime; if(MaxRGBValue > maxrgbvalue) MaxRGBValue = maxrgbvalue; }
    if(MaxRGBValue > maxrgbvalue) { MaxRGBValue -= mrgbvi * FrameTime; if(MaxRGBValue < maxrgbvalue) MaxRGBValue = maxrgbvalue; }

    // render HDRColorBuffer texture to LDRColorBuffer texture with tone mapping shader applied -------------------------------

    glBindFramebuffer(GL_FRAMEBUFFER, FBO);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, LDRColorBuffer, 0);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
    glBindTexture(GL_TEXTURE_2D, HDRColorBuffer);
    glUseProgram(ToneMapping);
    glUniform1f(ToneMapping.UniformLocations[0], MaxRGBValue);
    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);
    glBindTexture(GL_TEXTURE_2D, 0);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    // render BrightPixelsBuffer texture --------------------------------------------------------------------------------------

    glBindFramebuffer(GL_FRAMEBUFFER, FBO);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, BrightPixelsBuffer, 0);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
    glBindTexture(GL_TEXTURE_2D, LDRColorBuffer);
    glUseProgram(BrightPixels);
    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);
    glBindTexture(GL_TEXTURE_2D, 0);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    // downscale and blur BrightPixelsBuffer texture 4x -----------------------------------------------------------------------

    for(int i = 0; i < 4; i++)
    {
        int ds = 2 * (i + 1);

        // set viewport to 1/ds of the screen ----------------------------------------------------------------------------------

        glViewport(0, 0, Width / ds, Height / ds);

        // downscale ----------------------------------------------------------------------------------------------------------

        glBindFramebuffer(GL_FRAMEBUFFER, FBO);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, BloomBuffer[i*3+0], 0);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, BrightPixelsBuffer);
        glColor3f(1.0f, 1.0f, 1.0f);
        glBegin(GL_QUADS);
            glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0f, 0.0f);
            glTexCoord2f(1.0f, 0.0f); glVertex2f(1.0f, 0.0f);
            glTexCoord2f(1.0f, 1.0f); glVertex2f(1.0f, 1.0f);
            glTexCoord2f(0.0f, 1.0f); glVertex2f(0.0f, 1.0f);
        glEnd();
        glBindTexture(GL_TEXTURE_2D, 0);
        glDisable(GL_TEXTURE_2D);
        glBindFramebuffer(GL_FRAMEBUFFER, 0);

        // horizontal blur ----------------------------------------------------------------------------------------------------

        glBindFramebuffer(GL_FRAMEBUFFER, FBO);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, BloomBuffer[i*3+1], 0);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
        glBindTexture(GL_TEXTURE_2D, BloomBuffer[i*3+0]);
        glUseProgram(BlurH);
        glUniform1f(BlurH.UniformLocations[1], 1.0f / (float)(Width / ds));
        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);
        glBindTexture(GL_TEXTURE_2D, 0);
        glBindFramebuffer(GL_FRAMEBUFFER, 0);

        // vertical blur ------------------------------------------------------------------------------------------------------

        glBindFramebuffer(GL_FRAMEBUFFER, FBO);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, BloomBuffer[i*3+2], 0);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
        glBindTexture(GL_TEXTURE_2D, BloomBuffer[i*3+1]);
        glUseProgram(BlurV);
        glUniform1f(BlurH.UniformLocations[1], 1.0f / (float)(Height / ds));
        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);
        glBindTexture(GL_TEXTURE_2D, 0);
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }

    // display LDRColorBuffer texture ----------------------------------------------------------------------------------------

    glViewport(0, 0, Width, Height);

    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, LDRColorBuffer);
    glColor3f(1.0f, 1.0f, 1.0f);
    glBegin(GL_QUADS);
        glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0f, 0.0f);
        glTexCoord2f(1.0f, 0.0f); glVertex2f(1.0f, 0.0f);
        glTexCoord2f(1.0f, 1.0f); glVertex2f(1.0f, 1.0f);
        glTexCoord2f(0.0f, 1.0f); glVertex2f(0.0f, 1.0f);
    glEnd();
    glBindTexture(GL_TEXTURE_2D, 0);
    glDisable(GL_TEXTURE_2D);

    // blend 4 downscaled and blurred BrightPixelsBuffer textures over the screen ---------------------------------------------

    for(int i = 0; i < 4; i++)
    {
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, BloomBuffer[(3-i)*3+2]);
        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
        glEnable(GL_BLEND);
        glColor3f(1.0f, 1.0f, 1.0f);
        glBegin(GL_QUADS);
            glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0f, 0.0f);
            glTexCoord2f(1.0f, 0.0f); glVertex2f(1.0f, 0.0f);
            glTexCoord2f(1.0f, 1.0f); glVertex2f(1.0f, 1.0f);
            glTexCoord2f(0.0f, 1.0f); glVertex2f(0.0f, 1.0f);
        glEnd();
        glDisable(GL_BLEND);
        glBindTexture(GL_TEXTURE_2D, 0);
        glDisable(GL_TEXTURE_2D);
    }

    // end --------------------------------------------------------------------------------------------------------------------

    Text.Set("I: %.02f, MRGBV: %.03f", Intensity, MaxRGBValue);
}

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

    Projection = PerspectiveProjectionMatrix(45.0f, (float)Width, (float)Height, 0.125f, 512.0f);

    glBindTexture(GL_TEXTURE_2D, HDRColorBuffer);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, Width, Height, 0, GL_RGBA, GL_FLOAT, NULL);

    glBindTexture(GL_TEXTURE_2D, DepthBuffer);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, Width, Height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);

    glBindTexture(GL_TEXTURE_2D, LuminanceBuffer);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, Width, Height, 0, GL_RGBA, GL_FLOAT, NULL);

    int i = 0, x = Width, y = Height;

    do
    {
        x /= 2;
        y /= 2;

        glBindTexture(GL_TEXTURE_2D, MinificationBuffer[i]);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, x, y, 0, GL_RGBA, GL_FLOAT, NULL);

        i++;
    }
    while(x > 32 || y > 32);

    glBindTexture(GL_TEXTURE_2D, LDRColorBuffer);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

    glBindTexture(GL_TEXTURE_2D, BrightPixelsBuffer);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, Width, Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

    for(int i = 0; i < 4; i++)
    {
        int ds = 2 * (i + 1);

        for(int ii = 0; ii < 3; ii++)
        {
            glBindTexture(GL_TEXTURE_2D, BloomBuffer[3*i+ii]);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            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 / ds, Height / ds, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
        }
    }
}

void COpenGLRenderer::Destroy()
{
    delete [] data;

    Kocka.Delete();
    Podlaha.Delete();

    glDeleteTextures(1, &HDRColorBuffer);
    glDeleteTextures(1, &DepthBuffer);
    glDeleteTextures(1, &LuminanceBuffer);
    glDeleteTextures(8, MinificationBuffer);
    glDeleteTextures(1, &LDRColorBuffer);
    glDeleteTextures(1, &BrightPixelsBuffer);
    glDeleteTextures(12, BloomBuffer);

    if(gl_version >= 21)
    {
        PerPixelLighting.Delete();
        Luminance.Delete();
        Minification.Delete();
        ToneMapping.Delete();
        BrightPixels.Delete();
        BlurH.Delete();
        BlurV.Delete();
    }

    if(GLEW_ARB_framebuffer_object)
    {
        glDeleteFramebuffers(1, &FBO);
    }
}

...
per_pixel_lighting.vs
#version 120

uniform vec3 CameraPosition;

varying vec3 LD, Normal, LDR, EV;

void main()
{
    LD = gl_LightSource[0].position.xyz - gl_Vertex.xyz;
    Normal = gl_Normal;
    LDR = reflect(-LD, Normal);
    EV = CameraPosition - gl_Vertex.xyz;
    gl_TexCoord[0] = gl_MultiTexCoord0;
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
per_pixel_lighting.fs
#version 120

uniform sampler2D Texture;

varying vec3 LD, Normal, EV, LDR;

void main()
{
    vec3 LDN = normalize(LD);
    vec3 NormalN = normalize(Normal);
    vec3 LDRN = normalize(LDR);
    vec3 EVN = normalize(EV);
    float NdotLD = max(dot(NormalN, LDN), 0.0);
    float EVdotLDR = pow(max(dot(EVN, LDRN), 0.0), 32.0);
    vec3 Color = texture2D(Texture, gl_TexCoord[0].st).rgb * (gl_LightSource[0].ambient.rgb + gl_LightSource[0].diffuse.rgb * (NdotLD + EVdotLDR));
    gl_FragColor = vec4(Color, 1.0);
}
luminance.vs
#version 120

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

uniform sampler2D HDRColorBuffer;

void main()
{
    vec3 Color = texture2D(HDRColorBuffer, gl_TexCoord[0].st).rgb;
    
    float MaxRGBValue = max(Color.r, max(Color.g, Color.b));
    
    gl_FragColor = vec4(MaxRGBValue, 0.0, 0.0, 0.0);
}
minification.vs
#version 120

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

uniform sampler2D LuminanceBuffer;

uniform float odx, ody;

void main()
{
    float a = texture2D(LuminanceBuffer, gl_TexCoord[0].st + vec2(0.0, 0.0)).r;
    float b = texture2D(LuminanceBuffer, gl_TexCoord[0].st + vec2(odx, 0.0)).r;
    float c = texture2D(LuminanceBuffer, gl_TexCoord[0].st + vec2(odx, ody)).r;
    float d = texture2D(LuminanceBuffer, gl_TexCoord[0].st + vec2(0.0, ody)).r;
    
    float maxlum = max(max(a, b), max(c, d));
    
    gl_FragColor = vec4(maxlum, 0.0, 0.0, 0.0);
}
tone_mapping.vs
#version 120

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

uniform sampler2D HDRColorBuffer;
uniform float MaxRGBValue;

void main()
{
    vec3 Color = texture2D(HDRColorBuffer, gl_TexCoord[0].st).rgb;
    
    gl_FragColor = vec4(Color / MaxRGBValue, 1.0);
}
bright_pixels.vs
#version 120

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

uniform sampler2D LDRColorBuffer;

void main()
{
    vec3 Color = texture2D(LDRColorBuffer, gl_TexCoord[0].st).rgb;
    
    float MaxRGBValue = max(Color.r, max(Color.g, Color.b));
    
    if(MaxRGBValue > 0.90)
    {
        gl_FragColor = vec4(Color, 1.0);
    }
}
blur.vs
#version 120

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

uniform sampler2D Texture;
uniform int Width;
uniform float odw;

void main()
{
    vec3 Color = vec3(0.0);
    int wp1 = Width + 1;
    float Sum = 0.0;
    
    for(int x = -Width; x <= Width; x++)
    {
        float width = (wp1 - abs(float(x)));
        Color += texture2D(Texture, gl_TexCoord[0].st + vec2(odw * x, 0.0)).rgb * width;
        Sum += width;
    }
    
    gl_FragColor = vec4(Color / Sum, 1.0);
}
blurv.fs
#version 120

uniform sampler2D Texture;
uniform int Width;
uniform float odh;

void main()
{
    vec3 Color = vec3(0.0);
    int wp1 = Width + 1;
    float Sum = 0.0;
    
    for(int y = -Width; y <= Width; y++)
    {
        float width = (wp1 - abs(float(y)));
        Color += texture2D(Texture, gl_TexCoord[0].st + vec2(0.0, odh * y)).rgb * width;
        Sum += width;
    }
    
    gl_FragColor = vec4(Color / Sum, 1.0);
}
Download
high_dynamic_range_bloom.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.