Emission lighting in Unity

Getting your emission maps to work in Unity

Emission maps (also known as emissive maps) are textures that can be applied to materials to make certain parts of an object emit light (like the cube in the image above). In Unity, lights from emission maps don’t start affecting the scene as soon as you place them on the material. There are a lot of settings you have to get right in your scene and material settings to get the emission maps working right.

Setting the emission map

For starters, the image below shows where you can turn on and set the emission map for a material.

Do take note of a few things:

  • Emission maps are only available on materials using certain shaders, so you will not find an emission map on all materials. You can set a material’s shader using the dropdown above Rendering Mode (see image above).
  • In this article, we will be configuring emissives for Unity’s Built-in Standard Shader. The script included in this article may not work if you are using a different shader.
  • Emissive maps should be mostly black. Only the parts of an object that emit light should have colour. If your object only emits a single-coloured light, consider using a black-white emission map, as it allows you to tint the colour of the light using the material’s settings. You can refer to an example further down this article.
  • On top of adjusting the emission map’s colour, you can also adjust the intensity of light coming from emissive areas. See the image below.
Setting emission intensity
You can adjust the intensity of your emissive light.

Setting static flags and enabling GI

Once the material is set up and applied on a GameObject, you will find that your object emits light, but the light does not seem to affect the rest of the objects in the scene.

Unbaked emissive object
Emissive lighting is not easy to get right.

For reference, here are the texture maps that have been used to create the material on the cube (feel free to download and try them out for yourself).

Diffuse / Albedo
Normal
Emissive

To get the emissive light to affect the rest of your scene, you need to mark all the GameObjects that you want lit as Static, including the emissive GameObject. If you don’t know how to do this, see this article for more information.

You will also need to make sure that the respective global illumination flags in the Lighting window are checked:

  • For baked emissives, Baked Global Illumination needs to be checked.
  • For realtime emissives, Realtime Global Illumination needs to be checked. If unchecked, realtime emissives will behave like baked emissives.
  • If your light probes don’t seem to work with realtime emissives, consider using Enlighten as the Lightmapper.
Enabling Global Illumination for emissives
Make sure that your Lighting settings are set right.

Once done, you will need to Generate Lighting (i.e. bake lighting) for the scene.


Article continues after the advertisement:


Realtime vs. Baked emission

Under the material’s emission settings, you should see a dropdown that says Global Illumination. In the dropdown, there are 2 options: Realtime and Baked. Depending on what option you choose, the result of the generated emissive lighting will be slightly different.

Baked Emissive
Baked Emissive

The baked emissive lighting will look more intricate and realistic, compared to the realtime one:

Although realtime emissive lighting looks less realistic, you have the option of turning it on and off during runtime with a bit of code.

Realtime Emissive Dynamic Lighting
Realtime emissive lighting can be changed in runtime.

The script below was used to activate and deactivate the emissive lighting in the image above. Specifically, the bolded portions show the parts that are responsible for activating and deactivating emissive lighting.

using System.Collections;
using UnityEngine;

[RequireComponent(typeof(Renderer))]
public class DynamicEmissive : MonoBehaviour {

    new Renderer renderer; // new hides the parent <renderer> property.
    Material material;
    Color emissionColor;

    void Start() {
        // Gets access to the renderer and material components as we need to
        // modify them during runtime.
        renderer = GetComponent<Renderer>();
        material = renderer.material;

        // Gets the initial emission colour of the material, as we have to store
        // the information before turning off the light.
        emissionColor = material.GetColor("_EmissionColor");

        // Start a coroutine to toggle the light on / off.
        StartCoroutine(Toggle());
    }
    
    IEnumerator Toggle() {
        bool toggle = false;
        while(true) {
            yield return new WaitForSeconds(1f);
            Activate(toggle, Random.Range(0.5f,2f));
            toggle = !toggle;
        }
    } 

    // Call this method to turn on or turn off emissive light.
    public void Activate(bool on, float intensity = 1f) {
        if(on) {

            // Enables emission for the material, and make the material use
            // realtime emission.
            material.EnableKeyword("_EMISSION");
            material.globalIlluminationFlags = MaterialGlobalIlluminationFlags.RealtimeEmissive;

            // Update the emission color and intensity of the material.
            material.SetColor("_EmissionColor", emissionColor * intensity);

            // Makes the renderer update the emission and albedo maps of our material.
            RendererExtensions.UpdateGIMaterials(renderer);

            // Inform Unity's GI system to recalculate GI based on the new emission map.
            DynamicGI.SetEmissive(renderer, emissionColor * intensity);
            DynamicGI.UpdateEnvironment();

        } else {

            material.DisableKeyword("_EMISSION");
            material.globalIlluminationFlags = MaterialGlobalIlluminationFlags.EmissiveIsBlack;

            material.SetColor("_EmissionColor", Color.black);
            RendererExtensions.UpdateGIMaterials(renderer);

            DynamicGI.SetEmissive(renderer, Color.black);
            DynamicGI.UpdateEnvironment();

        }
    }
}

Feel free to adapt the above script for your own purposes. Some comments have been included in the script to explain how it works.

Affecting dynamic (i.e. non-static) objects

Regardless of which emission mode you are using, emissive lighting will only affect static objects by default. For dynamic objects to be affected by emissive lighting, they will need to be within a light probe group that covers areas affected by emissive lighting.

Dynamic objects unlit by emissives
By default, non-static objects are not lit by emissives.

Even realtime emissive lights need to be baked and use light probe groups to affect dynamic objects, because Unity uses precomputed realtime global illumination. Yes, it’s a bit of a contradiction, but what it means is that Unity uses a lot of complicated mathematics to approximate global illumination realtime instead of actually doing realtime global illumination (because it’s damn expensive).

The Emission Lighting Checklist™

A lot to digest? Use this simple checklist to see what you’ve missed out:

S/NDescriptionCheck
1Enabled Emission in a material and assigned an emission colour / map.
2Ensured that the Emission intensity on the material is not 0, and Emission colour is not black.
3Environment objects to be lit are marked Static.
4Emissive object is marked Static.
5Baked and / or Realtime Global Illumination is checked in the Lighting window before baking.
6Light probes are laid out across the parts of the scene where emissive lighting is present.
7If using realtime emissives, ensured that Enlighten is the lightmapper used.

Article continues after the advertisement:


Leave a Reply

Your email address will not be published.