a snippet of code for
moving computation
to "bake time"

bake time


by Charles Hinshaw
Sep 4, 2013

Static Sky is a game for tablets, and even though the latest iPad is a beast*, there are some things that you just don’t want to be doing at runtime on a mobile device… like casting thousands of rays in the scene to compute viable angles for a cover system (and tracing them back along the NavMesh to rank them) or calculating the splash positions for raindrop collisions in a storm. Whenever possible, we try to design these things so that the heavy lifting can happen at “bake time”. For us, that means recalculating automatically not only when we build for device, but also when we hit play in the Unity editor — because life is way too short to have to re-build your game just because you forgot to click “Bake” somewhere.

We’re using this technique quite a bit, so I thought it might be nice to take a moment and share a snippet of code. In a super simple file called “IBakeable.cs”, we have the following:

using UnityEngine;

#if UNITY_EDITOR

using UnityEditor.Callbacks;

#endif

using System.Collections;



public class BakeFunction
{
 
    #if UNITY_EDITOR

    [PostProcessScene(-1)]
    public static void OnPostprocessScene()
    {
        foreach (MonoBehaviour mb in UnityEngine.Object.FindObjectsOfType (typeof (MonoBehaviour)))
        {

            IBakeable ib = mb as IBakeable;
            if (ib != null)
 ib.Bake();

        }
    }
    #endif

}



public interface IBakeable
{

    void Bake ();


}

All we have to do is implement the IBakeable interface and put the slow iterative stuff into a Bake() function on any components that need to have a bake-time step. Hooking into OnPostprocessScene() to call Bake() means that there is no runtime hiccup and no need to remember to click “Recalculate” when iterating in the Scene or before building — pressing play or build does the work for us.

Cheers!
Charles

* “Beast” is, I suppose, a relative term


by Tenebrous
September 5, 2013

Brilliant!


by Takuan Daikon
September 5, 2013

That is brilliant, and I can think of some immediate uses for this idea in my own work. Thanks for this!


by Martijn
September 5, 2013

IDD What a great idea!


by Benoit FOULETIER
September 5, 2013

Small world… I coded the exact same postprocessor just yesterday, except I called my interface IBuildSceneCallback 🙂 !
One thing I’m not a fan of though, is that when you hit play the callback only happens after Awake, so if you expected stuff to be already baked at that point it’s a pity.
Works fine for actual builds though.


by Matt Diamond
September 5, 2013

I like it! I could have used something like this to automatically generate preview images for each level of my puzzle game.

Minor point that FindObjectsOfType won’t return any objects that are inactive. I think this would cause a problem if you have objects with a bake step that must be initially inactive in a scene.

In that unlikely event, a solution would be to use FindObjectsOfTypeAll instead. I understand it returns many objects that aren’t strictly part of the scene, but those won’t be bakeable anyway. I doubt there would be any noticeable performance hit.


by Ethan Vosburgh
September 28, 2013

I’m running into a problem generating meshes in ExecuteInEditMode that then keep updating at runtime. I’ve read that using the 
#if UNITY_EDITOR define is a decent way to get around this but am wondering if this would be a more elegant solution.

And thanks guys for these helpful insights into your dev process 🙂


by Charles
September 30, 2013

@Ethan – are you otherwise serializing your meshes correctly and just looking for a good point to do that serialization? It seems like if you’re doing things to generate the meshes at edit time, post-generation is the right time to serialize for you, rather than baking when going into build. It really depends on what you want though. I suppose you’re using AssetDatabase.CreateAsset() to serialize the mesh in edit mode and then setting the MeshFilter.mesh to point to that asset for runtime?


by Nicholas Francis
October 2, 2013

@Ethan: Yeah, Unity’s handling of [ExecuteInEditMode] is so crappy I don’t know whether to laugh or cry….

#if !UNITY_EDITOR will help it from not running on the actual device. To prevent it from running in playmode, inside the editor, you need to do sth like:

if (Application.isPlaying && Application.isEditor)
return;

at the beginning of your update function. It blows but it works 😉


by Ethan Vosburgh
October 2, 2013

@Nich and Charles

Thanks guys 🙂

Yeah, I went with:

if (Application.isPlaying && Application.isEditor)
return;

I will probably only have several dozen of these per level so the overhead will hopefully be nominal.

Add Your Comment