Search Unity

  1. Unity Asset Manager is now available in public beta. Try it out now and join the conversation here in the forums.
    Dismiss Notice
  2. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  3. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

(Case 931488) PostProcessSceneAttribute not called after loading scene

Discussion in '2017.2 Beta' started by Peter77, Jul 16, 2017.

  1. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,589
    The PostProcessSceneAttribute documentation says:
    In 2017.2.0b3, the method is only called when entering Playmode, the method is not called when additively loading a scene.

    My test case loads 4 additive scenes, printing what scene is about to be loaded to the Console window. Then I have a PostProcessScene callback that prints the current sceneCount to the Console window. This allows me to see at what point and how often the PostProcessScene callback is fired.

    Code (CSharp):
    1. public class Loader : MonoBehaviour
    2. {
    3.     System.Collections.IEnumerator Start()
    4.     {
    5.         yield return null;
    6.  
    7.         Debug.Log("Loading Scene_2");
    8.         UnityEngine.SceneManagement.SceneManager.LoadScene("Scene_2", UnityEngine.SceneManagement.LoadSceneMode.Additive);
    9.  
    10.         Debug.Log("Loading Scene_3");
    11.         UnityEngine.SceneManagement.SceneManager.LoadScene("Scene_3", UnityEngine.SceneManagement.LoadSceneMode.Additive);
    12.  
    13.         AsyncOperation asyncOp = null;
    14.         Debug.Log("Loading Scene_4");
    15.         asyncOp = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync("Scene_4", UnityEngine.SceneManagement.LoadSceneMode.Additive);
    16.         while(!asyncOp.isDone)
    17.             yield return null;
    18.  
    19.         Debug.Log("Loading Scene_5");
    20.         asyncOp = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync("Scene_5", UnityEngine.SceneManagement.LoadSceneMode.Additive);
    21.         while(!asyncOp.isDone)
    22.             yield return null;
    23.     }
    24. }
    25.  
    26.  
    27. static class SceneProcessor
    28. {
    29.     [PostProcessScene]
    30.     static void OnPostProcessScene()
    31.     {
    32.         var text = new System.Text.StringBuilder();
    33.         text.AppendFormat("  OnPostProcessScene: sceneCount={0}\n", UnityEngine.SceneManagement.SceneManager.sceneCount);
    34.         for(var n = 0; n < UnityEngine.SceneManagement.SceneManager.sceneCount; ++n)
    35.             text.AppendFormat("{0}\n", UnityEngine.SceneManagement.SceneManager.GetSceneAt(n).name);
    36.  
    37.         Debug.Log(text.ToString());
    38.     }
    39. }

    Reproduce
    • Open user project
    • Open Asset/Scenes/Scene_1
    • Press Play
    Observe that it outputs:
    Code (CSharp):
    1. OnPostProcessScene: sceneCount=1
    2. Loading Scene_2
    3. Loading Scene_3
    4. Loading Scene_4
    5. Loading Scene_5
    It only called the PostProcessScene method when entering Playmode.

    Expected
    The test should output:
    Code (CSharp):
    1. OnPostProcessScene: sceneCount=1
    2. Loading Scene_2
    3. OnPostProcessScene: sceneCount=2
    4. Loading Scene_3
    5. OnPostProcessScene: sceneCount=3
    6. Loading Scene_4
    7. OnPostProcessScene: sceneCount=4
    8. Loading Scene_5
    9. OnPostProcessScene: sceneCount=5
    PostProcessScene method called when entering Playmode and after having loaded every single scene.


    Please also take a look at the Feedback item I created regarding the PostProcessSceneAttribute, because I believe it lacks an important argument.
    https://feedback.unity3d.com/sugges...ribute-provide-scene-argument-callback-method
     
    Last edited: Jul 16, 2017
    Prodigga likes this.
  2. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    Yes, there isn't any way to know which scene we are processing when a scene is loaded additive in 2017.1 either. In 2017.1 I can additively load 3 scenes at the same time. I get PostProcessScene called 3 times, but in all 3 calls the scene count is 4. (All scenes are present). Not sure which 'scene' the call is 'for'.

    I was using
    Code (CSharp):
    1. SceneManager.GetSceneAt(SceneManager.sceneCount - 1)
    to figure out the current scene, but this doesn't work when loading multiple scenes at the same time.
     
  3. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,589
    They introduced the IProcessScene API in 5.6 or 2017.1, which provides the Scene it's processing on:
    https://docs.unity3d.com/ScriptReference/Build.IProcessScene.OnProcessScene.html

    I haven't used it yet, but it looks like it's a replacement for the PostProcessSceneAttribute.


    Kind of unrelated, but I recommend to at least try/test if loading scenes sequentially improves loading times.

    I loaded 5 scenes in parallel in my game too. I changed it to load scenes sequentially as an attempt to avoid the enormous cost of "asset integration steps". Luckily, it did improve loading times in the editor significantly and causes way less hiccups in the build.
     
    Last edited: Oct 7, 2017
  4. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    Thanks Peter. I'll try the sequential load when I get into the office on Monday.

    I'll also have to see if the IProcessScene will get invoked when playing in the editor too, since we rely on that functionality. (PostProcessScene runs just before we enter the scene so we can prepare the scene the same way we do for a build while we test in the editor.)

    From the documentation description it sounds like it only runs during the build process. (Which would be a shame. I can't think of many/any post processing operations I would only want to run when building.)
     
  5. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,589
    I apply scene post processing when doing a build only.

    The reason behind this approach is to keep "EnterPlayMode" time as fast as possible. I iterate a lot in the editor and every second I don't have to stare at frozen Unity when pressing Play makes a difference for me. :) However, I have several rather expensive processors, such as baking static meshes and the like.
     
  6. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    I see. Haven't thought about using it like that! We use PostProcessScene to generate UGUI elements based on data in our project. For example, we have a tech tree with nodes and connections between nodes defined in a scriptable asset. We have a Tech Tree Generator script that instantiates UGUI UI elements on PostProcessScene in our menu scene to build the tree by reading that data. So every time we build and every time we hit play in the editor, our UI is up to date with the most recent data! (We do more than just a tech tree :) ). Hoping I can reproduce this with IProcessScene.
     
  7. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    @Peter77 I just did a small test, the callback is called when changing scenes in the editor too. :) Sweet!

    I repeated your test, the output is:

    Code (CSharp):
    1.   OnProcessScene: sceneCount=1
    2.     Scene_1
    3. Loading Scene_2
    4. Loading Scene_3
    5. Loading Scene_4
    6.   OnProcessScene: sceneCount=4
    7.     Scene_2
    8.   OnProcessScene: sceneCount=4
    9.     Scene_3
    10.   OnProcessScene: sceneCount=4
    11.     Scene_4
    12. Loading Scene_5
    13.   OnProcessScene: sceneCount=5
    14.     Scene_5
    Code:
    Code (CSharp):
    1. using System.Text;
    2. using UnityEditor.Build;
    3. using UnityEngine;
    4. using UnityEngine.SceneManagement;
    5.  
    6. public class Loader : MonoBehaviour
    7. {
    8.     public static StringBuilder result = new StringBuilder();
    9.     System.Collections.IEnumerator Start()
    10.     {
    11.         yield return null;
    12.  
    13.         result.Append("Loading Scene_2\n");
    14.         UnityEngine.SceneManagement.SceneManager.LoadScene("Scene_2", UnityEngine.SceneManagement.LoadSceneMode.Additive);
    15.  
    16.         result.Append("Loading Scene_3\n");
    17.         UnityEngine.SceneManagement.SceneManager.LoadScene("Scene_3", UnityEngine.SceneManagement.LoadSceneMode.Additive);
    18.  
    19.         AsyncOperation asyncOp = null;
    20.         result.Append("Loading Scene_4\n");
    21.         asyncOp = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync("Scene_4", UnityEngine.SceneManagement.LoadSceneMode.Additive);
    22.         while (!asyncOp.isDone)
    23.             yield return null;
    24.  
    25.         result.Append("Loading Scene_5\n");
    26.         asyncOp = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync("Scene_5", UnityEngine.SceneManagement.LoadSceneMode.Additive);
    27.         while (!asyncOp.isDone)
    28.             yield return null;
    29.  
    30.         Debug.Log(Loader.result.ToString());
    31.     }
    32. }
    33.  
    34.  
    35. class SceneProcessor : IProcessScene
    36. {
    37.     public int callbackOrder { get; private set; }
    38.     public void OnProcessScene(Scene scene)
    39.     {
    40.         Loader.result.AppendFormat("  OnProcessScene: sceneCount={0}\n", UnityEngine.SceneManagement.SceneManager.sceneCount);
    41.         Loader.result.AppendFormat("    {0}\n", scene.name);
    42.     }
    43. }
    44.  
     
    Peter77 likes this.
  8. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,589
    That's great, so it seems to be fixed mostly! What Unity version did you use to run the test?
     
    Last edited: Oct 7, 2017
  9. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    2017.2.0b8 (Little outdated on my home PC ;) )
     
  10. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    Just a note, in 2017.1 IProcessScene is broken :p I was excited to use this instead of PostProcessScene but it doesn't work. When you addtively load scenes, you get an IProcessScene callback for each scene you've loaded, but the scene object being passed in to your callback is the same as the active scene every time. ie Load Scene1 and additive load Scene2 + Scene3 means you get 3 IProcessCallbacks, but if you log out scene.name, it is Scene1 for all 3 calls. :p

    This seems to be fixed in 2017.2.0b8 and up (?) I don't have 2017.2 in the office, we will wait for release candidate 3 before we download and then try it out again.
     
  11. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,589
    I ran into the same issue just a few hours ago! I was updating the code to use IProcessScene and then got the callback for the same scene always, just as you described.

    It's always fascinating how something that seems so simple is just broken. Not only should it easy to test during development, it seems it's also a good candidate for an automated test.

    I'm glad they didn't remove the old API at the same time they introduced IProcessScene, because then we'd be screwed.
     
  12. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    Agreed. Their internal QA seems like it could use a little bit of work. I have no doubt they have some QA, but still - too many little things fly under the radar..

    I remember a few betas back (Maybe for 5.6 beta? Earlier?)... They introduced the ability to create an Editor Script instead of a regular script from the project window context menu. Turned out the developer had left in some test logs... Selecting 'Editor Script' from the context menu would create your script but then it would also log out "Test" as an error in to the console. How did this get past QA? How did this make it to an actual release? Did the developer just push their changes to master and bam! It was in the release, no testing done what so ever?