SceneManager.LoadSceneAsync progress jumps from 0 to 0.9 after ~15s wait between yields

Hello, I am making a load screen for my game. Approach seems straightforward, made a scene with text saying “Loading x%”. Make an AsyncOperation object and poll its progress to update the text. However my scene starts the load loop, then waits about 15 seconds, then jumps from 0 to 90%, then jumps straight to loading. Here is the code, and I left in my debug prints to confirm the timing, on the off chance those are screwy:

    public IEnumerator LoadGameSceneAsync()
    {
        const int SCENEINDEX = 3;
        print("LoadGameSceneAsync: " + System.DateTime.Now);
        AsyncOperation operation = SceneManager.LoadSceneAsync(SCENEINDEX);
        print("LoadGameSceneAsync2: " + System.DateTime.Now);

        while (!operation.isDone)
        {
            print("operation.progress :" + System.DateTime.Now + " operation.progress: " + operation.progress);
            yield return null;
        }

    }

Here’s the console output:

Notice the 14 second wait between 0 and 0.9.

Looking online, the only other mentions I see of this behavior is for scenes that are extremely small and load instantly, but the scene I am loading is quite hefty. One unusual feature of the level is it contains a bunch of embedded video clips - approximately 4 gigs worth. I can see that accounting for the long load time but I don’t know why that might cause problems with the progress updating. Otherwise the scene is just standard geos. Anyone have any clues what might be happening here?

Its a feature. A stupid one but thats how it works. At 90% your scene is effectively loaded and its oncreate/onstart procedures are run. This includes any asset loading, especially embedded videos, and will freeze your ui until it finishes loading everything.

The only solution i know of requires large reworks to your code, that basically remove everything from the start/load of your scene and loads it in a function called manually after your scene has been loaded.

IIRC the progress will not be updated properly when using play mode. Have you tried making a build and see what happens? Can you report if it at least works there correctly?

Also note that when hitting approx. 0.9, you’ll want to set scene activation to be allowed in order to actually complete the loading.

As for the progress value… I’ve never really understood the 0.9 thing anyway, honestly though I’ve never bothered searching if there’s any technical information out there as to why they expose a value of 0.9 as “done” when they could have made this a normalized value on the public API side.

One thing to note is that code in Start/Awake/OnEnable will run after you set the scene to active. So if you have lots of calculations that take place here will run synchronously outside the scene load. Are you doing heavy calculations in the start of the loaded scene?

Winner winner chicken dinner! It does work much better in a build than in the editor. Ill throw in that scene activation as well. Thanks!

If you want the scene to start as quickly as possible, then you should set it to allowed the moment it starts loading. Don’t wait for 0.9.

The only reason I can think of to wait for 0.9 is if you want to notify the user that you’re ready and then wait for them to take some action (e.g. if your loading screen has a story on it and you want the user to click to indicate that they’re done reading).

Good to know, thanks!

You can use allowSceneActivation, so if it’s set to false, it won’t redirect right away.
With that, even if the scene loads before the progress bar, it will only be redirected if the progress bar reaches 100% with a simple check and setting allowSceneActivation to true.

float progress = 0f;

AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(sceneIndex);

asyncLoad.allowSceneActivation = false; //scene will not load while this value is false

while(progress <= 1f) {

    slider.value = progress;

    progressText.text = Mathf.Round(progress * 100f) + "%";

    progress += .01f;

    yield return new WaitForSeconds(.01f);
}

while (!asyncLoad.isDone && progress >= 1f) {

    asyncLoad.allowSceneActivation = true; //here the scene is definitely loaded.

    yield return null;

}

When allowSceneActivation is set to false, Unity stops progress at 0.9, and maintains.isDone at false.
so the progress will not be >= 1