Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Baking lighting via command line script

Discussion in 'Scripting' started by dgoyette, Sep 26, 2019.

  1. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,120
    I build via a command line script. Recently I decided I would try to bake lighting via the command line build as well, to avoid needing to go into each scene manually and bake lighting. I added the following to my command line build method:

    Code (CSharp):
    1.             // Bake lighting. This should generally be pretty fast, as we assume that lighting is already baked and cached.
    2.             double totalLightBakingTime = 0;
    3.             foreach (var scene in scenes)
    4.             {
    5.                 Debug.Log($"Opening scene {scene} and baking lighting.");
    6.                 var lightBakingSceneStartTime = DateTime.Now;
    7.                 EditorSceneManager.OpenScene(scene);
    8.                 Lightmapping.Bake();
    9.  
    10.                 var lightBakingSeconds = (DateTime.Now - lightBakingSceneStartTime).TotalSeconds;
    11.                 totalLightBakingTime += lightBakingSeconds;
    12.                 Debug.Log($"Finished baking lighting for scene {scene} in {lightBakingSeconds} seconds.");
    13.             }
    14.             Debug.Log($"Finished baking lighting for all scenes in {totalLightBakingTime} seconds.");

    Although this does perform the baking, I'm finding some issues with the results of baking in this way. In one level, the emissive lights don't seem to update the Realtime GI properly when I bake this way. If, however, I manually bake within the Unity editor (and I disable baking during the command line build) the lighting works properly.

    So I'm wondering if there's a different approach I should be using to bake lighting during a command line build. I use a batch file to kick off the build, which launches a headless version of Unity:

    Code (CSharp):
    1. "C:\Program Files\Unity\Hub\Editor\2019.1.14f1\Editor\Unity.exe" -quit -batchmode -stackTraceLogType Full -projectPath "C:\Users\Dan\Documents\GitHub\Gravia" -executeMethod CommandLineBuildUtil.BuildWindows
    One thing to note, though I don't know if it's significant, is that the resulting LightingData.asset files that come from baking lighting in these two ways (within Unity proper and via command line) are the same file size, but they differ slightly in their exact content. They're binary files (or something like that) so I don't know if this is meaningful to show some comparison, but the earlier parts of the files show various differences:

    upload_2019-9-26_11-18-6.png

    Is anyone else baking lighting in a command line script? If so, how are you doing it? Is the approach I'm taking not correct?
     
    isidro02139 likes this.
  2. matt_wills8

    matt_wills8

    Joined:
    Jan 26, 2020
    Posts:
    2
    Did you make any progress with this? we're interested in doing something similar
     
  3. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,120
    I stopped baking lighting as part of the build process, and instead I just use an Editor tool to rebake lighting for all of my scenes. When the lighting is baked in the full editor, it never runs into any of the problems I described. And the build process becomes a bit faster in cases where I do several builds in a row without changing the lighting.

    This is the editor code I use. I'm pretty sure I found a good portion of this, but I've customized it to only bake specific scenes I want. This should work in Unity 2019.X, but it has some warnings, so I'm not sure if it's going to keep working in Unity 2020.

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using System.Linq;
    3. using UnityEditor;
    4. using UnityEditor.SceneManagement;
    5. using UnityEngine;
    6.  
    7. namespace GraviaSoftware.Gravia.Code.Editor
    8. {
    9.  
    10.     public class RebakeSceneLightingEditorWindow : EditorWindow
    11.     {
    12.         // Array to store an Object array of the scenes
    13.         private string[] scenes;
    14.  
    15.         // Lists and string array for easier management
    16.         List<string> sceneList = new List<string>();
    17.         private int sceneIndex = 0;
    18.         private string[] scenePath;
    19.  
    20.         // Editor text
    21.         string bakeButton = "Bake";
    22.         string status = "Idle...";
    23.         System.DateTime timeStamp;
    24.  
    25.  
    26.  
    27.  
    28.         [MenuItem("Gravia/Rebake Scene Lighting")]
    29.         public static void ShowWindow()
    30.         {
    31.             // Get existing open window or if none, make a new one:
    32.             var window = (RebakeSceneLightingEditorWindow)EditorWindow.GetWindow(typeof(RebakeSceneLightingEditorWindow), true, "Rebake Scene Lighting");
    33.             window.autoRepaintOnSceneChange = true;
    34.             window.Show();
    35.         }
    36.  
    37.  
    38.         // Refresh the editor text when in focus
    39.         void OnFocus()
    40.         {
    41.             //status = "Idle...";
    42.             if (!Lightmapping.isRunning)
    43.             {
    44.                 bakeButton = "Bake";
    45.             }
    46.         }
    47.  
    48.         void OnGUI()
    49.         {
    50.             // "target" can be any class derrived from ScriptableObject
    51.             // (could be EditorWindow, MonoBehaviour, etc)
    52.  
    53.             if (GUILayout.Button(bakeButton)) // Button to start bake process
    54.             {
    55.                 InitializeBake();
    56.             }
    57.             EditorGUILayout.LabelField("Status: ", status);
    58.         }
    59.  
    60.         // If not baking, set delegates, set scenes, and start baking.
    61.         // Otherwise, stop lightmapping and update editor text
    62.         void InitializeBake()
    63.         {
    64.  
    65.             scenes = CommandLineBuildUtil.GetProductionSceneList().Union(CommandLineBuildUtil.GetUISceneList()).ToArray();
    66.  
    67.             if (!Lightmapping.isRunning)
    68.             {
    69.                 Lightmapping.completed = null;
    70.                 Lightmapping.completed = SaveScene;
    71.                 Lightmapping.completed += BakeNewScene;
    72.                 SetScenes();
    73.                 BakeNewScene();
    74.             }
    75.             else
    76.             {
    77.                 Lightmapping.Cancel();
    78.                 UpdateBakeProgress();
    79.             }
    80.         }
    81.  
    82.         // Create a string array of scenes to bake
    83.         private bool SetScenes()
    84.         {
    85.             // Reset values
    86.             sceneList.Clear();
    87.             sceneIndex = 0;
    88.  
    89.             // Get paths for scenes and store in list
    90.             if (scenes.Length == 0)
    91.             {
    92.                 status = "No scenes found";
    93.                 bakeButton = "Bake";
    94.                 return false;
    95.             }
    96.             else
    97.             {
    98.  
    99.  
    100.                 for (int i = 0; i < scenes.Length; i++)
    101.                 {
    102.                     sceneList.Add(scenes[i]);
    103.                 }
    104.  
    105.                 // Sort and put scene paths in array
    106.                 scenePath = sceneList.ToArray();
    107.                 return true;
    108.             }
    109.         }
    110.  
    111.         // Loop through scenes to bake and update on progress
    112.         private void BakeNewScene()
    113.         {
    114.             if (sceneIndex < scenes.Length)
    115.             {
    116.                 EditorSceneManager.OpenScene(scenePath[sceneIndex]);
    117.                 timeStamp = System.DateTime.Now;
    118.                 Debug.Log($"Baking occlusion for {sceneList[sceneIndex]}");
    119.                 StaticOcclusionCulling.Compute();
    120.                 Debug.Log($"Baking lighting for {sceneList[sceneIndex]}");
    121.                 Lightmapping.BakeAsync();
    122.                 UpdateBakeProgress();
    123.                 sceneIndex++;
    124.             }
    125.             else
    126.             {
    127.                 DoneBaking("done");
    128.             }
    129.         }
    130.  
    131.         // Updates baking progress
    132.         private void UpdateBakeProgress()
    133.         {
    134.             if (Lightmapping.isRunning)
    135.             {
    136.                 status = "Baking " + (sceneIndex + 1).ToString() + " of " + scenes.Length.ToString() + " (" + scenes[sceneIndex] + ")";
    137.                 bakeButton = "Cancel";
    138.             }
    139.             else if (!Lightmapping.isRunning)
    140.             {
    141.                 DoneBaking("cancel");
    142.             }
    143.         }
    144.  
    145.         // Saves the scene at the end of each bake before starting new bake
    146.         private void SaveScene()
    147.         {
    148.             System.TimeSpan bakeSpan = System.DateTime.Now - timeStamp;
    149.             string bakeTime = string.Format("{0:D2}:{1:D2}:{2:D2}",
    150.                 bakeSpan.Hours, bakeSpan.Minutes, bakeSpan.Seconds);
    151.             var currentScene = EditorSceneManager.GetActiveScene();
    152.             Debug.Log("(" + sceneIndex.ToString() + "/" +
    153.                 scenes.Length.ToString() + ") " + "Done baking: " +
    154.                 currentScene.name + " after " + bakeTime +
    155.                 " on " + System.DateTime.Now.ToString());
    156.             EditorSceneManager.SaveOpenScenes();
    157.         }
    158.  
    159.         // When done baking, update the editor text
    160.         private void DoneBaking(string reason)
    161.         {
    162.             Lightmapping.completed = null;
    163.             sceneList.Clear();
    164.             sceneIndex = 0;
    165.  
    166.             if (reason == "done")
    167.             {
    168.                 status = "Bake is done";
    169.                 bakeButton = "Bake";
    170.             }
    171.             else if (reason == "cancel")
    172.             {
    173.                 status = "Canceled";
    174.                 bakeButton = "Bake";
    175.             }
    176.         }
    177.     }
    178. }
    179.