Light emitters are objects that create light in the scene. Usually they produce direct lighting and most of them support shadows.
Incoming light usually consists of zero or more point lights at some position with some attenuation radius and color. Surface points outside the attenuation radius are not affected by the light and within the radius the light is usually faded out linearly. The linear falloff curve is popular because it is less harsh than the realistic behavior and for that reason easier to control. This is a crude approximation as a point light falloff would be 1/distance and there is no zero decay at some distance. Real lights are no points, they have some size (area light) which affects the shadow penumbra and the specular (where the specular is actually the reflection of the light source).
In simple per pixel lighting each light is rendered in a separate pass resulting in one draw call for each material of a render mesh. We optimized that by using an übershader which can combine up to four light sources in one pass. This is more efficient but introduces some other complications. In general, the system scales badly with many small lights in an environment with many objects.
Since CryENGINE 3 we have deferred lighting, a feature which can handle many more lights efficiently. The idea is to store all properties for lighting in some off-screen buffer (normal, specular power factor, depth for deriving position) and perform the lighting calculations independently from the geometry only for the visible pixels. The cost of the lighting is now almost independent of the geometry complexity.
Partly based on the deferred lighting we implemented irradiance lighting that allows to approximate even more lights with very little performance cost. However, those lights cannot handle shadows and have other limitations.
Shadows for point lights are made by splitting up the spherical shape into six (we experimented with more) frustums that we handle separately with some unified shadow mapping code.
The sun is often approximated by a colored directional light without distance attenuation. This works well on a small area far away from the sun.
Sun shadows are implemented by splitting up the view frustum into multiple parts that we handle separately with some unified shadow mapping code (Cascaded Shadow Maps). Additionally, we use Variance Shadow Maps for the more blurry shadows from the terrain.
Image Based Lighting
The concept of Image Based Lighting (IBL) brings some advantages but has limitations as well, so it is beneficial to know about its properties and combine different methods where useful. IBL allows to render very complex lighting situation, usually with an infinitely distant environment map (on GPU's this is usually a cubemap). Hard specular reflections are simple as a single texture lookup in the mirrored eye direction gives the lighting in that direction. Blurry reflections can be approximated efficiently by adjusting the mip level on the lookup. Diffuse lighting can be done efficiently with a single lookup in the normal direction into a pre-convoluted environment map.
- High quality.
- Fast for many lights and even a complex environment is reflected.
- Energy preserving specular power.
- Works only well for local positions with distant emitters and reflection content.
- Static content only.
We extended the classical cubemap IBL and thanks to the deferred lighting, we can blend between local environment maps (we call them light probes). Even a single global light probe already helps to improve the lighting as the classical flat ambient is replaced by something that is direction dependent and shows some specular material behavior.
One Color for Specular and Diffuse
In a pure mathematical model the light diffuse and specular contribution can be colored differently without problems. This can be useful in some cases (yellow sun for the specular, red for the diffuse as the nearby sky is reddish) but it might prevent some optimizations and can cause more problems. We usually try to have a light color and a multiplier to quickly scale the effect/contribution of the light (good range: 0.1 .. 16) and another multiplier on top of that to reduce the specular (good range: 0 .. 1, exceptionally higher than 1). The specular multiplier allows to tweak between extremely diffuse lighting (e.g. 0 for foggy non specular lighting) and ordinary harder lighting (e.g. 1 for bright day light).
- Recommended reading for IBL: http://ati.amd.com/developer/SIGGRAPH05/Isidoro-CubeMapFiltering.pdf