3D C/C++ tutorials - OpenGL 2.1 - Atmospheric light scattering
3D C/C++ tutorials -> OpenGL 2.1 -> Atmospheric light scattering
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
...

class COpenGLRenderer
{
protected:
    ...

protected:
    CTexture Texture, DirtTexture;
    CShaderProgram Sky, SunDepthTest, BlurH, BlurV, SunRaysLensFlareHalo;
    GLuint /*ScreenTexture,*/ DepthTexture, SunTextures[4], FBO, VBO;
    int SunTextureWidth, SunTextureHeight;

public:
    bool Pause;
    float SunR;
    vec3 SunCPos, SunRotVec;

public:
    ...
};

...
opengl_21_tutorials_win32_framework.cpp
...

COpenGLRenderer::COpenGLRenderer()
{
    Pause = false;
    SunR = 15.0f;
    SunRotVec = normalize(vec3(0.0f, -0.66f, -1.0f));
    SunCPos = rotate(vec3(-512.0f, 0.0f, 0.0f), -22.5f, SunRotVec);

    Camera.SetViewMatrixPointer(&ViewMatrix);
}

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("GL_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;
    }

    Error |= !Texture.LoadTexture2D("texture.jpg");
    Error |= !DirtTexture.LoadTexture2D("lensdirt_lowc.jpg");

    Error |= !Sky.Load("skyfromatmosphere.vs", "skyfromatmosphere.fs");
    Error |= !SunDepthTest.Load("sundepthtest.vs", "sundepthtest.fs");
    Error |= !BlurH.Load("blur.vs", "blurh.fs");
    Error |= !BlurV.Load("blur.vs", "blurv.fs");
    Error |= !SunRaysLensFlareHalo.Load("sunrayslensflarehalo.vs", "sunrayslensflarehalo.fs");

    if(Error)
    {
        return false;
    }

    glUseProgram(SunDepthTest);
    glUniform1i(glGetUniformLocation(SunDepthTest, "SunTexture"), 0);
    glUniform1i(glGetUniformLocation(SunDepthTest, "DepthTexture"), 1);
    glUseProgram(0);

    glUseProgram(SunRaysLensFlareHalo);
    glUniform1i(glGetUniformLocation(SunRaysLensFlareHalo, "LowBlurredSunTexture"), 0);
    glUniform1i(glGetUniformLocation(SunRaysLensFlareHalo, "HighBlurredSunTexture"), 1);
    glUniform1i(glGetUniformLocation(SunRaysLensFlareHalo, "DirtTexture"), 2);
    glUniform1f(glGetUniformLocation(SunRaysLensFlareHalo, "Dispersal"), 0.1875f);
    glUniform1f(glGetUniformLocation(SunRaysLensFlareHalo, "HaloWidth"), 0.45f);
    glUniform1f(glGetUniformLocation(SunRaysLensFlareHalo, "Intensity"), 2.25f);
    glUniform3f(glGetUniformLocation(SunRaysLensFlareHalo, "Distortion"), 0.94f, 0.97f, 1.00f);
    glUseProgram(0);

    float Kr = 0.0030f;
    float Km = 0.0015f;
    float ESun = 16.0f;
    float g = -0.75f;
    float InnerRadius = 10.0f;
    float OuterRadius = 10.25f;
    float Scale = 1.0f / (OuterRadius - InnerRadius);
    float ScaleDepth = 0.25f;
    float ScaleOverScaleDepth = Scale / ScaleDepth;

    glUseProgram(Sky);
    glUniform3f(glGetUniformLocation(Sky, "v3CameraPos"), 0.0f, InnerRadius, 0.0f);
    glUniform3f(glGetUniformLocation(Sky, "v3InvWavelength"), 1.0f / powf(0.650f, 4.0f), 1.0f / powf(0.570f, 4.0f), 1.0f / powf(0.475f, 4.0f));
    glUniform1f(glGetUniformLocation(Sky, "fCameraHeight"), InnerRadius);
    glUniform1f(glGetUniformLocation(Sky, "fCameraHeight2"), InnerRadius * InnerRadius);
    glUniform1f(glGetUniformLocation(Sky, "fInnerRadius"), InnerRadius);
    glUniform1f(glGetUniformLocation(Sky, "fInnerRadius2"), InnerRadius * InnerRadius);
    glUniform1f(glGetUniformLocation(Sky, "fOuterRadius"), OuterRadius);
    glUniform1f(glGetUniformLocation(Sky, "fOuterRadius2"), OuterRadius * OuterRadius);
    glUniform1f(glGetUniformLocation(Sky, "fKrESun"), Kr * ESun);
    glUniform1f(glGetUniformLocation(Sky, "fKmESun"), Km * ESun);
    glUniform1f(glGetUniformLocation(Sky, "fKr4PI"), Kr * 4.0f * (float)M_PI);
    glUniform1f(glGetUniformLocation(Sky, "fKm4PI"), Km * 4.0f * (float)M_PI);
    glUniform1f(glGetUniformLocation(Sky, "fScale"), Scale);
    glUniform1f(glGetUniformLocation(Sky, "fScaleDepth"), ScaleDepth);
    glUniform1f(glGetUniformLocation(Sky, "fScaleOverScaleDepth"), ScaleOverScaleDepth);
    glUniform1f(glGetUniformLocation(Sky, "g"), g);
    glUniform1f(glGetUniformLocation(Sky, "g2"), g * g);
    glUniform1i(glGetUniformLocation(Sky, "Samples"), 4);
    glUseProgram(0);

    vec3 *SkyDomeVertices = new vec3[112 * 3], va, vb, vc, vd;

    float stepa = (float)M_PI * 2.0f / 16, startb = asin(InnerRadius / OuterRadius), stepb = ((float)M_PI_2 - startb) / 4;
    int pos = 0;

    for(int y = 0; y < 3; y++)
    {
        float b = startb + stepb * y;

        for(int x = 0; x < 16; x++)
        {
            float a = stepa * x;

            va = vec3(sin(a) * cos(b) * OuterRadius, sin(b) * OuterRadius, -cos(a) * cos(b) * OuterRadius);
            vb = vec3(sin(a + stepa) * cos(b) * OuterRadius, sin(b) * OuterRadius, -cos(a + stepa) * cos(b) * OuterRadius);
            vc = vec3(sin(a + stepa) * cos(b + stepb) * OuterRadius, sin(b + stepb) * OuterRadius, -cos(a + stepa) * cos(b + stepb) * OuterRadius);
            vd = vec3(sin(a) * cos(b + stepb) * OuterRadius, sin(b + stepb) * OuterRadius, -cos(a) * cos(b + stepb) * OuterRadius);

            SkyDomeVertices[pos + 0] = va;
            SkyDomeVertices[pos + 1] = vb;
            SkyDomeVertices[pos + 2] = vc;

            pos += 3;

            SkyDomeVertices[pos + 0] = vc;
            SkyDomeVertices[pos + 1] = vd;
            SkyDomeVertices[pos + 2] = va;

            pos += 3;
        }
    }

    float b = startb + stepb * 3;

    for(int x = 0; x < 16; x++)
    {
        float a = stepa * x;

        va = vec3(sin(a) * cos(b) * OuterRadius, sin(b) * OuterRadius, -cos(a) * cos(b) * OuterRadius);
        vb = vec3(sin(a + stepa) * cos(b) * OuterRadius, sin(b) * OuterRadius, -cos(a + stepa) * cos(b) * OuterRadius);
        vc = vec3(0, OuterRadius, 0);

        SkyDomeVertices[pos + 0] = va;
        SkyDomeVertices[pos + 1] = vb;
        SkyDomeVertices[pos + 2] = vc;

        pos += 3;
    }

    glGenBuffers(1, &VBO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, 112 * 3 * 3 * sizeof(float), SkyDomeVertices, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    delete [] SkyDomeVertices;

    //glGenTextures(1, &ScreenTexture);
    glGenTextures(1, &DepthTexture);
    glGenTextures(4, SunTextures);

    glGenFramebuffersEXT(1, &FBO);

    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, &vec4(vec3(0.0f), 1.0f));
    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, &vec4(1.0f));
    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, &vec4(1.0f));

    glEnable(GL_LIGHT0);
    glEnable(GL_COLOR_MATERIAL);

    Camera.Look(vec3(10.0f, 1.75f, 0.0f), vec3(-512.0f, 0.0f, 0.0f), false);

    return true;
}

void COpenGLRenderer::Render(float FrameTime)
{
    // calculate sun direction, position and color

    vec3 SunCDir = normalize(SunCPos);
    vec3 SunWPos = Camera.Position + SunCPos;
    float RefractionFactor = (1.0f - sqrt(max(0.0f, SunCDir.y)));
    vec3 SunColor = 1.0f - vec3(0.0f, 0.5f, 1.0f) * RefractionFactor;

    // calculate ambient and diffuse light color

    vec3 LightColor = 1.0f - vec3(0.0f, 0.25f, 0.5f) * RefractionFactor;
    float AmbientIntensity = 0.0625f + 0.1875f * min(1.0f, max(0.0f, (0.375f + SunCDir.y) / 0.25f));
    float DiffuseIntensity = 0.75f * min(1.0f, max(0.0f, (0.03125f + SunCDir.y) / 0.0625f));

    glViewport(0, 0, Width, Height);
    
    //glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBO);
    //glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, ScreenTexture, 0);
    //glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, DepthTexture, 0);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_PROJECTION);
    glLoadMatrixf(&ProjectionMatrix);

    // render sky

    glMatrixMode(GL_MODELVIEW);
    glLoadMatrixf(&ViewMatrix);

    glTranslatef(Camera.Position.x, Camera.Position.y - 10.0f /*InnerRadius*/, Camera.Position.z);

    glEnableClientState(GL_VERTEX_ARRAY);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glVertexPointer(3, GL_FLOAT, 0, NULL);
    glUseProgram(Sky);
    glUniform3fv(glGetUniformLocation(Sky, "v3LightPos"), 1, &SunCDir);
    glDrawArrays(GL_TRIANGLES, 0, 112 * 3);
    glUseProgram(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glDisableClientState(GL_VERTEX_ARRAY);

    // render scene

    glMatrixMode(GL_MODELVIEW);
    glLoadMatrixf(&ViewMatrix);

    glLightfv(GL_LIGHT0, GL_AMBIENT, &vec4(vec3(AmbientIntensity), 1.0f));
    glLightfv(GL_LIGHT0, GL_DIFFUSE, &vec4(LightColor * DiffuseIntensity, 1.0f));
    glLightfv(GL_LIGHT0, GL_POSITION, &vec4(SunWPos, 1.0f));

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
    glEnable(GL_LIGHTING);

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

    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, Texture);
    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();
    glDisable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, 0);

    glBegin(GL_QUADS);
        glNormal3f( 0.0f,  1.0f,  0.0f);
        glVertex3f(-4.0f, -0.5f,  4.0f);
        glVertex3f( 4.0f, -0.5f,  4.0f);
        glVertex3f( 4.0f, -0.5f, -4.0f);
        glVertex3f(-4.0f, -0.5f, -4.0f);
    glEnd();

    GLUquadric *obj = gluNewQuadric();

    for(int z = -2; z <= 2; z += 1)
    {
        for(int x = -2; x <= 2; x += 1)
        {
            glMatrixMode(GL_MODELVIEW);
            glLoadMatrixf(&ViewMatrix);
            glTranslatef((float)x, -0.25f, (float)z);
            gluSphere(obj, 0.25f, 32, 32);
        }
    }

    gluDeleteQuadric(obj);

    glDisable(GL_LIGHTING);
    glDisable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);

    // copy depth buffer to texture

    glBindTexture(GL_TEXTURE_2D, DepthTexture);
    glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, Width, Height);
    glBindTexture(GL_TEXTURE_2D, 0);

    //glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

    // test if sun is inside camera frustum

    bool CalculateSunRaysLensFlareHalo = false;
    int Test = 0, Tests = 16;
    float Angle = 0.0f, AngleInc = 360.0f / Tests;

    mat4x4 VPB = BiasMatrix * ProjectionMatrix * ViewMatrix;

    while(Test < Tests && !CalculateSunRaysLensFlareHalo)
    {
        vec3 SunWEdge = SunWPos + rotate(Camera.X, Angle, Camera.Z) * SunR;

        if(SunWEdge.y - Camera.Position.y > 0.0f)
        {
            vec4 SunPosProj = VPB * vec4(SunWEdge, 1.0f);
            SunPosProj /= SunPosProj.w;

            CalculateSunRaysLensFlareHalo |= (SunPosProj.x >= 0.0f && SunPosProj.x <= 1.0f && SunPosProj.y >= 0.0f && SunPosProj.y <= 1.0f && SunPosProj.z >= 0.0f && SunPosProj.z <= 1.0f);
        }

        Angle += AngleInc;
        Test++;
    }

    // if it is then calculate lens flare

    if(CalculateSunRaysLensFlareHalo)
    {
        vec4 SunPosProj = VPB * vec4(SunWPos, 1.0f);
        SunPosProj /= SunPosProj.w;

        glViewport(0, 0, SunTextureWidth, SunTextureHeight);

        // render sun sphere

        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBO);
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, SunTextures[1], 0);
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0);

        glClear(GL_COLOR_BUFFER_BIT);

        glMatrixMode(GL_MODELVIEW);
        glLoadMatrixf(&ViewMatrix);
        double pl[] = {0.0f, 1.0f, 0.0f, -Camera.Position.y};
        glClipPlane(GL_CLIP_PLANE0, pl);
        glEnable(GL_CLIP_PLANE0);
        glTranslatef(SunWPos.x, SunWPos.y, SunWPos.z);
        glColor3fv(&SunColor);
        glEnable(GL_CULL_FACE);
        GLUquadric *obj = gluNewQuadric();
        gluSphere(obj, SunR, 16, 16);
        gluDeleteQuadric(obj);
        glDisable(GL_CULL_FACE);
        glDisable(GL_CLIP_PLANE0);

        // test if sun sphere is behind scene geometry

        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBO);
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, SunTextures[0], 0);
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0);

        glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, SunTextures[1]);
        glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, DepthTexture);
        glUseProgram(SunDepthTest);
        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);

        // blur sun sphere horizontally (low)

        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBO);
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, SunTextures[3], 0);
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0);

        glBindTexture(GL_TEXTURE_2D, SunTextures[0]);
        glUseProgram(BlurH);
        glUniform1i(glGetUniformLocation(BlurH, "Width"), 1);
        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);

        // blur sun sphere vertically (low)

        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBO);
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, SunTextures[1], 0);
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0);

        glBindTexture(GL_TEXTURE_2D, SunTextures[3]);
        glUseProgram(BlurV);
        glUniform1i(glGetUniformLocation(BlurV, "Width"), 1);
        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);

        // blur sun sphere horizontally (high)

        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBO);
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, SunTextures[3], 0);
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0);

        glBindTexture(GL_TEXTURE_2D, SunTextures[0]);
        glUseProgram(BlurH);
        glUniform1i(glGetUniformLocation(BlurH, "Width"), 10);
        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);

        // blur sun sphere vertically (high)

        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBO);
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, SunTextures[2], 0);
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0);

        glBindTexture(GL_TEXTURE_2D, SunTextures[3]);
        glUseProgram(BlurV);
        glUniform1i(glGetUniformLocation(BlurV, "Width"), 10);
        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);

        // blur sun sphere radially and calculate lens flare and halo and apply dirt texture

        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBO);
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, SunTextures[3], 0);
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0);

        glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, SunTextures[1]);
        glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, SunTextures[2]);
        glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, DirtTexture);
        glUseProgram(SunRaysLensFlareHalo);
        glUniform2fv(glGetUniformLocation(SunRaysLensFlareHalo, "SunPosProj"), 1, &SunPosProj);
        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);

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

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

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    /*glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, ScreenTexture);
    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 sun texture over the screen

    if(CalculateSunRaysLensFlareHalo)
    {
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, SunTextures[3]);
        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);
    }

    // move sun

    if(!Pause)
    {
        SunCPos = rotate(SunCPos, 0.25f * FrameTime, SunRotVec);
    }
}

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

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

    /*glBindTexture(GL_TEXTURE_2D, ScreenTexture);
    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);
    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, DepthTexture);
    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);
    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);

    SunTextureWidth = Width / 2;
    SunTextureHeight = Height / 2;

    for(int i = 0; i < 4 ;i++)
    {
        glBindTexture(GL_TEXTURE_2D, SunTextures[i]);
        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_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, SunTextureWidth, SunTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
        glBindTexture(GL_TEXTURE_2D, 0);
    }

    glUseProgram(BlurH);
    glUniform1f(glGetUniformLocation(BlurH, "odw"), 1.0f / (float)SunTextureWidth);
    glUseProgram(BlurV);
    glUniform1f(glGetUniformLocation(BlurV, "odh"), 1.0f / (float)SunTextureHeight);
    glUseProgram(0);
}

void COpenGLRenderer::Destroy()
{
    Texture.Destroy();
    DirtTexture.Destroy();

    //glDeleteTextures(1, &ScreenTexture);
    glDeleteTextures(1, &DepthTexture);
    glDeleteTextures(4, SunTextures);

    Sky.Destroy();
    SunDepthTest.Destroy();
    BlurH.Destroy();
    BlurV.Destroy();
    SunRaysLensFlareHalo.Destroy();

    glDeleteBuffers(1, &VBO);

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

...

void COpenGLView::OnKeyDown(UINT Key)
{
    switch(Key)
    {
        case VK_ADD:
            OpenGLRenderer.SunCPos = rotate(OpenGLRenderer.SunCPos, OpenGLRenderer.SunRotVec, + M_PI / 180.0f);
            break;

        case VK_SUBTRACT:
            OpenGLRenderer.SunCPos = rotate(OpenGLRenderer.SunCPos, OpenGLRenderer.SunRotVec, - M_PI / 180.0f);
            break;

        case VK_SPACE:
            OpenGLRenderer.Stop = !OpenGLRenderer.Stop;
            break;
    }
}

...
Download
atmospheric_light_scattering.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.