Sponsored By

Light Baking Automation in Unity 5

This blog will discuss an improvement on the time consuming process of baking lights in Unity 5, and will provide a solution on how to address this by automating the process using a single editor script.

Tino van der Kraan, Blogger

November 5, 2015

4 Min Read
Game Developer logo in a gray background | Game Developer

[As posted http://sassybot.com/blog/light-baking-automation-in-unity-5/]

Hello! Let's talk about light baking in Unity 5 and automating the baking process.

We have all been there. Staring at a progress bar assuming that it must be done soon just to discover that it was nowhere near finished by the time that the process is finally done. You look at the clock and scold yourself for wasting time you could have spent catching up on sleep.

Light baking can take a lot of time. Generally these processes are offloaded using different computers or are done overnight but it usually requires someone to press a few buttons every now and then to move things along. In an attempt to get more baking done with less management, I created a simple script that takes care of this for any number of scenes you throw at it.

The idea is pretty simple. Tell Unity which scenes need to be baked and set it to bake. Below you can see an example of how it works.

The script takes care of pressing the bake button for every scene in the list you give it, and it will save the scene when done with the bake before moving to the next. While doing this, it reports on its progress with the amount of time taken per bake and at what time each bake finished.

1) Create an Editor folder at the root of your Unity project and create a new C# script called BakeScenes

2) Copy and paste the code below into the Bake Scenes script using a text editor of your choice


using System.IO;
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;

public class BakeScenes : EditorWindow
{
    // Array to store an Object array of the scenes
    public Object[] scenes;

    // Lists and string array for easier management
    List sceneList = new List();
    private int sceneIndex = 0;
    private string[] scenePath;

    // Editor text
    string bakeButton = "Bake";
    string status = "Idle...";
    System.DateTime timeStamp;

    // Menu entry
    [MenuItem("Tools/Bake Scenes")]
    public static void ShowWindow()
    {
        EditorWindow window = GetWindow(typeof(BakeScenes), false, "Bake Scenes");
        window.autoRepaintOnSceneChange = true;
    }

    // Refresh the editor text when in focus
    void OnFocus()
    {
        status = "Idle...";
        if (!Lightmapping.isRunning)
        {
            bakeButton = "Bake";
        }
    }

    void OnGUI()
    {
        // "target" can be any class derrived from ScriptableObject 
        // (could be EditorWindow, MonoBehaviour, etc)
        ScriptableObject target = this;
        SerializedObject so = new SerializedObject(target);
        SerializedProperty scenesProperty = so.FindProperty("scenes");

        EditorGUILayout.PropertyField(scenesProperty, true); // True means show children
        so.ApplyModifiedProperties(); // Remember to apply modified properties

        if (GUILayout.Button(bakeButton)) // Button to start bake process
        {
            InitializeBake();
        }
        EditorGUILayout.LabelField("Status: ", status);
        so.Update();
    }

    // If not baking, set delegates, set scenes, and start baking.
    // Otherwise, stop lightmapping and update editor text
    void InitializeBake()
    {
        if (!Lightmapping.isRunning)
        {
            Lightmapping.completed = null;
            Lightmapping.completed = SaveScene;
            Lightmapping.completed += BakeNewScene;
            SetScenes();
            BakeNewScene();
        }
        else
        {
            Lightmapping.Cancel();
            UpdateBakeProgress();
        }
    }

    // Create a string array of scenes to bake
    private bool SetScenes()
    {
        // Reset values
        sceneList.Clear();
        sceneIndex = 0;

        // Get paths for scenes and store in list
        if (scenes.Length == 0)
        {
            status = "No scenes found";
            bakeButton = "Bake";
            return false;
        }
        else
        {
            for (int i = 0; i < scenes.Length; i++)
            {
                sceneList.Add(AssetDatabase.GetAssetPath(scenes[i]));
            }

            // Sort and put scene paths in array
            scenePath = sceneList.ToArray();
            return true;
        }
    }

    // Loop through scenes to bake and update on progress
    private void BakeNewScene()
    {
        if (sceneIndex < scenes.Length)
        {
            EditorApplication.OpenScene(scenePath[sceneIndex]);
            timeStamp = System.DateTime.Now;
            Lightmapping.BakeAsync();
            UpdateBakeProgress();
            sceneIndex++;
        }
        else
        {
            DoneBaking("done");
        }
    }

    // Updates baking progress
    private void UpdateBakeProgress()
    {
        if (Lightmapping.isRunning)
        {
            status = "Baking " + (sceneIndex + 1).ToString() +
            " of " + scenes.Length.ToString();
            bakeButton = "Cancel";
        }
        else if (!Lightmapping.isRunning)
        {
            DoneBaking("cancel");
        }
    }

    // Saves the scene at the end of each bake before starting new bake
    private void SaveScene()
    {
        System.TimeSpan bakeSpan = System.DateTime.Now - timeStamp;
        string bakeTime = string.Format("{0:D2}:{1:D2}:{2:D2}",
            bakeSpan.Hours, bakeSpan.Minutes, bakeSpan.Seconds);
        Debug.Log("(" + sceneIndex.ToString() + "/" +
            scenes.Length.ToString() + ") " + "Done baking: " +
            EditorApplication.currentScene + " after " + bakeTime +
            " on " + System.DateTime.Now.ToString());
        EditorApplication.SaveScene();
    }

    // When done baking, update the editor text
    private void DoneBaking(string reason)
    {
        Lightmapping.completed = null;
        sceneList.Clear();
        sceneIndex = 0;

        if (reason == "done")
        {
            status = "Bake is done";
            bakeButton = "Bake";
        }
        else if (reason == "cancel")
        {
            status = "Canceled";
            bakeButton = "Bake";
        }
    }
}

You will now have a Tools menu entry, as can be seen in the first .gif, in the menu bar of Unity where you can open the Bake Scenes window. Just add your scenes, hit bake, and...

Extend your gratitude by giving me a shoutout on Twitter at @Tinovdk or sharing this blog on social media of  your choosing.

Thanks for reading all the way to the end! :)

Read more about:

Featured Blogs
Daily news, dev blogs, and stories from Game Developer straight to your inbox

You May Also Like