I finally got around to putting world generation in a background thread so I can use the main thread to show a loading progress bar. This was a little tricky since you can only interact with Unity on the main thread, so for things like combining meshes or spawning objects I added a main thread task queue, which will execute tasks for up to about 30 milliseconds each tick. That queue is pumped during a regular Unity Update call, so in order to get those tasks to run as quickly as possible I disabled VSync while the level is loading.
I haven’t found a good way to profile the background threads—Unity’s profiler only looks at the main thread and VS can’t profile Unity’s instance of Mono. I already have to monitor world generation progress in order to report back to the main thread so it can increment the progress bar, and I get some timing reporting out of that, but nothing granular. So optimizing this has been guess and check, trial and error. Like, comment out a line and see how much faster that makes it, to measure that line’s impact.
I’m definitely getting some ideas here about how I would structure an engine if I wrote one from scratch, in order to make procedural world generation faster. The main thing I think would be to have object types that are specialized instead of general purpose, so that it’s not super expensive to create an object. Making engine types threadsafe, or at least lockable, would be a huge win too.