create your own solar system

Genesis is a simulator software to easily create his own celestial system.

Technical stack

OpenGL + GLSL + C++ with Visual Studio

Step 1: OpenGL and SDL context implementation

How did I have OpenGL work with SDL ? Easy: SDL gets an OpenGL context. So the architecture basis of my program is SDL with OpenGL display functions inside.

Step 2 : shader

My desire to increase the visual effects of my programs encouraged me to cross over the shader road. That's why I concentrated my efforts in this space simulator software. The shader using in OpenGL is named GLSL.

Shader allows to configure the graphic card pipeline to change the way to display images to screen: shape and mesh display, light ray, etc... In GLSL, it exists two kinds of shader: pixel shader (named also fragment shader) and vertex shader. To sum up: vertex shader affects the vertex on a shape whereas pixel shader affects each pixel on a shape. Both are needed to have a shader work: if one is missing; that can't work. The assembly of a vertex and pixel shader is named "program". If you want to learn more about the way to use it, go to: Shaders and GLSL.

Tips

  • A singularity in shader using is that the shader program is not compiled at the same time your OpenGL program is. Shader program is compiled when the OpenGL program is launched. So I had to implement by myself the shader loading and compilation in the OpenGL program.
  •  The shader using is easy too because you just need to activate or not the shader program when you need it. If the shader is not activated, OpenGL uses the usual pipelines.
  • Finally, the shader coding is not disturbing: 4 lines can be enough to get good effects. However, you'll need good mathematic, logical and physical skills.

The hardness can be the way you have implemented your OpenGL program! Actually, the more your OpenGL program is complex (light ray, z-buffer, etc...), the more your shader will be involve in it. In the video above, I have used shaders for buttons apparition and solar effect (fire and magma).

Tips

  • A Uniform variable (variable used to give information to shader) not initialized generates an error.
  • It is impossible to use shader for a single part of what is displayed: If you want to affect an object color with shader, you'll need to configure texture and light parts too. Otherwise, it will be not displayed. Using texture in shader is easily done. Light need to well understand the light working in OpenGL in reality and the graphic card.
  • Using OpenGL shader is really helpful when you want to reduce processor computing times, because it is the graphic card which works. This asset become a drawback if your card graphics isn't efficient or when your OpenGL version is too old. I had this kind of problems with my card. As I couldn't find any help with official Ati drivers, I used this one: driver ATI radeon mobility and my problem was resolved.
  • If you want to do multi-texturing with shader, you need to use Uniform variables. If you know how to use GLSL, you'll remember that linkUniformVariableGLint() is used to send integer variable to shader. Thanks to it, you can send texture identifier to shader.

However, at the beginning, you had to link textures to shader program: U = glGetUniformLocationARB(ShaderProgramName, varUniform) with:

  • U: an integer used by OpenGL program
  • ShaderProgramName: the shader program
  • varUniform: the uniform variable in the shader

Then, you can send several textures to shader this way:

//Activate the OpenGL texture number 0.
glActiveTexture(GL_TEXTURE0);

//The texture id A is link to the OpenGL texture number 0.
glBindTexture(GL_TEXTURE_2D,A);

//Activate the OpenGL texture number 1
glActiveTexture(GL_TEXTURE1);

//The texture id B is link to the OpenGL texture number 1.
glBindTexture(GL_TEXTURE_2D,B);

//Activate the shader named shader.
_shader.active();

//Send the texture link to the OpenGL texture number 0, to the uniform variable U1.
glUniform1iARB(TexA, 0);

//Send the texture link to the OpenGL texture number 1, to the uniform variable U2.
glUniform1iARB(TexB, 1);

For example, this lines above work with this code in you shader:

uniform sampler2D texA;
uniform sampler2D texB;
texture2D(texA,gl_TexCoord[0].st);
texture2D(texB,gl_TexCoord[1].st);

To help people beginning to use shader, I share these simple shaders I used in Genesis:

Damien Leroux Genesis Magma

Damien Leroux Genesis UI Apparition Progressive

Damien Leroux Genesis UI Full2

Damien Leroux Genesis Rotation

Step 3 : skybox

Damien Leroux Genesis Skybox2

To display space around planets, I used a skybox. Using it can be easy with OpenGL extension. As OpenGL extensions are not always available (depending of your graphic card), Glew can easily verify if the extension you want is existing. Besides, the skybox is named in OpenGL: GL_TEXTURE_CUBE_MAP_ARB. It is a cube within the camera centered. I created by myself the space textures. If you need its, go to: space texture for skybox

Step 4 : texture

For texturing the planets and the star (Sun, as you want), I used jpeg images. Thanks to SDL, I could load images and thanks to OpenGL, I converted these images to textures.

Step 5 : camera

In order to be able to move inside our system, I used a trackball. This one reacts according to mouse and scrolling movements.

  • I have adapted my trackball to cross over space if I targeted a star, a planet or a satellite. This targeting is programmed to fix the planet or star that is the referent of the targeted planet. For example, if click on Earth, the sun is fixed in space or if I click on Moon, the Earth is fixed.
  • When I change the camera target, there is a smooth transition from point A to point B: it is a linear interpolation (lerp). That means: coordonnatesA x (1-t) + coordonnatesB x (t) = Current position (t: 0 to 1).

If you need to know how use texture, go to: my first solar system - step 5

Step 6: lights

Damien Leroux Genesis Light

Lighting is displayed to simulate light from the star. This light had to be deactivated on any elements like sun or the menu. This link may help you if you want learn how to do: openGL light

Step 7: Mouse picking

The mouse picking requires two different processes: the first one is used to recognize OpenGL 3D shapes: such as star (sphere). The second one is used to know if a 2D texture on the shape is under the mouse or not. For example, this can be really useful to detect a quad without detect transparent pixels on it.

  • On one hand, to recognize shapes, I displayed the OpenGL area to let OpenGL register in a stack, shapes under mouse cursor. This display mustn't appear on the screen. Once this stack is completed, I can get the shape with the lower depth. It is substantial to unable texture, color and light processes because the drawing is just used for the picking and is not displayed. Moreover, using texture, color and light processes  twice for each frame could widely reduced frame rate (FPS). after finishing the picking process, I drew all shapes yet. This time, I add texture and light and display it on the screen. If you need to learn how to do that, go to:openGL mouse picking.
  • On the other hand, to recognize specific form on a texture, the mouse picking is manually handled. For example, if I want my cursor to recognize a round faced to camera, I compare the difference between the round center and the cursor with the round radius.

Step 8: UI creation

Damien Leroux Genesis UI

The menu implementation is cut in two classes: one for menus, another one for buttons. Buttons get specifics shapes and meanings while menus gathers buttons. In the video example, I draw button thanks shaders. Each button gets a state: "appeared", "disappeared", "focused", "clicked", "appearing" or "disappearing". A button can change:

  • It own state: for example, when I focus the button: the buttons state is "focused".
  • Other buttons states. For example, if I click on it, other buttons can be stated: "appearing". The appearing state allows a smooth display when the button just has to appear.
  • Any variable, according to the button goal, as creating a new planet.

Step 9: celestial body creating

I created a superclass named CELESTIALBODY and several subclass: PLANET or STAR. A celestial body gets: name, position, trajectory, identifier, shape, size, colors, textures, creation date, life time and chemical components. A planet is a celestial body with an atmosphere and may be life.A star is a celestial body with light radiations. Creating a planet means saving new data and generating new comportments. In the video, I simplified the name edition with a random system. The planet size is randomly chosen too. The planet speed depends on it size and it distance from the star. When a planet is created, I can choose it trajectory and its chemical components.

To set the celestial body components:

Damien Leroux Genesis UI Full3

The chemical components are used to color the future planet. it could have been used for ather thing: wieght, size, attraction , etc...

To set trajectory, 3 steps are needed:

Choose the referent celestial body of the new planet:

Damien Leroux Genesis Planet

Choose where position the planet:

Damien Leroux Genesis Skybox

Choose the planet incline and planet direction:

Damien Leroux Genesis Universe

Step 10: draw text

It can be complicated. Even if SDL, thanks to it text library TTF, allowed text display, it wouldn't work with the OpenGL context. So, in order to display text, I had to:

  • Generate a SDL_surface with the text I wanted.
  • Fix this one to an OpenGL quad.

Here is how it works:

//Goal: create an OpenGL id with texture created from text.
//name is the text I want
//font is the font I need
//color is the text color

GLuint load_name(const char * name,TTF_Font *font, SDL_Color color){
//SDL surface taking text
    SDL_Surface* gl_fliped_surface=NULL;
    GLuint glID=0; //the result id.
    // I load text on surface.
    if((gl_fliped_surface=TTF_RenderText_Blended(font, name, color)) !=NULL) {
        //I generate a integer for the texture named glID
        glGenTextures(1, &glID);
        //I specify which texture used for next operations.
        glBindTexture(GL_TEXTURE_2D, glID);
        //I create the OpenGL texture thanks to the SDL surface
        glTexImage2D(GL_TEXTURE_2D, 0, 4, gl_fliped_surface->w, gl_fliped_surface->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, gl_fliped_surface->pixels);
        //the texture display settings
        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_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        //free surface
        SDL_FreeSurface(gl_fliped_surface);
    }
    return glID;
}

How to use it:

//the quad size to display text
GLfloat textSize[2]; 
//I active 2D OpenGL processes for texture.
glEnable(GL_TEXTURE_2D); 
//_texte is the glId I load thanks to the previous function.
glBindTexture(GL_TEXTURE_2D,_texte); 
glBegin(GL_QUADS);
glTexCoord2d(1,0);
glVertex3f(0, textSize[1],-textSize[0]);
glTexCoord2d(0,0);
glVertex3f(0, textSize[1], textSize[0]);
glTexCoord2d(0,1);
glVertex3f(0,-textSize[1], textSize[0]);
glTexCoord2d(1,1);
glVertex3f(0,-textSize[1],-textSize[0]);
glEnd();

glDisable(GL_TEXTURE_2D);

Final Result

Damien Leroux Genesis

Damien Leroux Genesis UI Full1

Download Genesis