Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Resolved How to set active occlusion data at runtime for additive scene?

Discussion in 'Scripting' started by Leozzyzheng, Feb 27, 2021.

  1. Leozzyzheng

    Leozzyzheng

    Joined:
    Mar 8, 2019
    Posts:
    16
    I have a Main scene to store some general gameobjects for all game levels and I load scene with LoadSceneMode.Additive so there will be two scenes at a time, one is Main and another is something like Level1. I only load one level scene at a time.

    I need use occlusion culling to get the better performance in each level, but I see the bake data is not used by Unity, I have checked this documentation: https://docs.unity3d.com/Manual/occlusion-culling-scene-loading.html

    I tried this and succeed.

    But it ask me to bake all levels' occlusion data into the Main scene, I think it is unacceptable because each level has its own bake settings, they are different and if I want to re-bake one level, then I need re-bake all levels, the bake time will be every long compared to baking each level only if I changed it. Also I only want to load one level's occulsion data to save memory and I/O.

    I have searched the forum and found someone said if I set the additive level scene active and then Unity will use the bake data from the active scene instead of the first loaded scene. I tried but it still show no bake data in editor.

    So is there any way to let me force Unity choose the correct occlusion bake data at runtime?
     
    LazloBonin likes this.
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,033
    I'm not sure there is... I think it is analogous to the render settings in that only one can be active at a time.

    The reason is that if you compute occlusion you do so in a context, and Unity only builds enough information to be accurate in that context. If you then add extra context (e.g., the second additive scene), the first scene's occlusion would no longer be valid.
     
  3. Leozzyzheng

    Leozzyzheng

    Joined:
    Mar 8, 2019
    Posts:
    16
    I agree with you, but the first scene has nothing to do with the occlusion, there are just some UI gameobjects or virtual cameras, they don't need any occlusion. Just like I move the Don'tDestroyOnLoad to a single scene.

    So in fact I only need use one occlusion at a time even I load more than one scene at a time. Is there any way to do this?
     
    grobonom and LazloBonin like this.
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,033
    I'm sorry, I misread your post: I thought you wanted two scenes with culling to merge at runtime. My bad.

    Now, for one occluded scene among many additively loaded...

    For what you're saying you tried (setting that scene to be active), that's the correct way for setting Lighting / RenderSettings (set the scene active), so I'm surprised that didn't do it.

    When you mark that scene active, did you pause and verify that it really was in the Hierarchy window?

    ALSO: you know you cannot load a scene AND mark it active in the same frame, right? You have to wait for the scene to load (at end of frame), then mark it active, after at least waiting until the next frame. I suppose if it was async streamed in it would take even more time before you can mark it active.
     
  5. Leozzyzheng

    Leozzyzheng

    Joined:
    Mar 8, 2019
    Posts:
    16
    I have checked the Hierarchy and can confirm the additive scene is actived, I also tried to ative the first single scene and active the additive scene again, the lighting changed like what you said but editor always show there is no occlusion data.

    I also found a interested thing is that if I select any gameobject with renderer in the additive scene then the occlusion data is actived and draw calls descreased a lot and editor also show the bake data size.

    BTW, I use Unity2018.4.2, will there be an issue about active operation?
     
    Last edited: Feb 28, 2021
    LazloBonin likes this.
  6. Leozzyzheng

    Leozzyzheng

    Joined:
    Mar 8, 2019
    Posts:
    16
    @Kurt-Dekker I finally found the reason why the active doesn't work. It should be called on the same frame of scene loaded. Which means you need to set the additive scene active immediately after SceneManager.sceneLoaded is called. If you set active only delay one frame, then the occlusion data won't be used by Unity. It was tested on Unity 2018.4, 2019.4, 2020.2.

    God, it is so counter-intuitive.
     
    grobonom and LazloBonin like this.
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,033
    I tend to be lazy and not hook that callback. That callback (.sceneLoaded) is indeed called on (at earliest) the frame after you issue the actual LoadScene() call, or at latest, once the scene is truly loaded in.
     
  8. Leozzyzheng

    Leozzyzheng

    Joined:
    Mar 8, 2019
    Posts:
    16
    The most annoying thing is that Unity doesn't tell anything about the Active behaviour, it should be documented.
     
  9. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,033
    Seems that it should be part of the argument to LoadScene().

    I can see conflicts of course, but at least it would be fire and forget, which is how I always wrap it up: I tend not to use straight LoadScene additives, no async, so I just wait a frame and mark the scene I want as active.

    My scene helper, link inside the source to the CallAfterDelay gist as well:

    https://gist.github.com/kurtdekker/862da3bc22ee13aff61a7606ece6fdd3
     
    IndieFist likes this.
  10. IndieFist

    IndieFist

    Joined:
    Jul 18, 2013
    Posts:
    521
    This could load the occlusion data from any scene? is not required to make occlusion before of all scene in the main active like documentation explain?
    https://docs.unity3d.com/es/2019.4/Manual/occlusion-culling-scene-loading.html

    I want to have an scene, and modify this one loading additive way other scene and import his occlusion data and nav for agents, is possible that?
     
  11. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,033
    I have no idea. Make a quick experiment and find out!
     
  12. IndieFist

    IndieFist

    Joined:
    Jul 18, 2013
    Posts:
    521
    im testing and is not possible >.<
     
  13. LazloBonin

    LazloBonin

    Joined:
    Mar 6, 2015
    Posts:
    818
    I just want to confirm that this works and after a lot of googling, seems like the only fix.

    In my case I have a very complex scene loading setup (multiple asyncs at once, waiting for deserialization before activation, etc, etc.), and the "catch-all" solution I found was to hook SceneManager.sceneLoaded right before my whole loading routine, then unhook it after.

    So for example:

    Code (CSharp):
    1. private static string occlusionScenePath;
    2.  
    3. private static void FixOcclusionCulling(Scene scene, LoadSceneMode mode)
    4. {
    5.     if (scene.path == occlusionScenePath)
    6.     {
    7.         SceneManager.SetActiveScene(scene);
    8.     }
    9. }
    10.  
    11. private static void MyLoading()
    12. {
    13.     occlusionScenePath = // the path of the occlusion scene
    14.     SceneManager.sceneLoaded += FixOcclusionCulling;
    15.     // Your loading rountine here, which may include any number of scenes/async/etc., including the occlusion scene
    16.     SceneManager.sceneLoaded -= FixOcclusionCulling;
    17. }
    18.  
     
    hayashi-hololab and IndieFist like this.
  14. IndieFist

    IndieFist

    Joined:
    Jul 18, 2013
    Posts:
    521
    This is using pre computed occlusion really ?
     
  15. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,434
    Do all the scenes need the same occlusion data then?
    Wait what? I thought that async scene load only worked one scene at a time, each time i tried concurrent scene load it blocked the next one until the previous was active. How did you cast that magic spell?
     
  16. LazloBonin

    LazloBonin

    Joined:
    Mar 6, 2015
    Posts:
    818
    Sorry, not "at once", I just meant to load multiple async scenes in the same stack/setup. My level is layered (like one scene for art, one for audio, one for gameplay, etc.).
     
  17. grobonom

    grobonom

    Joined:
    Jun 23, 2018
    Posts:
    335
    This seems to also work for me.
    I'm in the same case as you're: 1st scene is my loader and entry menu. My real scenes are loaded/unloaded by this menu.
    I hardly struggled on this topic ! Mostly like if unity users ( and unity devs ) only use one scene for everything.
    Now things look better:
    one scene ---> one occlusion
    this will allow me to have multiple new scenes in the future without having to rebake everything in a nonsense way.

    Thanks and happy unitying !
     
  18. eliteforcevn

    eliteforcevn

    Joined:
    Oct 25, 2018
    Posts:
    47
  19. Alex_Heizenrader

    Alex_Heizenrader

    Joined:
    May 16, 2019
    Posts:
    97
    This should be documented somewhere. Setting an additive scene as active right with the sceneLoaded callback does indeed load the occlusion culling data. Thank you to the ones that found out
     
  20. URGr8

    URGr8

    Joined:
    Sep 10, 2012
    Posts:
    25
    Wow, this is crazy that you have to do this, but it does work to set it active after the first frame. Here is my code that works. I have other scenes and then load this one last.

    Code (CSharp):
    1.         AsyncOperation asyncOperation = SceneManager.LoadSceneAsync(level, LoadSceneMode.Additive);
    2.         asyncOperation.allowSceneActivation = false;
    3.         while (!asyncOperation.isDone)
    4.         {
    5.             percentageDoneText = ((int)(100f * asyncOperation.progress / .9f)).ToString() + "%";
    6.             SetLoadingLabel($"LOADING Level {percentageDoneText}");
    7.             // scene has loaded as much as possible, the last 10% can't be multi-threaded
    8.             if (asyncOperation.progress >= 0.9f)
    9.             {
    10.                 // we finally show the scene
    11.                 asyncOperation.allowSceneActivation = true;
    12.             }
    13.             yield return null;
    14.         }
    15.         //IMPORTANT
    16.         //NOTE - Seems that you have to set the scene active on the first frame after loading or the Occlusion data will not load properly...
    17.         SceneManager.SetActiveScene(SceneManager.GetSceneByName(level));