This is the documentation for Enlighten.

Irradiance with skylight


One way to produce more interesting shading which varies with the normal while still only computing the Enlighten irradiance output at run-time is to use the fixed radiosity normal texture produced by the precompute.

To do this, model the indirect irradiance illumination as a light coming from the irradiance normal direction, with a half-Lambert falloff. Then add back an extra skylight term for geometry which faces away from the radiosity normal.

The diffuse component of the directional irradiance model is similar in that the incoming bounce light is computed with a half-Lambert falloff, but the incoming direction is not fixed; it is read from the directional texture(s).

This works well for scenes such as outdoor cityscapes where there may be detailed geometry (for example, ledges and window frames) which faces away from the radiosity normal and should pick up extra light from the sky which is missed out of the irradiance computation.

float3 GetIrradiance(float2 uv, float3 normal)
{
    float3 irradiance = tex2D(g_IrradianceSampler, uv).xyz;
    float4 radiosityNormalTextureValue = tex2D(g_RadiosityNormalSampler, uv);

    // The w channel of the radiosity normal texture is the "skylight factor" - how much
    // of the environment is visible at that point.
    float skylightFactor = radiosityNormalTextureValue.w;
        
    // Rescale radiosity normal (since it comes from an 8888 texture with values
    // in [0,1]).
    float3 radiosityNormal = radiosityNormalTextureValue.xyz * 2.0f - 1.0f;

    // Compute lighting for a hemispherical lighting coefficient for a light with the sky
    // colour in the "up" direction and black in the "down" direction.
    float3 hemispherical = (dot(normal, g_SkylightUp) * 0.5f + 0.5f) * g_SkylightColour * skylightFactor;

    // Compute the half-Lambert term for the "irradiance light" coming along the
    // irradiance normal direction.
    float4 tau = float4(radiosityNormal.xyz, 1.0f) * 0.5f;
    float dotI = dot(tau, float4(normal, 1.0f));

    // Combine the irradiance light and the skylight, and clamp.
    return max(float3(0.0f, 0.0f, 0.0f), dotI * irradiance.xyz + (1.0f - dotI) * hemispherical * g_SkylightColour);
}