Lighting in Games

Setting the right atmosphere and mood is important in any type of game. From Myst-like puzzles to real time strategy to first person shooters, lighting plays a huge role in how players interact with a game’s world are impacted by it. Mysterious and horror games meant to keep players on the edge of their seats usually have darker environments, punctuated by brighter areas and objects to ensure you notice them. Other genres tend to use more balanced lighting systems, and games that are praised for their appearance masterfully paint their worlds onto our screens, the environments telling stories of their own. Lighting is a topic which merits an in-depth study all on its own; most artists spend years mastering the subtleties of light and color. This article will introduce you to the key concepts of light in computer graphics and how to use it effectively.

Many different considerations go into lighting of any kind, be it for games, movies, or even in well-architected buildings. Every AAA game I have read the credits for has had at least one lighting director; these people make sure every inch of graphics look their best and contribute to the story. Think about this for a moment – there are people whose primary job is studying how things look and tweaking environments to get the best possible result.

Big games have lighting directors is because light is a complicated topic, both in the real world and in computer graphics. In reality, light travels from its source and is reflected, scattered, and/or refracted for every surface it encounters. Realistic modeling of light in simulations is called ray tracing and can generate very lifelike images by casting rays into the scene to calculate physically-correct lighting. Ray tracing’s downside is that it cannot run in real time on today’s hardware. In fact, a single ray traced frame can take hours to render, although some implementations for games can achieve frame rates up to 20FPS (Intel’s Quake Wars: Ray Traced and nVidia’s OptiX).

Instead of sending millions of rays into a scene, most games use a method where each object is individually sent to the GPU where it is mapped into 3D space and rendered. Creating refractions or reflections can be difficult when using this method because models do not have information about any of the objects around them. Games have been using this technique for decades and graphics cards provide dedicated pipelines for drawing objects this way.

There are a few standard ways to calculate how light illuminates a surface, and while there are numerous variations within each method, we’ll look at the most common configurations. The first of these is a very simple model known as Lambert lighting, named after Johann Lambert who described the idea behind it in 1760. Objects lit in this way are called Lambertian and emit light evenly across all viewing angles. This means that different points on an object will look the same no matter what angle they are viewed from. Thus, the Lambert model is used to render objects which have only diffuse lighting, where there is no glossiness or reflections.

To be able to calculate the lighting at a point on an object we need to know a few things about the light and the object. First we need to know the position of point on the object relative to the light source, which is found by light_position - point_position. Second, we need to know the normal vector of the object where we are performing the calculation, which tells which direction the surface is facing. Once we have this information Lambert lighting is very easy and intuitive to calculate. Simply put, surfaces directly facing the light are fully lit and the amount of lighting falls off linearly as the normals turn perpendicular to the light. To determine if two vectors, such as the surface normal and the light direction, are in the same direction we need to find the angle between them. This is very simple to calculate and the result is called the dot product of the two vectors. First we normalize both vectors so each one has a unit length of one, then the dot product can be calculated as Ax*Bx + Ay*By + Az*Bz. The dot product of any two normalized vectors will be a value between -1.0 and 1.0, where 1.0 means the vectors are pointing in the same direction, 0.0 indicates they are perpendicular, and when the dot product is `-1.0’ the vectors are pointing in opposite directions. This result fits perfectly when calculating Lambert light where we want to know the relation between the light direction and the surface’s normal vector.