Basic Lighting in OpenGL and SDL Game Programming

Lighting is one of the components of a game that can provide an immersive reality to the player — or be so distracting that playing becomes difficult. To ease working with lighting, OpenGL provides simplified API. The focus of this discussion will be on the basics of using lighting API provided by OpenGL. This article is the latest part in a multi-part series on game programming with OpenGL and SDL.

The first section will be about the whys and wherefores of lighting. The second and third sections will focus on using the basic lighting API in a game. The last section will delve into an application that will make use of the concepts and API introduced in the first two sections. That is the outline for this discussion.

Lighting in OpenGL: The Whys and Wherefores

Similar to all other aspects of a game, lighting has a close relationship with the mechanics of illumination in real world. Hence, the first step in understanding how lighting works in OpenGL, and in any given game, is to know how lighting works in real life. One has to know the types of lighting or illumination one encounters in day-to-day life.

The lighting encountered in the real world can be broadly categorized into ambient light, diffuse light, and specular light. The categorization is based upon the direction of the source of light. Here are the details:

Ambient Light

When the direction of light cannot be determined, giving an illusion that the light is coming from all directions, such a light or illumination is known as ambient light or ambient illumination. The reason for the illusion is the scattering of the light by the environment. Examples of ambient light are sunlight, the overhead lighting of a room, and so forth.

The backlighting of a room also has a large component of ambient light. The reason for this is that the light is bounced off many surfaces before it reaches one’s eyes, thus seemingly coming from all directions. One of the main aspects of ambient light is that when it comes in contact with any surface, it is scattered in all directions equally.

Diffuse Light

When the light comes from a particular direction, it provides diffuse illumination. Since it comes from one direction, if it hits a surface squarely, it is brighter; if it just touches the surface, the illumination will be less. However, once the light hits the surface, it is scattered equally in all directions. Due to this, a diffuse light appears bright from whichever angle it is seen.

Specular Light

When a light comes from a particular direction, strikes a surface and bounces off in a preferred direction, such a light or illumination is known as specular light or specular illumination. In other words, light reflecting off the surface of smooth material is specular. The shininess of an object can be related to the specularity. One thing to keep in mind about specular light is that its angle of incidence is the same as that of its angle of reflection.

Now that the types of lighting have been discussed, let us move onto the steps required to implement basic lighting in OpenGL.

{mospagebreak title=Implementing Lighting, Step by Step}

In order to use the lighting API in OpenGL, certain steps need to be followed. These steps change according to the requirements. The requirements can include material, colors etc. However, for this discussion, the focus is on simple lighting, so the steps we will discuss are rudimentary. One point to keep in mind, however, is that the rudimentary steps remain unchanged even if the requirements change. Without further delay, here are the required steps:

1. Enable lighting.

2. Define normal vectors for each vertex.

3. Create one or more light sources.

4. Choosing a lighting model.

Of these, the third and fourth steps have multiple sub-steps. Here are the details.

Enable lighting

OpenGL can be compared to a state machine. Using that analogy, lighting is also one of its states. Hence, lighting needs to be enabled. To enable lighting, the glEnable() function needs to be called with GL_LIGHTING as the parameter. Before performing any other operation regarding illumination, lighting should be enabled. In code the statement will be

glEnable(GL_LIGHTING);


Define normal vectors for each vertex

It is necessary to define and determine the orientation of light with respect to an object, normal to the vertices of the object. OpenGL does not do normal vector calculations automatically. The calculation of normal vectors will be covered in the future.

The calculated normal vectors need to be passed to OpenGL. To do so, any variation of glNormal function can be used. However, if no normal vectors are passed, then OpenGL takes (0, 0, 0, 0) as the normal vector.

Create one or more light sources

Creating one or more light sources can be sub-divided into the following two steps:

1.  Defining a light source: In OpenGL one can define up to eight light sources. The names of these light sources are of the format GL_LIGHTn where n stands for numbers from 0 to 7. To define a light source, variants of glLight*() are used. Basically, it takes the light source number, the type of light and the values that will control the light (especially the color). The color is defined as RGBA i.e. Red, Green, Blue and the Alpha. For example, to define a light source with the source number as 0, the type as specular and the value as an array of floats, the statements will be

GLfloat specular[] = {1.0f, 1.0f, 1.0f , 1.0f};

glLightfv(GL_LIGHT0, GL_SPECULAR, specular); 

2.  Enabling the light source: The next step is to enable the light source that has just been defined. To do so, one needs to use glEnable and pass the light source number as a parameter. By default, all of the light sources are disabled. Passing the light source number to glEnable(), enables the light source. For example, the following statement enables the light source that has 0 as its number:

glEnable(GL_LIGHT0); 

{mospagebreak title=Lighting Model}

The final step is to choose a lighting model. The lighting model determines two things. First, it determines whether the user is viewing the scene from an infinite distance or locally. If the user is considered to be viewing from an infinite distance, the angle of light and that of the viewer is ignored. The result
will be unrealistic lighting. Secondly, the lighting model determines whether or not the front and back surface calculations for an object need to be done separately.

To choose a lighting model, the glLightModel*() method is used. This method, or command as it is known in OpenGL, is used to set the amount of global ambient light that will be cast on the objects on the scene.

One of the variants of glLightModel*() is glLightModelfv(). It takes a parameter telling OpenGL that global ambient light needs to be set, and the array defining the color of global ambient light. For example, to set the global ambient light with the color having values of 0.5f, 0.5f, 0.5f and 1.0f, the statements will be:

Glfloat global_ambient[] = {0.5f, 0.5f, 0.5f, 1.0f};

glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);

That completes the steps necessary for implementing basic lighting in an application or game. In the next section, basic lighting will be added to the existing framework.

{mospagebreak title=Lighting in the Real World}

The modifications to the framework will provide lighting to the framework. The changes need to be done in the following function:

CreateWindowGL – Here the code for initializing the lighting and defining the light source will be added.

Let us get started. The following is the existing code:

bool CreateWindowGL(int W, int H, int B, Uint32 F)

// This Code Creates Our OpenGL Window

{

SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );

// In order to use SDL_OPENGLBLIT we have to

SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );

// set GL attributes first

SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );

SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );

SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );

// colors and double buffering


if(!(Screen = SDL_SetVideoMode(W, H, B, F)))

// SDL_SetVideoMode to create the window

{

return false; // if it fails, return false

}


SDL_FillRect(Screen, NULL, SDL_MapRGBA(Screen->format,0,0,0,0));

ReshapeGL(SCREEN_W, SCREEN_H);

// calling reshape as the window is created

return true; // return true (initialization successful)

}


In the above code, we will add the statements to initialize and define the lighting and light source.


bool CreateWindowGL(int W, int H, int B, Uint32 F)

// This Code Creates Our OpenGL Window

{

SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );

// In order to use SDL_OPENGLBLIT we have to

SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );

// set GL attributes first

SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );

SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );

SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );// colors and double

//buffering

glEnable(GL_LIGHTING);//enable lighting

GLfloat specular[] = {1.0f, 1.0f, 1.0f , 1.0f};

glLightfv(GL_LIGHT0, GL_SPECULAR, specular); //create a light source

glEnable(GL_LIGHT0); //enable the light source

Glfloat global_ambient[] = {0.5f, 0.5f, 0.5f, 1.0f};

glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);//set the
//global lighting model



if(!(Screen = SDL_SetVideoMode(W, H, B, F)))

// SDL_SetVideoMode to create the window

{

return false; // if it fails, return false

}


SDL_FillRect(Screen, NULL, SDL_MapRGBA(Screen->format,0,0,0,0));

 

ReshapeGL(SCREEN_W, SCREEN_H);

// calling reshape as the window is created

return true; // return true (initialization successful)

}


That’s it. That completes implementing code for adding basic lighting. However, this discussion has left some questions open. These questions include the effect of lighting on material, how the rotation of an object will affect the lighting, and so forth. These will be topic of discussion in the next part. Till then…

[gp-comments width="770" linklove="off" ]

chat sex hikayeleri Ensest hikaye