- Home /
Can Jobs be used to load large scenes asynchronously without freezing?
I've struggled with async scene loading for years. My scenes are typically very large, and take 10+ seconds to load. This is because they use 2k x 2k terrains, dense Vegetation Studio landscaping, and realistic ocean water, plus lots of other objects.
My initial plan was to move the player to a persistent enclosed space or sub-scene - a hyperloop car, or a space warp bubble for instance - and project a scene transition video while destroying the old scene and using SceneManager.LoadSceneAsync to load the new one. Unfortunately async isn't really async, as has been reported elsewhere, and the player and video freeze for quite a long time once the new scene load reaches 90%.
So I have several questions:
Can the new Jobs System be used to load a new scene in another thread, so it's fully ready to go, and then dump it all back into the main thread without as much lag?
If not, are there any other thread safe ways to do this outside the main thread?
If it can't be done at all using multi-threading, are there other ways to minimize the lag? Load the parts the player will see first for instance, and build up the rest over multiple frames to minimize impact?
I'm looking for solutions that are tested, and relatively simple to implement, either through code or Asset Store products. Most of the suggestions I've seen elsewhere are pretty vague, or show the person offering them just read them from the manual without actually using them in challenging scenes. They're also generally several years old, some going back to Unity 5, so I'm hoping there have been new developments in Unity 2021/2022. Thanks.
Answer by rh_galaxy · May 11 at 09:40 PM
I'm not familiar with Jobs. But threading is good with the limitation that you are not allowed operations that involves Unity state.
The freezes will possibly be shorter, but will not be gone. I made a VR game where steady framerate is important, so I ended up fading screen to black.
Here is a piece of code for one extra thread I have in my game (modified/untested).
using System.Threading;
public class GameLevel : MonoBehaviour
{
Thread thread;
ManualResetEvent event = new ManualResetEvent(false);
bool next = false;
void LoadThread()
{
//do something
//...
//pause until main thread detect it
next = true;
event.WaitOne();
//generate final mesh for example
//...
loaded = true;
}
void LoadBegin()
{
ThreadStart ts = new ThreadStart(LoadThread);
thread = new Thread(ts);
thread.Priority = System.Threading.ThreadPriority.Lowest;
thread.Start();
}
public bool LoadDone()
{
if (next)
{
//do things that must be with Unity
//...
next = false;
event.Set();
}
return !thread.IsAlive;
}
}
//in main thread
AsyncOperation asyncLoad;
bool loadBeginDone = false;
bool loadDone = false;
IEnumerator LoadAsyncScene()
{
asyncLoad = SceneManager.LoadSceneAsync(scenName, LoadSceneMode.Single);
asyncLoad.allowSceneActivation = false;
while (!asyncLoad.isDone)
{
//scene has loaded as much as possible
if (asyncLoad.progress >= 0.9f)
{
if (!loadBeginDone)
{
GameLevel.LoadBegin();
loadBeginDone = true;
}
else if (GameLevel.LoadDone())
{
loadBeginDone = false;
asyncLoad.allowSceneActivation = true;
//all done, next
state++;
}
}
yield return null;
}
loadDone = asyncLoad.isDone;
}
@rh_galaxy Thanks for the quick reply, and the code example. The reason I asked specifically about Jobs, was that it supposedly keeps the code thread-safe by default, making issues related to that less likely. While your solution doesn't use it, it does look fairly clean and straightforward, so should give me something to test at least.
Your answer
Follow this Question
Related Questions
Loaded two scenes asynchronously, neither will activate? 1 Answer
How can I avoid a framerate drop when asynchronously loading scenes 0 Answers
Loading scene with LoadSceneAsync freezes and progress jumps from 0% to 90% 2 Answers
SceneManager onActiveSceneChange Pause for a while before loading a new scene 0 Answers