The Lighting Engine

The engine uses static light sources and dynamic light sources for its lighting effects. Static light sources create shadow maps on level surfaces, and are compiled into precomputed radiance volumes (PRV) that affect the ambient lighting of entities. Dynamic light sources affect the diffuse, specular, and emissive lighting of entities, and generate entity shadows. Static lights are placed in the level with WED; dynamic light can be emitted by entities at run time, or with version A8 also by setting the Dynamic flag of static light sources.

Static shadow maps

As the name says, static shadow maps affect static parts of the level: level geometry and - from version A8 on - terrain. Level shadow maps also affect entities, but only indirect through the Precomputed Radiance Volumes. The PRV equally lights the whole entity mesh depending on the static shadow distribution on level blocks along a plane below the entity. Dynamic light only affects the entity parts in its range, regardless of shadows and floor planes. Static light has no influence on the rendering time, while many dynamic lights can reduce the frame rate. If you want an entity to be affected by dynamic light sources only, set its UNLIT flag, but do not assign the mat_unlit material. If you want an entity to be affected by the static PRV only, assign the mat_unlit material but do not set the UNLIT flag.

For affecting the overall lighting in a level, use the Sun and Ambient settings in Map Properties in WED, or the sun_color and ambient_color vectors in the script.

Dynamic lights

DirectX supports only 8 dynamic light sources, which is the limit of today's 3D hardware when not using shaders. From A7 on, the engine contains a light manager that can render a theoretically unlimited number of dynamic light sources at the same time. Before rendering a particular mesh or object its 8 closest light sources are automatically activated and all other light sources are switched off. This way the 3D hardware limit is still kept, although hundreds of light sources can be visible at the same time. The maximum number of lights can be set through max_lights.

The light sorting, although very fast, is an additional rendering process that can affect the frame rate, depending on the number and ranges of active lights. Levels and map entities must be compiled in mesh mode (Create Mesh activated). Terrain should be chunked; the smaller the chunks, the less visible are light swapping effects when more than 8 lights move in or out of the range of a chunk.

 !!  When an object is in the range of more than 8 dynamic lights, the light sorting will remove the lights that are farthest away from the center of the object. This can cause artifacts especially when using shaders. Lights that are in range of a certain vertex of the object mesh are 'removed' by lights that are closer to the object center, but out of range of the vertex. The effect is sharp brightness differences along mesh edges. For this reason, use the light count shader for adjusting dynamic lights and making sure that no mesh is in range of more than 8 dynamic lights. When using shaders, the supported number of lights can be even lower.

The light formula

Both static and dynamic lights offer enough flexibility to solve a wide range of lighting situations even without using shaders. Shaders can be used to program a customized lighting engine; otherwise the total amount of light of every vertex is computed using the following equation:

Total Light = Ambient Light + Diffuse Light + Specular Light + Emissive Light

Ambient Light

Ambient light provides constant lighting for a scene. It lights all object vertices the same and is not dependent on any other lighting factors such as vertex normals, light direction, or camera position. The ambient lighting for a scene is described by the following equation.

Ambient Light = AmbientMtl * ( PRV + EntRGB )

Where:

Parameter
Description
AmbientMtl Material ambient color.
EntRGB Red, Green, Blue color of the entity when its light flag is set.
PRV Precomputed radiance color (position dependent, see below).

Precomuted Radiance Volumes (PRV) contain the precomputed light values for a grid of positions in the level, and are generated by the map compiler from static light sources and level geometry. The light values are stored in radiance planes along the shaded level surfaces. Every entity gets its radiance color value from the nearest radiance plane below its origin. This way, entities are automatically lit in bright regions and dark in shadows. Consequently you'll get wrong PRV lights when placing the entities' origin below the floor or into a solid block. For debugging purposes the current PRV values of the watched entity are indicated on screen.

Diffuse Light

Diffuse Light depends on both the light direction and the object surface normal. It varies across the surface of an object as a result of the changing light direction and the changing surface normal vector. It shades objects using a Gouraud shading algorithm and gives them three-dimensional (3-D) depth.

After adjusting the light intensity for any attenuation effects, the lighting engine computes how much of the remaining light reflects from a vertex, given the angle of the vertex normal and the direction of the incident light. This step is skipped for sun light because it does not attenuate over distance. The system considers two reflection types, diffuse and specular, and uses a different formula to determine how much light is reflected for each. After calculating the amounts of light reflected, the engine applies these new values to the diffuse and specular reflectance properties of the current material. The resulting color values are the diffuse and specular components that the rasterizer uses to produce Gouraud shading and specular highlighting.

The sun light is multiplied with the PRV brightness value. This way, reflected sun light is dim indoors or within static shadows, and bright outside.

Diffuse lighting is described by the following equation.

Diffuse Light = DiffuseMtl * (SunRGB * (N . SunDir) * (PRV + AlbedoMtl)
                               
+ Sum( Light[n] * (N . Ldir[n]) * Atten[n] * Spot[n] ))

Parameter
Description
DiffuseMtl Diffuse material color.
PRV Precomputed radiance value.
SunRGB Color of the sun light.
SunDir Direction vector from object vertex to the sun.
AlbedoMtl Albedo value of the material.
Sum Sum over all dynamic lights (up to 7).
Light[n] Color of the n-th light.
N Vertex normal vector.
Ldir[n] Direction vector from object vertex to the n-th light.
Atten[n] Light attenuation of the n-th light (distance dependent).
Spot[n] Spotlight factor of the n-th light (distance and angle dependent).

Specular Light

Specular Lighting identifies the bright specular highlights that occur when light hits an object surface and reflects back toward the camera. It is more intense than diffuse light and falls off more rapidly across the object surface. It takes longer to calculate specular lighting than diffuse lighting, however the benefit of using it is that it adds significant detail to a surface.

Modeling specular reflection requires that the system not only know in what direction light is traveling, but also the direction to the camera. The system uses a simplified version of the Phong specular-reflection model, which employs a halfway vector to approximate the intensity of specular reflection. Specular Lighting is described by the following equation.

Specular Light = SpecularMtl * (SunRGB * (N . H)^p * (PRV + AlbedoMtl)
                                       + Sum( Light[n] * (N . H)^p * Atten[n] * Spot[n] )

Parameter
Description
SpecularMtl Specular material color.
PRV Precomputed radiance value.
SunRGB Color of the sun light.
AlbedoMtl Albedo value of the material.
Sum Sum over all dynamic lights (up to 7).
N Vertex normal vector.
H Halfway vector.
p Specular reflection power. Range is 0 to +infinity.
Light[n] Color of the n-th light.
Atten[n] Light attenuation of the n-th light (distance dependent).
Spot[n] Spotlight factor of the n-th light (distance and angle dependent).

Emissive Light

Emissive Light looks as if emitted by the entity; for example, a glow (it does however not influence nearby surfaces like dynamic light that is really emitted!) It is set solely by the emissive material color,

Emissive Light = EmissiveMtl

 

► latest version online