Scene loads very slow from a black screen after fade

So I guess this is finaly the last big error before I can run my game properly.

So I have build my game to make a little play test. In my version you go from starting a new game into a cutscene. Once the cutscene has finished I am using the normal fader, that we also used for the portal, to fade in into the first level.The fade is doing its job and is doing the fade out with the setted times.But then it takes like 10-20 seconds until the next scene loads. So after the fade its like a black screen for 10-20 seconds until the game finaly loads and I am asking myself why? Is it cause of the LoadSceneAsync?
This is the code of my cutscene, which loads the Coroutine once the video has finished to play:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Video;
using UnityEngine.SceneManagement;
using RPG.Saving;
using System;

namespace RPG.SceneManagement
{

    public class VideoPlayback : MonoBehaviour
{
    public VideoPlayer VideoPlayer; // Drag & Drop the GameObject holding the VideoPlayer component
    public string SceneName ;  

    [SerializeField] float fadeInTime= 0.2f;
    [SerializeField] float fadeOutTime = 0.3f;
    [SerializeField] int sceneToLoad = 2;
  

     void Start() 
     {

        VideoPlayer.loopPointReached += LoadScene;
     }
     void LoadScene(VideoPlayer vp)
     {
            StartCoroutine(LoadFirstScene());
            
      }

         IEnumerator LoadFirstScene()
           {
            Fader fader = FindObjectOfType<Fader>();
            yield return fader.FadeOut(fadeOutTime);
            SceneManager.LoadSceneAsync(sceneToLoad);
            fader.FadeIn(fadeInTime);
             
            }
  }
}

And here we have my Fader and Portal Scripts:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//Script for creating a fade when changing between scenes

namespace RPG.SceneManagement
{

    public class Fader : MonoBehaviour
    {
        CanvasGroup canvasGroup;
        Coroutine currentActiveFade = null;

        private void Awake()
        {
            canvasGroup = GetComponent<CanvasGroup>();    
        }

        public void FadeOutImmediate()
        {
           canvasGroup.alpha = 1;
        }

        public Coroutine FadeOut(float time)
        {
           return Fade(1, time);
        }

        public Coroutine FadeIn(float time)
        {
            return Fade(0,time);
        }

        public Coroutine Fade(float target,float  time)
        {
             if (currentActiveFade != null)
            {
                StopCoroutine(currentActiveFade);
            }
                currentActiveFade = StartCoroutine(FadeRoutine(target,time));
                return currentActiveFade;
        }

        private IEnumerator FadeRoutine(float target, float time)
        {
            while (!Mathf.Approximately(canvasGroup.alpha, target)) 
             {
                canvasGroup.alpha = Mathf.MoveTowards(canvasGroup.alpha, target,Time.unscaledDeltaTime/time);
                yield return null;
             }
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.AI;
using RPG.Control;
using UnityEngine.Events;

//Script for creating a portal and change scenes seemesly

namespace RPG.SceneManagement
{
    public class Portal : MonoBehaviour
    {
        enum DestinationIdentifier
        {
            A, B, C, D, E
        }

        [SerializeField] int sceneToLoad = 1;
        [SerializeField] Transform spawnPoint;
        [SerializeField] DestinationIdentifier destination;
        [SerializeField] float fadeInTime = 1f; 
        [SerializeField] float fadeOutTime = 1f; 
        [SerializeField] float fadeWaitTime = 0.5f;

       

        private void OnTriggerEnter(Collider other)
        {
            if(other.tag == "Player")
            {
                StartCoroutine(Transition());
                
            }
        }

        private IEnumerator Transition()
        {
            if(sceneToLoad < 0)
            {
                Debug.LogError("Scene to Load not set");
                yield break;
            }

            //SceneManager.LoadScene(sceneToLoad);
            
            DontDestroyOnLoad(gameObject);
            
            Fader fader = FindObjectOfType<Fader>();
            SavingWrapper wrapper = FindObjectOfType<SavingWrapper>();
            PlayerController playerController = GameObject.FindWithTag("Player").GetComponent<PlayerController>();
            playerController.enabled = false;
            
            yield return fader.FadeOut(fadeOutTime);

            //Save current Level
            
            wrapper.Save();

            yield return SceneManager.LoadSceneAsync(sceneToLoad);
            PlayerController newplayerController = GameObject.FindWithTag("Player").GetComponent<PlayerController>();
            newplayerController.enabled = false;
            
            //Load current Level
            wrapper.Load();

            Portal otherPortal = GetOtherPortal();
            UpdatePlayer(otherPortal);

            wrapper.Save();

            yield return new WaitForSeconds(fadeWaitTime);
            fader.FadeIn(fadeInTime);
            
            newplayerController.enabled = true;
            Destroy(gameObject);
        }

        private void UpdatePlayer(Portal otherPortal)
        {
            GameObject player =GameObject.FindWithTag("Player");
            player.GetComponent<NavMeshAgent>().enabled = false;
            player.transform.position = otherPortal.spawnPoint.position;
            player.transform.rotation = otherPortal.spawnPoint.rotation;
            player.GetComponent<NavMeshAgent>().enabled = true;
        }

        private Portal GetOtherPortal()
        {
            foreach (Portal portal in FindObjectsOfType<Portal>())
            {
                if (portal == this) continue;
                if(portal.destination != destination) continue;

                return portal;
            }
            return null;
        }
    }
}

It’s possibly a problem in your LoadFirstScene() Coroutine…
All three statements need a yield return to function properly

IEnumerator LoadFirstScene()
{
   Fader fader = FindObjectOfTpe<Fader>();
   yield return fader.FadeOut(fadeOutTime);
   yield return SceneManager.LoadSceneAsync(sceneToLoad);
   yield return fader.FadeIn(fadeInTime);
}
1 Like

That haven’t done the trick. After the Cutscene has played, now the screen stays in the fader white screen for about 20-30 seconds until the scene is loaded. And I guess 20-30 seconds for loading a scene is a bit too long

I’m not at all sure if this will solve your issue but you have to bare in mind that this VideoPlayer object will be destroyed when the scene changes, just like portals do. This is why we have the DontDestroyOnLoad in the portal transition. Perhaps your LoadFirstScene should look like this

IEnumerator LoadFirstScene()
{
    // keep the object across scenes
    DontDestroyOnLoad(gameObject);

    Fader fader = FindObjectOfTpe<Fader>();
    yield return fader.FadeOut(fadeOutTime);
    yield return SceneManager.LoadSceneAsync(sceneToLoad);
    yield return fader.FadeIn(fadeInTime);

    // Destroy the object 'cos it's no longer needed
    Destroy(gameObject);
}

This then also means that the VideoPlayer object must be in the root of the hierarchy, like portals

But it is totally fine that the videoPlayer gets destroyed cause after the cutscene I dont need it anymore when I load the first level then?

Yes, but the video player is controlling the fade, so it needs to finish the fade first before it is destroyed

Just tried it out with your code and the white fade is still about 20-30 seconds before loading the scene

Doe it wait 20-30 seconds before loading the scene, or does it take 20-30 seconds to load the scene?

Add some debug logs and show us what’s happening

    Debug.Log($"Fading out: {fadeOutTime}");
    yield return fader.FadeOut(fadeOutTime);
    Debug.Log("Loading scene");
    yield return SceneManager.LoadSceneAsync(sceneToLoad);
    Debug.Log($"Fading in: {fadeInTime}");
    yield return fader.FadeIn(fadeInTime);
    Debug.Log("Done");

The console prints timestamps (by default) so also show us that

So thats what hes shooting me out on the Debug. But it takes 20-30 seconds until he starts with printing the first debug log message, meanwhile the hole screen is just white…

The delay has nothing to do with the fader. Your scene takes 40 seconds to load. What is so big in your scene that it takes 40 seconds to load?

I have no Idea? :smiley: Just some NPC’s and my player and the world and a weathermanager… Can I somehow find out what is so big that it takes so long?

I don’t really know. I’ve never had issues with scenes loading for such a long time that I needed to look into it. What I do know is that all references are being loaded into memory. If you have a prefab that references 100 other prefabs, all 100 of those prefabs will be loaded. Any references they have will also be loaded, etc.

Perhaps take a look at this.

Don’t know if it may help

Well what I tried to do is to put a loading screen in, so I wont have those white fading. I used the Tutorial from Brackeys for it but actually the progress bar only hits 100% when he load the level, before it will stay at 0% until those annoying 40 seconds are over…why.?? :c

We need to do things a bit differently when you want progress with LoadSceneAsync

        AsyncOperation op = SceneManager.LoadSceneAsync(levelToLoad);
        while ( !op.isDone )
        {
            float progress = Mathf.Clamp01(op.progress / .9f);
            //Update progress bar
            yield return null;
        }

IIRC, this allows you to load the scene and also lets you decide when to switch.

So, technically, you can start the scene load at the same time as the cutscene video so it will start loading the scene while the video is playing. If the video is long enough, the scene would be loaded by the time the it is done and you can just switch scenes. If the video finishes before the level is loaded completely, you can just continue to wait with a load screen.

It would be something like this

public class VideoPlayback : MonoBehaviour
{
    public VideoPlayer VideoPlayer; // Drag & Drop the GameObject holding the VideoPlayer component
    public string SceneName ;  

    [SerializeField] float fadeInTime = 0.2f;
    [SerializeField] float fadeOutTime = 0.3f;
    [SerializeField] int sceneToLoad = 2;

    AsyncOperation sceneLoadOperation;

    void Start() 
    {
        sceneLoadOperation = SceneManager.LoadSceneAsync(sceneToLoad);
        sceneLoadOperation.allowSceneActivation = false; // don't switch scenes when done
        VideoPlayer.loopPointReached += LoadScene;
    }
    
    void LoadScene(VideoPlayer vp)
    {
        StartCoroutine(LoadFirstScene());
    }

    IEnumerator LoadFirstScene()
    {
        Fader fader = FindObjectOfType<Fader>();
        yield return fader.FadeOut(fadeOutTime);
        while (!sceneLoadOperation.isDone)
        {
            // you could 'adjust' remaining progress to appear to be going from 0-100
            float progress = Mathf.Clamp01(sceneLoadOperation.progress / .9f);
            //Update progress bar
            yield return null;
        }
        yield return fader.FadeIn(fadeInTime);

        sceneLoadOperation.allowSceneActivation = true;
    }
}

So, this will start the scene load when this component start, but it will not switch scenes when it’s done. When the video is complete and it faded the screen, it will start the progress bar (if it’s not completely loaded yet) and then load the scene when it’s done. At least, that’s the theory. I haven’t tested this

Well that isn’t working out aswell but I think the fade and loading of the Scene is not really the problem. The problem is, that after the video has finished, that it takes too much time until he starts with the coroutine. So I am not sure but maybe something is wrong with this

  VideoPlayer.loopPointReached += LoadScene;

Cause this is taking so much time to load the function LoadScene. Is there any other possability of tracking if a video has finished playing?

According to the documentation (which ends at v2017.4) this event will fire when the video reached its end. Is there a long emptiness at the end of the video that you did not expect?

That was my thought aswell but the video has no emptyness at the end. But still it takes up to 30-40 seconds until the Coroutine starts. So the problem must be there somehow cause the normal level loading is super fast. Just the start of the coroutine takes ages

Can you zip and upload your project somewhere? Then I can take a better look at it. If you do, please do not include the Library folder. This will reduce the size

This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.

Privacy & Terms