SceneManager.LoadSceneAsync and getting REAL loading times

Hey community,

I’m loading a pretty big environment through SceneManager.LoadSceneAsync, but when I first initiate the load, the async progress jumps from 0.0 to 0.9 in like one frame, and then I wait for ~90-100 seconds for the scene to actually load/switch, or whatever is happening on the preloading thread. I don’t mind the wait time, But I do need to know the exact percentage of completion. Is there a way to do this?

Here’s my current code :

public IEnumerator LoadMyLevel()
    {
        PhotonNetwork.isMessageQueueRunning = false;
        AsyncOperation async = SceneManager.LoadSceneAsync(LevelInfo.LevelName, LoadSceneMode.Single);
        async.allowSceneActivation = false;
        while (async.progress < 0.9f)
        {
            StatusText.text = "<Loading Map : " + LevelInfo.LevelName + " : " + (100f * async.progress).ToString("F0") + ">";
        }
        StatusText.text = "<Loading Complete : " + LevelInfo.LevelName + " : " + (100f * async.progress).ToString("F0") + ">";
        async.allowSceneActivation = true;
        while(!async.isDone)
            yield return async;
       
           
    }

It could be that the scene doesn’t take long to load at all, especially if most of the art and sound assets are already in memory from a previous scene, but the first frame of your new scene, or the last frame of the current scene, could be what is taking the time. If you have expensive operations taking place in Awake, OnEnable, or Start of the new scene, they could be dragging out that frame time. If you have expensive operations taking place in OnDisable or OnDestroy of your current scene, those could drag out the frame time.

There’s loading the assets and what not, and then there’s initializing the assets. The 0.9 to 1 is the initializing. And it’s taking a while.

There’s no actual way to know how long a load will actually take. There’s no actual way for unity to even know how long your scene takes to initialize…

So here in lies a big problem… when we know we have 1000megs of data to load into memory… we can tell how far a long we are. We’ve loaded 500megs, so we have 50% left.

BUT, when we have tons of initialization stuff, there’s no metric to measure by. We don’t know how many of what are whats. The loader could come up with some analytics to count how many things are to be initialized and as it goes through the list it tallies stuff off and whatnot… but this is actually a lot of work that would add even more load time, as well as complicate the loading code (we have to use the tracking load code when loading through SceneManager, where as we use the faster when calling Instantiate). So it’s more work and code for the Unity devs, to result in slower load times… for what, so that those people who want to show a loading bar have a bay that doesn’t stall out for a little it of its progression?

You ever notice how most of those bars for other things (like installers) do the SAME thing, they seem to do large sections of loading super d, duper fast, but others super d-duper slow.

This is why… some things just aren’t so easy to track.

Now if you don’t like it jumping to 90% then sitting at 90% for a while then jumping to 100%… how about you do this.

For the first 90%, scale the number to be from 0->50%.

Then while initializing add to the 0.5 little tiny bits every frame until it’s done.

Now the bar appears to be progressing more accurately then before, though still not actually accurate… because it couldn’t be accurate. And why does it matter? (heck, why do you think so many games just have a spinning logo or what not when loading…)

Like this:

while(async.progress < 0.9f)
{
    var scaledPerc = 0.5f * async.progress / 0.9f;
    StatusText.text = "<Loading Map : " + LevelInfo.LevelName + " : " + (100f * scaledPerc).ToString("F0") + ">";
}

async.allowSceneActivation = true;
float perc = 0.5f;
while(!async.isDone)
{
    yield return null;
    perc = Mathf.Lerp(perc, 1f, 0.05f);
    StatusText.text = "<Loading Map : " + LevelInfo.LevelName + " : " + (100f * perc).ToString("F0") + ">";
}

StatusText.text = "<Loading Complete : " + LevelInfo.LevelName + " : 100>";
2 Likes

hmmm, I see what you mean. I’ll see if I can trim the initialization stuff in the scene that supposed to be loaded, as well as cheat the progress bar. Thanks guys for the “solution” lol

whoa! I substituted your code in my script and the great big scene took about 3 seconds to load! What type of magic are you using? @lordofduct