Positions of the 8 most relevant dynamic lights
, including a virtual dynamic light that represents the sun.
The light ranges (lightrange) are stored in the vecLightPos.w component. The light range is zero if a light is not active.
Positions of the 8 most relevant dynamic lights as above, but in view coordinates rather than world coordinates.
RGB values of the 8 most relevant dynamic lights.
Normalized direction vectors of the 8 most relevant dynamic lights. If a light is not directional, i.e. if it is not the sun and its SPOTLIGHT flag is not set, all components of this vector are 0.
Otherwise the w component is set to the range of the light.
- A7.20 The array is sorted from close to far lights, with vecLightPos being the position of the closest light.
The sun has the largest distance and is thus the last light in the array.
In postprocessing shaders, the light values are set to the 8 closest lights that overlap the frustum of the postprocessing view. If the postprocessing view has a genius, the light values are set to the closest lights in range of the genius entity instead.
- In an average vs 1.1 shader, the maximum number of instructions is only
sufficient for calculating about 6 dynamic lights. Higher shader versions
can theoretically support 30
or more simultaneous dynamic lights.
- Use only lights with a nonzero range for light calculation. The .w component contains the range, therefore use only the
vecLightPos.xyz components for matrix multiplications.
The light range of the sun can be adjusted through the third component (roll) of the sun_angle vector (default: 100,000).
If sun_light is zero, the sun is not included in the array. This can be used for indoor levels when you don't want sun light to affect shaders.
The type of light can be determined in shaders in the following way: vecLightDir[i].w > 10000 => sun; vecLightDir[i].w > 0 => spotlight or directional light; otherwise, pointlight.
// Use dynamic lights in a vertex shader
// return the dynamic light on the surface
float4 DoPointLight(float3 P, float3 N, int i)
// calculate the light ray pointing from the light to the surface
float3 D = (float3)vecLightPos[i]-P;
// calculate the angle between surface and light ray
float NdotL = dot(N,normalize(D));
// modulate the light by the surface angle
float4 Color = vecLightColor[i] * NdotL;
// calculate the light attenuation factor
float fac = 0.f;
if (NdotL >= 0.f && vecLightPos[i].w > 0.f)
// get the distance factor
float LD = length(D)/vecLightPos[i].w;
if (LD < 1.f)
fac = 1.f - LD;
return Color * fac;
VS_OUT TerrainLight_VS (
float4 inPos : POSITION,
float3 inNormal : NORMAL)
// transform the vector position to screen coordinates
Out.Pos = mul(inPos,matWorldViewProj);
// Terrains don't need to rotate the normal, but it must be normalized
float3 N = normalize(inNormal);
float3 P = mul(inPos,matWorld);
// Add 6 dynamic lights (maximum for vs 1.1)
Out.Color = float4(0.f,0.f,0.f,0.f);
for (int i=0; i<6; i++)
Out.Color += DoPointLight(P,N,i);
predefined shader variables