some wise words
Want to be notified of new blog posts?


Tino van der Kraan

Light Baking Automation in Unity 5November 5, 2015

By Tino

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.

I won’t assume that you know exactly how to install this script so let me illustrate this for you with this step by step explanation for the code illiterate.

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<string> sceneList = new List<string>();
    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! 🙂

Want to be notified of new blog posts?