Generating the skybox textures may require a little more effort because each texture must seamlessly align with the four other textures it shares an edge with. If you are artistically inclined, you may be able to draw or paint these textures, but it is probably easier to use 3D modeling software to render six views of a scene for each face of the skybox. An excellent choice for rendering skyboxes is Terragen (www.planetside.co.uk/terragen/), which creates remarkably realistic-looking images of virtual landscapes. I used Terragen to create the skycube textures in Figure 12-3 that we will be using in the skybox sample code.
Rendering the skybox should be the first thing done in a new frame, and negates the need to clear the color buffer (although you will still need to clear the depth buffer).
Since a skybox is just a model of a cube, it can be stored as any other model, but there are a few additional steps required prior to rendering:
1. Set the wrap mode of all the textures in the skybox to GL_CLAMP_TO_EDGE. This is necessary to avoid seams in the skybox, where the cube faces meet. See the previous chapter for more information on wrapping modes. This step needs to be done only once.
2. Set the position of the skybox to be the same as the camera (i.e., the player). This is because the skybox represents very distant scenery that can never be reached by the player.
3. Disable lighting with glDisable(GL_LIGHTING). We don't need to use OpenGL's lighting features because the textures of the skybox have effectively been prelit. With lighting disabled, OpenGL will render the textures with the original brightness levels.
4. Disable the depth buffer with glDepthMask(False). Normally if the player was inside a cube he would not be able to see anything outside of the cube, which is obviously not want we want. Setting the depth mask to False with glDepthMask(False) tells OpenGL to ignore the depth information in the skybox, so that other models will be rendered on top of it.
Once the skybox has been rendered, be sure to reenable lighting and the depth mask, or the other models in the scene may not render correctly. The following two lines should follow the call to render the skybox:
Let's write code to render a skybox. Listing 12-6 uses the Model3D class from the previous chapter to load a skybox model and its associated textures. When you run it, you will see a scenic view of mountains, and if you adjust the viewpoint with the mouse you will be able to see the landscape from any direction.
Listing 12-6. Rendering a Skybox (skybox.py) SCREEN_SIZE = (800, 600)
from OpenGL.GL import * from OpenGL.GLU import *
import pygame from pygame.locals import *
# Import the Model3D class import model3d def resize(width, height):
glViewport(0, 0, width, height)
gluPerspective(60.0, float(width)/height, .1, 1000.)
# Enable the GL features we will be using glEnable(GL_LIGHTING) glEnable(GL_DEPTH_TEST) glEnable(GL_LIGHTING) glEnable(GL_TEXTURE_2D) glShadeModel(GL_SMOOTH)
# Enable light 1 and set position glEnable(GL_LIGHT0)
screen = pygame.display.set_mode(SCREEN_SIZE, FULLSCREEN | HWSURFACE | ^ OPENGL | DOUBLEBUF)
# Read the skybox model sky_box = model3d.Model3D()
# Set the wraping mode of all textures in the skybox to GL_CLAMP_TO_EDGE for material in sky_box.materials.itervalues():
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
# Used to rotate the world mouse_x = 0.0 mouse_y = 0.0
#Don't display the mouse cursor pygame.mouse.set_visible(False)
for event in pygame.event.get(): if event.type == QUIT: return if event.type == KEYDOWN: return
# We don't need to clear the color buffer (GL_COLOR_BUFFER_BIT)
# because the skybox covers the entire screen glClear(GL_DEPTH_BUFFER_BIT)
mouse_rel_x, mouse_rel_y = pygame.mouse.get_rel() mouse_x += float(mouse_rel_x) / 5.0 mouse_y += float(mouse_rel_y) / 5.0
# Rotate around the x and y axes to create a mouse-look camera glRotatef(mouse_y, 1, 0, 0)
# Disable lighting and depth test glDisable(GL_LIGHTING) glDepthMask(False)
# Draw the skybox sky_box.draw_quick()
# Reenable lighting and depth test before we redraw the world glEnable(GL_LIGHTING)
# Here is where we would draw the rest of the world in a game pygame.display.flip()
Although a skybox creates a convincing illusion of distance scenery, there are enhancements that can be used to add some more visual flare to the backdrop. One of the downsides of the skybox technique is that it doesn't change over time because the image has been prerendered. Animating parts of the skybox, or adding atmospheric effects on top of it, can add a little extra realism. For example, making the sun shimmer a little or rendering lightning in the distance can enhance a skybox. It is also possible to layer translucent skyboxes and animate one or more of them. For instance, there could be a skybox for distant mountains and another for clouds. Rotating the cloud skybox independently would create realistic-looking weather effects.
Skyboxes aren't the only method of rendering a backdrop in a game; a skydome is a similar technique that uses a sphere, or hemisphere, to display distant scenery. A dome may be a more obvious choice than a cube because the real sky is spherical in nature, but a sphere is not quite as easy to texture as a cube. A cylinder is another alternative, if the player will never look directly up.
Was this article helpful?