Light Setting in OpenGL

Introduction: 

Have you ever tried to set lights for your 3D objects? To me, light setting is a hard topic; I spend time doing small increments of codes and debugging to try to understand the light effects. When there is a need for creating multiple light sources, things get complicated. Lights are interestingly blended to create wanted and unwanted effects. A solid understanding of basic light setting is helpful for any graphic designer. Otherwise, the 3D objects just look like 2D boring blobs of colored shapes. 

Visual effects of different light sources and light components

Figure1 shows us a scene with a small yellow light shining on a cube. From the picture, we notice that a light source needs to have a location, and involved light components are ambient and diffuse [1]. Also, we realize that when only ambient and diffuse features are used, the surface of the object looks dull.

Figure 1: Ambient /Diffuse light source.
Source: Adapted from https://www.just.edu.jo/~yaser/courses/cs480/Tutorials [1]

In contrast, an object looks shiny when its surface reflects most of the incoming light. In order to create a shiny object, a specular light component is added. Specular color determines the color of the highlight(GL_SPECULAR). In addition, users need to determine how shiny a surface is (GL_SHININESS). Figure 2 shows specular color changes from the same color to white from bottom to the top. Also, shininess is increasing from left to right (5, 25, 45,65,85). 

In OpenGL, to enable or disable lighting, users need to call glEnable(GL_LIGHTING) or glDisable(GL_LIGHTING). When lighting is enabled, colors that are specified by glColor*() will become invalid. Light position is set using GL_POSITION. Light components are set using GL_AMBIENT, GL_DIFFUSE

Figure 2: specular and shiny settings decide shininess of the object.
Source: http://cgkit.sourceforge.net/tutorials/materials.html [2]

Per-vertex lighting vs. per-face lighting:

Like the name might suggest, for per-vertex lighting, users need to define a normal vector using glNormal3f(x,y,z) at each vertex. Similarly, for per-face lighting, normal vectors are defined at each face of the object. If it is desired to have a lit smooth surface, per-vertex should be used. If it is desired to have a flat surface, per-face should be used. The smaller the face and the larger the number of vertices, the better the object will look when it is lit. 

In OpenGL, glShadeModel(GL_FLAT) is used when using per-face lighting and glShadeModel(GL_SMOOTH) is used when applying per-vertex lighting. Also, we need to enable normalization by using glEnable(GL_NORMALIZE).

Alpha blending and transparency

Alpha value is the 4th component of a color (rgba); it determines the opacity of an object when it is used with blend factors GL_SRC_ALPHA and GL_ONE_MINUS_SRC_ALPHA. With alpha blending, the output pixel is a weighted sum of the existing pixel and newly calculated pixel.

Figure 3: Alpha Blending and transparency feature.
Source: http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-10-transparency/ [3]

Difference light sources: directional light, pointlight, and spotlight 

Figure 4 shows us some important features of different light sources. Directional light creates parallel light rays because the light position is very far away (infinite). As a result, it doesn’t matter any more how each object in world space relates to the light source. While the point light equally radiates in all directions, the spotlight is focused and forms a cone shape.

Figure 4: Characteristics of different light sources. Source: https://gdbooks.gitbooks.io/legacyopengl/content/Chapter5/light_spotlight.html [4]

Spotlights’ features

Although point light and spot light have different light effects, setting those lights are pretty much the same, except that in spotlight, some spotlight’s specifications are added: GL_SPOT_DIRECTION, GL_SPOT_EXPONENT, and GL_SPOT_CUTOFF

By default, GL_SPOT_DIRECTION points towards the negative z axis (0,0,-1).

GL_SPOT_EXPONENT ranges from 0 to 128. By default, its value is 0, which means there is no light attenuation as the spotlight spreads toward the side edges of the cone. In other words, the cone of light is evenly distributed. 

GL_SPOT_CUTOFF determines how wide the light cone is. It specifies the angle between the cone’s axis and the cone’s edge. It ranges from 0 to 90 degrees.

Figure 5: Spotlight settings and meaning. Source: [4]

Two-sided light vs. one-sided light: 

Light can be performed for all faces: front-faces (GL_FRONT) or back faces (GL_BACK). To disable this two-sided light, use GL_FALSE instead of GL_TRUE in the following function: 

glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);

Local viewpoint vs. infinite viewpoint:

By default, the viewpoint is infinite; the direction between light source and any vertex in the scene is constant. In contrast, for the local viewpoint, direction from the light source to each vertex is taken into account. As a result, the local viewpoint seems to be more realistic. The following function sets the local viewpoint at (0,0,0). To choose an infinite viewpoint, use the GL_FALSE. 

glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);

Static lights vs. perspective lights vs. dynamic lights

Static lights will never move. To set static light, light is positioned after setting the camera (after the call to gluLookAt() and before performing matrix transformation. 

Perspective light, in contrast, will relatively fix with the camera position. For example, headlights are perspective lights when a passenger is sitting in the car and the car is moving. The headlight in this case will relatively fix relative to the passengers’ eyes. To have a perspective light effect, Light should be defined after setting the modelview matrix to identity matrix and before calling gluLookAt(). 

For dynamic light, the light will move as the object moves. Light transformation in this case is done after the object transformation. Push and pop matrices are also used in this case. A useful example that I find is shown below (figure 6).

Figure 6: Example of dynamic light setting for Mr. Roboto. Source: https://gdbooks.gitbooks.io/legacyopengl/content/Chapter5/move_and_rotate.html[6]

Conclusion:

We have discussed some basic background of lights: light sources, light models in OpenGL, and light interactions. Hopefully, this could benefit learners when implementing multiple lights in a program. Proper light setting brings “soul” to the scene and object. Through clever light usage, lights bring valuable meanings and engage viewers into the scene. 

Reference 

[1] Jérôme Jouvie. Tutorial8-1: Light [Part I]. [Online]. Available: https://www.just.edu.jo/~yaser/courses/cs480/Tutorials/OpenGl%20-%20Tutorial8-1%20Light%20Part%20I.htm. Accessed Oct 13th, 2021.

[2] cgkit. Materials: How to change the visual appearance of your objects. [Online]. Available: http://cgkit.sourceforge.net/tutorials/materials.html. Accessed Oct 13th, 2021.

[3] openGL_tutorial. Tutorial 10: Transparency. [Online]. Available: http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-10-transparency/. Accessed Oct 13th, 2021.

[4]LegacyOpenGL. Spotlights. [Online]. Available: https://gdbooks.gitbooks.io/legacyopengl/content/Chapter5/light_spotlight.html. Accessed Oct 13th, 2021.

[5] LegacyOpenGL. Moving and rotating. [Online]. Available: https://gdbooks.gitbooks.io/legacyopengl/content/Chapter5/move_and_rotate.html. Accessed Oct 13th, 2021.

Print Friendly, PDF & Email

Leave a comment

Your email address will not be published. Required fields are marked *