3D C/C++ tutorials - OpenGL 2.1 - Planet Earth from space
3D C/C++ tutorials -> OpenGL 2.1 -> Planet Earth from space
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 EarthMap, CloudsMap;//, LightsMap;
    CShaderProgram gfs, gfa, sfs, sfa;
    GLuint VerticesVBO, TexCoordsVBO, VerticesCount;
    float InnerRadius, OuterRadius;

public:
    ...
};

...
opengl_21_tutorials_win32_framework.cpp
...

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

COpenGLRenderer::~COpenGLRenderer()
{
}

bool COpenGLRenderer::Init()
{
    bool Error = false;

    Error |= !EarthMap.LoadTexture2D("earthmap.jpg");
    Error |= !CloudsMap.LoadTexture2D("cloudsmap.jpg");
    //Error |= !LightsMap.LoadTexture2D("lightsmap.jpg");

    Error |= !gfs.Load("groundfromspace.vs", "groundfromspace.fs");
    Error |= !gfa.Load("groundfromatmosphere.vs", "groundfromatmosphere.fs");
    Error |= !sfs.Load("skyfromspace.vs", "skyfromspace.fs");
    Error |= !sfa.Load("skyfromatmosphere.vs", "skyfromatmosphere.fs");

    if(Error)
    {
        return false;
    }

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

    GLuint programs[] = {gfs, gfa, sfs, sfa};

    for(int i = 0; i < 4; i++)
    {
        glUseProgram(programs[i]);
        glUniform3f(glGetUniformLocation(programs[i], "v3LightPos"), 0.0f, 0.0f, 1.0f);
        glUniform3f(glGetUniformLocation(programs[i], "v3InvWavelength"), 1.0f / powf(0.650f, 4.0f), 1.0f / powf(0.570f, 4.0f), 1.0f / powf(0.475f, 4.0f));
        glUniform1f(glGetUniformLocation(programs[i], "fInnerRadius"), InnerRadius);
        glUniform1f(glGetUniformLocation(programs[i], "fInnerRadius2"), InnerRadius * InnerRadius);
        glUniform1f(glGetUniformLocation(programs[i], "fOuterRadius"), OuterRadius);
        glUniform1f(glGetUniformLocation(programs[i], "fOuterRadius2"), OuterRadius * OuterRadius);
        glUniform1f(glGetUniformLocation(programs[i], "fKrESun"), Kr * ESun);
        glUniform1f(glGetUniformLocation(programs[i], "fKmESun"), Km * ESun);
        glUniform1f(glGetUniformLocation(programs[i], "fKr4PI"), Kr * 4.0f * (float)M_PI);
        glUniform1f(glGetUniformLocation(programs[i], "fKm4PI"), Km * 4.0f * (float)M_PI);
        glUniform1f(glGetUniformLocation(programs[i], "fScale"), Scale);
        glUniform1f(glGetUniformLocation(programs[i], "fScaleDepth"), ScaleDepth);
        glUniform1f(glGetUniformLocation(programs[i], "fScaleOverScaleDepth"), ScaleOverScaleDepth);
        glUniform1f(glGetUniformLocation(programs[i], "g"), g);
        glUniform1f(glGetUniformLocation(programs[i], "g2"), g * g);
        glUniform1i(glGetUniformLocation(programs[i], "Samples"), 4);
        glUniform1i(glGetUniformLocation(programs[i], "s2Tex1"), 0);
        glUniform1i(glGetUniformLocation(programs[i], "s2Tex2"), 1);
        //glUniform1i(glGetUniformLocation(programs[i], "s2Tex3"), 2);
        glUseProgram(0);
    }

    int X = 128, Y = X / 2, vpos = 0, tpos = 0;
    float a, stepa = (float)M_PI * 2.0f / (float)X, stepb = (float)M_PI / (float)Y, b = -(float)M_PI_2 + stepb;

    vec3 *vertices = new vec3[X * (Y - 1)];

    for(int y = 0; y < (Y - 1); y++)
    {
        a = -(float)M_PI;

        for(int x = 0; x < X; x++)
        {
            vertices[y * X + x] = normalize(vec3(sin(a) * cos(b), sin(b), cos(a) * cos(b)));
            a += stepa;
        }

        b += stepb;
    }

    VerticesCount = (X * (Y - 2) * 2 + X * 2) * 3;

    vec3 *Vertices = new vec3[VerticesCount];
    vec2 *TexCoords = new vec2[VerticesCount];

    for(int x = 0; x < X; x++)
    {
        Vertices[vpos++] = vec3(0.0f, -1.0f, 0.0f);
        Vertices[vpos++] = vertices[(0 + 0) * X + ((x + 1) % X)];
        Vertices[vpos++] = vertices[(0 + 0) * X + ((x + 0) % X)];

        TexCoords[tpos++] = vec2((float)(x + 0.5f) / (float)X, 0.0f);
        TexCoords[tpos++] = vec2((float)(x + 1) / (float)X, (float)(0 + 1) / (float)Y);
        TexCoords[tpos++] = vec2((float)(x + 0) / (float)X, (float)(0 + 1) / (float)Y);
    }

    for(int y = 0; y < Y - 2; y++)
    {
        for(int x = 0; x < X; x++)
        {
            Vertices[vpos++] = vertices[(y + 0) * X + ((x + 0) % X)];
            Vertices[vpos++] = vertices[(y + 0) * X + ((x + 1) % X)];
            Vertices[vpos++] = vertices[(y + 1) * X + ((x + 1) % X)];

            TexCoords[tpos++] = vec2((float)(x + 0) / (float)X, (float)(1 + y + 0) / (float)Y);
            TexCoords[tpos++] = vec2((float)(x + 1) / (float)X, (float)(1 + y + 0) / (float)Y);
            TexCoords[tpos++] = vec2((float)(x + 1) / (float)X, (float)(1 + y + 1) / (float)Y);

            Vertices[vpos++] = vertices[(y + 1) * X + ((x + 1) % X)];
            Vertices[vpos++] = vertices[(y + 1) * X + ((x + 0) % X)];
            Vertices[vpos++] = vertices[(y + 0) * X + ((x + 0) % X)];

            TexCoords[tpos++] = vec2((float)(x + 1) / (float)X, float(1 + y + 1) / (float)Y);
            TexCoords[tpos++] = vec2((float)(x + 0) / (float)X, float(1 + y + 1) / (float)Y);
            TexCoords[tpos++] = vec2((float)(x + 0) / (float)X, float(1 + y + 0) / (float)Y);
        }
    }

    for(int x = 0; x < X; x++)
    {
        Vertices[vpos++] = vertices[(Y - 2) * X + ((x + 0) % X)];
        Vertices[vpos++] = vertices[(Y - 2) * X + ((x + 1) % X)];
        Vertices[vpos++] = vec3(0.0f, 1.0f, 0.0f);

        TexCoords[tpos++] = vec2((float)(x + 0) / (float)X, (float)(Y - 1) / (float)Y);
        TexCoords[tpos++] = vec2((float)(x + 1) / (float)X, (float)(Y - 1) / (float)Y);
        TexCoords[tpos++] = vec2((float)(x + 0.5f) / (float)X, 1.0f);
    }

    glGenBuffers(1, &VerticesVBO);
    glBindBuffer(GL_ARRAY_BUFFER, VerticesVBO);
    glBufferData(GL_ARRAY_BUFFER, VerticesCount * 3 * 4, Vertices, GL_STATIC_DRAW);

    glGenBuffers(1, &TexCoordsVBO);
    glBindBuffer(GL_ARRAY_BUFFER, TexCoordsVBO);
    glBufferData(GL_ARRAY_BUFFER, VerticesCount * 2 * 4, TexCoords, GL_STATIC_DRAW);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    delete [] vertices;
    delete [] Vertices;
    delete [] TexCoords;

    Camera.Look(vec3(0.0f, 0.0f, 768.0f), vec3(0.0f, 0.0f, 0.0f), InnerRadius);

    return true;
}

void COpenGLRenderer::Render(float FrameTime)
{
    static float a = 0.0f;

    float ainc = 0.25f * FrameTime;

    a += ainc;

    if(length(Camera.Position) < OuterRadius * 1.1f)
    {
        vec3 Y = vec3(0.0f, 1.0f, 0.0f);

        Camera.Position = rotate(Camera.Position, ainc, Y);

        Camera.X = rotate(Camera.X, ainc, Y);
        Camera.Y = rotate(Camera.Y, ainc, Y);
        Camera.Z = rotate(Camera.Z, ainc, Y);

        Camera.CalculateViewMatrix();
    }
    
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);

    GLuint program;

    glMatrixMode(GL_MODELVIEW);
    glLoadMatrixf(&ViewMatrix);
    glScalef(InnerRadius, InnerRadius, InnerRadius);
    glRotatef(a, 0.0f, 1.0f, 0.0f);

    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();
    glScalef(InnerRadius, InnerRadius, InnerRadius);
    glRotatef(a, 0.0f, 1.0f, 0.0f);

    glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, EarthMap);
    glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, CloudsMap);
    //glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, LightsMap);

    if(length(Camera.Position) > OuterRadius) program = gfs;
    else program = gfa;

    glUseProgram(program);
    glUniform3fv(glGetUniformLocation(program, "v3CameraPos"), 1, &Camera.Position);
    glUniform1f(glGetUniformLocation(program, "fCameraHeight"), length(Camera.Position));
    glUniform1f(glGetUniformLocation(program, "fCameraHeight2"), length(Camera.Position) * length(Camera.Position));

    glEnableClientState(GL_VERTEX_ARRAY);
    glBindBuffer(GL_ARRAY_BUFFER, VerticesVBO);
    glVertexPointer(3, GL_FLOAT, 0, NULL);

    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glBindBuffer(GL_ARRAY_BUFFER, TexCoordsVBO);
    glTexCoordPointer(2, GL_FLOAT, 0, NULL);

    glDrawArrays(GL_TRIANGLES, 0, VerticesCount);

    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);

    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);

    glMatrixMode(GL_MODELVIEW);
    glLoadMatrixf(&ViewMatrix);
    glScalef(OuterRadius, OuterRadius, OuterRadius);

    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();
    glScalef(OuterRadius, OuterRadius, OuterRadius);

    if(length(Camera.Position) > OuterRadius) program = sfs;
    else program = sfa;

    //glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    //glEnable(GL_BLEND);

    glCullFace(GL_FRONT);

    glUseProgram(program);
    glUniform3fv(glGetUniformLocation(program, "v3CameraPos"), 1, &Camera.Position);
    glUniform1f(glGetUniformLocation(program, "fCameraHeight"), length(Camera.Position));
    glUniform1f(glGetUniformLocation(program, "fCameraHeight2"), length(Camera.Position) * length(Camera.Position));

    glEnableClientState(GL_VERTEX_ARRAY);
    glBindBuffer(GL_ARRAY_BUFFER, VerticesVBO);
    glVertexPointer(3, GL_FLOAT, 0, NULL);

    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glBindBuffer(GL_ARRAY_BUFFER, TexCoordsVBO);
    glTexCoordPointer(2, GL_FLOAT, 0, NULL);

    glDrawArrays(GL_TRIANGLES, 0, VerticesCount);

    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);
    
    glUseProgram(0);

    glCullFace(GL_BACK);

    glDisable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);
}

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, 4096.0f);

    glMatrixMode(GL_PROJECTION);
    glLoadMatrixf(&ProjectionMatrix);
}

void COpenGLRenderer::Destroy()
{
    EarthMap.Destroy();
    CloudsMap.Destroy();
    //LightsMap.Destroy();

    glDeleteBuffers(1, &VerticesVBO);
    glDeleteBuffers(1, &TexCoordsVBO);

    gfs.Destroy();
    gfa.Destroy();
    sfs.Destroy();
    sfa.Destroy();
}

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