Search Unity

Graphics [RELEASED] Perfect Culling - Pixel Perfect Occlusion Culling

Discussion in 'Tools In Progress' started by PatrickKa, Apr 18, 2021.

  1. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    This doesn't seem related to Perfect Culling because ftraceLightmaps seems to be part of Bakery. I was unable to reproduce the issue on my side. Maybe try to update Bakery and/or ask in the Bakery support chat whether this is expected. I'd imagine that the error might be harmless but I don't know for sure.
     
  2. wj640520

    wj640520

    Joined:
    Jun 9, 2017
    Posts:
    6
    Yes, it's the Bakery that causes the error to happen. I will try to ask Bakery support chat to get help. Thanks, Patrick!
     
  3. VoxelBoy

    VoxelBoy

    Joined:
    Nov 7, 2008
    Posts:
    240
    It looks like the BitStreamReader could be optimized. Making function calls to read single bits seems a bit wasteful.

    This screenshot is from Deep Profiling in the Unity Editor and the PerfectCullingVolume info is shown in the Inspector on the right side:
    upload_2022-2-28_10-7-41.png
     
    Lars-Steenhoff likes this.
  4. VoxelBoy

    VoxelBoy

    Joined:
    Nov 7, 2008
    Posts:
    240
    Also, am I right in assuming that this system does not consider shadows when calculating which renderers are visible from which cells?
     
  5. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    Are you currently experiencing performance issues related to this code path? It should be called rather infrequently but I'm sure there is more room for optimizations. I made a note to have another look but I remember that I manually inlined ReadBit in the past and it was not worth the messy code. Potentially could create a bit mask to read multiple bits at once though.

    That is correct. I was actually trying to implement that but I quickly realized that I'm not brave enough to enter the fight with various render pipelines.

    However you can open PerfectCullingConstants.cs and change the ToggleRenderMode to ToggleShadowcastMode. This would set the ShadowCastingMode to ShadowsOnly instead of disabling the renderer thus still allowing for shadows.
     
  6. athert

    athert

    Joined:
    Dec 31, 2012
    Posts:
    36
    Heya!
    Im playing just few hours with this asset but i found myself really confused about why some of my objects are or are not culled. There are objects behind walls and even terrains that are still visible (I added exclude floating sampling provider and exclude below collider array sampling provider so there are no probes below terrain that should cause this issue). Is there any debug better than visually looking at colors from sampling position? And if not, can you please tell me if there will be some in near future? It would be really great to have option where i can select probe, then object i want to debug and somewhere will be visible why this exact object is visible or not.
    Here i can send you screenshot of object in building that should not be visible at all but for some reason, its still on.
    (merge-downsample is 0 and include neighbor cell radius is 1. If i understand correctly, its looking at 3x3x3 probes around one that i have selected and enabling them too, or not?).
    upload_2022-3-3_2-35-5.png
    I know this will not probably tell you much but im just showing this as example where im struggling.

    Also, i thought that if i set merge-downsample to 1 and include neighbor cell radius to 0 then its same as if i will set merge-downsample to 0 and include neighbor cell radius to 1 but when im testing it, im getting different results. when merge-downsample is set to 0 and include neighbor cell radius to 1, im getting much more "correct" results but of course it will eat much more space. Is this something i understand incorrectly?
     
  7. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    Hey,

    I definitely have plans to add more debug options.

    The merge-downsample and include neighbor cell radius are very similiar but not 100% identical due to performance constraints at run-time. So you can see slightly different behaviour.
    Generally you should always use merge-downsample though and only use include neighbor cell radius as an additional debugging tool.

    Did you try to look into the Troubleshooting documentation? I'd recommend to enter play mode, select the Perfect Culling Volume and hit the Replace all renderers with bake material.

    This allows you to check that:
    a) the desired renderers have been added to the volume by observing that they changed color
    b) they are correctly rendering as opaque/transparent
    c) there is no issues with flipped normals, double sided meshes, etc.
    d) manually confirm the view is indeed blocked from the problematic position (align camera with closest cell on the Perfect Culling Camera is very helpful here)

    If your renderer can be seen through the window chances are that the neighbor cell sees it but it gets pulled in due to merge-downsample or include neighbor cell radius.

    So another test would be to set merge-downsample to 0 and set include neighbor cell radius to 0. You might see culling artifacts but this should be the raw culling output without any processing.

    The merge-downsample step effect should also be visualized and there is an additional documentation for Merge-Downsample so maybe look into that as well.

    If you cannot figure it out but you are able reproduce the problem in a small scene feel free to send it to me and I will look into it for you in-depth.
     
  8. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    I took action based on your feedback and the current release 1.1.5 introduces an alternative code path that does not need the ReadBit() method anymore.
    Because this is a very recent change in a critical part of the asset that is still being tested it is currently locked behind a flag. So after updating to 1.1.5 just open PerfectCullingConstants.cs, scroll to the bottom and set the flag ReadMultipleBitsInBitStream to true. Let me know if that helps.

    Everybody else is of course also welcome to make this change. Of course, this behaviour will become the new default behaviour in future versions after stability was confirmed. I don't even expect any problems but I just wanted to make sure. :)
     
    PutridEx likes this.
  9. JustinAHS

    JustinAHS

    Joined:
    Feb 18, 2013
    Posts:
    33
    I just bought and tinkered with the asset for a bit. Here are my thoughts,

    I had to modify `IsMaterialTransparent()` because it was assuming some materials were transparent when they were not. In my case, I had hundreds of materials and didn't want to use the pc_opaque workaround. But, like you said, "It's pretty hard to detect transparent materials." And modifying the method was painless.

    ---

    I tried the portal cell feature and it's useful!
    I think it would be more useful if we could also "cull" the portal cell.
    So, if the portal cell is not visible, then we also cannot see anything the portal cell can see.

    1. Create volume A
    2. Create volume B
    3. Create portal cell and set the culling volume to volume A
    4. Maybe set "culler volume" to volume B?
    5. Bake volume B

    When volume B says portal cell is not visible, then we cannot see anything in volume A.
    In my case, I would also like the "culler volume" to have multi-scene support.
    I think I would have references use strings for the name of the culler volume since mult-scene references aren't supported.

    Maybe I'll try implementing this on my own since the code seems pretty clean and extensible!

    ---

    The tutorial video was excellent at helping me set up everything, and the documentation was also good enough to answer my questions about portal cells and multi-scene culling.

    Thank you for this asset!
     
  10. JustinAHS

    JustinAHS

    Joined:
    Feb 18, 2013
    Posts:
    33
    I got a hacky solution working for portals.

    I have two scripts,
    1. CullListener (attach to a renderer in the "culler" volume)
    2. BindPortalCellToCullListener (attach to the portal of the culling volume)

    And I also modify PerfectCullingBakeGroup.Init() and PerfectCullingBakeGroup.Toggle()
    1. In Init(), build List<CullListener> from array of renderers
    2. In Toggle(), call CullListener.SetEnabled(isVisible)
    3. Set the culling volume out-of-bounds behavior to "Cull"

    Code (CSharp):
    1.  
    2. public class CullListener : MonoBehaviour
    3. {
    4.     public delegate void EnabledChangeDelegate(CullListener listener, bool enabled);
    5.     public event EnabledChangeDelegate OnEnabledChange = null;
    6.  
    7.     public void SetEnabled (bool enabled)
    8.     {
    9.         if (OnEnabledChange != null)
    10.         {
    11.             this.enabled = enabled;
    12.             OnEnabledChange(this, enabled);
    13.         }
    14.     }
    15. }
    16.  
    Code (CSharp):
    1.  
    2. public class BindPortalCellToCullListener: MonoBehaviour
    3. {
    4.     //Could also use GetComponent()
    5.     public PerfectCullingPortalCell portalCell;
    6.     public string targetCullListenerName;
    7.  
    8.     private CullListener cullListener = null;
    9.  
    10.     public void OnEnable()
    11.     {
    12.         SceneManager.sceneLoaded += OnSceneLoaded;
    13.         InitCullListener();
    14.     }
    15.  
    16.     public void OnDisable()
    17.     {
    18.         SceneManager.sceneLoaded -= OnSceneLoaded;
    19.         if (cullListener != null)
    20.         {
    21.             cullListener.OnEnabledChange -= OnEnabledChange;
    22.             cullListener = null;
    23.         }
    24.     }
    25.  
    26.     public void OnSceneLoaded(Scene scene, LoadSceneMode mode)
    27.     {
    28.         InitCullListener();
    29.     }
    30.  
    31.     private void InitCullListener ()
    32.     {
    33.         if (cullListener != null)
    34.         {
    35.             return;
    36.         }
    37.  
    38.         cullListener = GameObject.Find(targetCullListenerName).GetComponent<CullListener>();
    39.         if (cullListener != null)
    40.         {
    41.             portalCell.enabled = cullListener.enabled;
    42.             cullListener.OnEnabledChange += OnEnabledChange;
    43.         }
    44.     }
    45.  
    46.     public void OnEnabledChange (CullListener cullListener, bool enabled)
    47.     {
    48.         portalCell.enabled = enabled;
    49.     }
    50. }
    51.  
    When renderer is visible, portal cell is enabled.
    When renderer is invisible, portal cell is disabled.
    When portal cell is disabled and player is out-of-bounds, the entire volume is culled.

    This hack requires that the CullListener game object have a unique name throughout the entire game.
     
    PatrickKa likes this.
  11. bonickhausen

    bonickhausen

    Joined:
    Jan 20, 2014
    Posts:
    115
    Hiya!

    Your asset seems really neat. Does it work with Culling Groups?
     
  12. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    It should work for frustum culling but the occlusion culling part requires to use Unity Occlusion Culling (Umbra).
     
  13. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    Thank you for sharing your code. Really appreciate and hopefully useful for other people, too!

    Probably you can also solve it using a PerfectCullingSceneGroup script. Just add it to the scene and assign the renderer that should drive the PortalCell as the one and only element into the first array called renderers. The PortalCell should go into the second array called unityBehaviour. This is a very recent feature and not well documented but there is a demo scene called Demo_UnityBehaviours that uses this concept to cull a Light and toggle a script.

    For this to work properly you need to clear all renderers, add them back to the volume and re-bake though. It also does not support cross scene references. So your solution might be much more flexible and not that hacky really :)
     
    Last edited: Mar 9, 2022
  14. Lars-Steenhoff

    Lars-Steenhoff

    Joined:
    Aug 7, 2007
    Posts:
    3,527
    I'm also planning to buy a Mac Ultra with 20 Core CPU, Is the culling baking able to use all cores?
     
  15. VoxelBoy

    VoxelBoy

    Joined:
    Nov 7, 2008
    Posts:
    240
    Hey @PatrickKa, that's great to hear. I've shortly tested it in my project and the new code path works without problems. Thanks!
     
    PatrickKa likes this.
  16. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    The baking process for Perfect Culling actually also utilizes the GPU (for rasterization and compute shaders). So it also depends on the GPU. Because internally the baking uses the Unity Engine I also do not have any inside to what Unity can or cannot do here but I'd assume that it would try to maximize CPU usage especially if you make sure to select a modern Graphics API such as Vulkan or Metal and you use a recent Unity version.

    The bake steps that I was able to multi-thread are multi-threaded though (such as the Merge-Downsample step). Generally the fact that most of the Unity API can only be called from the Main Thread makes this pretty hard though.
     
    Lars-Steenhoff likes this.
  17. JohnAustinPontoco

    JohnAustinPontoco

    Joined:
    Dec 23, 2013
    Posts:
    283
    Wonderful asset! So much better than Umbra.

    Quick question. I have a decent number of groups of objects (ie. a room) where each is part of a big LOD Group. This is so that when you are far away from that room, the entire room gets swapped for a single mesh. But up close, I still want objects to be culled individually.

    From what I can read in the Docs, every lod group will be treated as a single object for the purposes of LODing. Is there any way to disable that?
     
  18. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    Do you know how to write/understand C#? Because if so it should be a matter of just opening PerfectCullingUtil.cs and adjusting the CreateBakeGroupsForRenderers function.

    Maybe something like this would do (only added a single line; remaining code for reference; should be round about line 76 in the file):
    Code (CSharp):
    1. // LODGroup
    2. foreach (LODGroup lodGroup in lodGroups)
    3. {
    4.    // vvv This line was added vvv
    5.    if (lodGroup.name.Contains("[PC_SKIP]")) continue;
    6.  
    7.    HashSet<Renderer> renderersInLodGroup = new HashSet<Renderer>();
    8.  
    Now LODGroups containing the word [PC_SKIP] (case-sensitive) in the name of the GameObject should be skipped and all the Renderers should be individual objects again. I haven't tested this though.

    Of course, you could also disable the entire foreach loop but I'd not recommend doing that because the advantage of treating LODGroups as a single object (as far as Perfect Culling is concerned) are:
    - Requires less memory
    - Allows to give back control to the LODGroup

    Important: You will need to Clear all renderers from your Perfect Culling Volume and add them back in for this change to take effect.

    Let me know if that helps and/or you need more assistance with this. :)
     
  19. JustinAHS

    JustinAHS

    Joined:
    Feb 18, 2013
    Posts:
    33
    I'm noticing a weird bug with the GetBakeHash().
    I tried to compare the editor GetBakeHash() and the bakeHash on the BakeData.
    upload_2022-3-15_15-44-52.png

    For some reason, the bakeHash is being set to a negative number when baking, but not in the editor.
    upload_2022-3-15_15-45-23.png

    I'll try and debug this a bit more but just thought I'd give you a heads up.

    [Edit]
    I am not using any additional occluders.
    I am using LOD groups.
    I have tried clearing renderer groups and re-adding them.
    I re-baked multiple times.
     
    Last edited: Mar 15, 2022
  20. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    Did you try to just bake again? The hash being negative is not a bug but is expected due to integer overflow and is not a concern at all :)

    It would be a bug if the warning does not go away after re-baking. If you updated to the most recent version it might have caused the hash difference because I had to fix an issue in a hash function so the hash might be slightly different now even though nothing changed.
     
  21. JustinAHS

    JustinAHS

    Joined:
    Feb 18, 2013
    Posts:
    33
    upload_2022-3-15_16-5-27.png

    I gave the diff a quick look over.
    The even numbered lines are groupType.
    The odd numbered lines are renderers.Length.

    Every single diff was for odd numbered lines.
    So, renderers.Length seems to be different in the editor vs bake.

    The LHS is editor.
    The RHS is bake.

    Every time there is a diff, it looks like the groupType is zero, or GroupType.Other.

    I've rebaked multiple times. And I'm on 1.1.5
     
  22. JustinAHS

    JustinAHS

    Joined:
    Feb 18, 2013
    Posts:
    33
    I think it might have to do with "Render Double Sided"?
    upload_2022-3-15_16-10-5.png

    [Edit]
    Confirmed. It's Render Double Sided.
    upload_2022-3-15_16-17-9.png

    For every diff, Render Double Sided is always true.

    The code I used to build the string,
    Code (CSharp):
    1.  
    2.  
    3.                 for (int i = 0; i < bakeGroups.Length; ++i)
    4.                 {
    5.                     hash = hash * 53 + (int)bakeGroups[i].groupType;
    6.                     hash = hash * 23 + bakeGroups[i].renderers.Length;
    7.                     sb.AppendLine(((int)bakeGroups[i].groupType).ToString());
    8.                     sb.AppendLine(bakeGroups[i].renderers.Length.ToString());
    9.  
    10.                     if (
    11.                         bakeGroups[i].groupType == PerfectCullingBakeGroup.GroupType.Other &&
    12.                         bakeGroups[i].renderers.Length == 2
    13.                     )
    14.                     {
    15.                         var c = bakeGroups[i].renderers[0].GetComponent<PerfectCullingRendererTag>();
    16.                         if (c != null)
    17.                         {
    18.                             sb.AppendLine("c: " + c.RenderDoubleSided.ToString());
    19.                         }
    20.                         var c2 = bakeGroups[i].renderers[1].GetComponent<PerfectCullingRendererTag>();
    21.                         if (c2 != null)
    22.                         {
    23.                             sb.AppendLine("c2: " + c2.RenderDoubleSided.ToString());
    24.                         }
    25.                     }
    26.                 }
     
    Last edited: Mar 15, 2022
  23. alexis78963_unity

    alexis78963_unity

    Joined:
    May 9, 2019
    Posts:
    14
    Hello,

    We are very interested in using your asset for our project but we are not sure if it would fit.

    We are using mirrors that are instancing cameras in real time. With the default Unity occlusion culling and with other assets we had the issue that the culling didn't detect the objects seen by the mirror. And therefore culled more objects than we wanted and broke our mirrors.

    Do you think there is a way to use your assets with Mirrors?

    Thanks for your great asset!

    Note: We are using mirrors in VR but I don't think this changes anything
     
  24. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    Thank you very much for providing all the information. I'm able to reproduce the issue and will look into it in-depth.
    For now this should not impact the baked data or culling but just result in an unwarranted warning due to the hash change. I will keep you updated.
     
  25. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    Currently this is not supported but if you are willing to make some changes it should in fact work.

    The changes you most likely would need to make:
    - Change the code to not disable the additional Camera used for the mirror
    - Make sure the Camera used for the mirror has Clear Color set to pure black (you don't want any Skybox, etc.)
    - Make sure no other effects are rendered. The camera needs to output the raw color values without modifying them.
    - Change the code to not swap the material for the mirror renderer
    - Use an unlit shader for the mirror renderer (no shading, you want pure colors)

    Or in other words: As long as you make sure that your shader outputs pure colors without shading, etc. and Perfect Culling does not disable/replace your camera and custom shader it should work just fine. By the way some customers also created custom shaders that would cull objects hidden by fog. You can do all of that, too. Just important to output pure colors to make it work.

    VR does indeed not change anything here. I put this on my list of features for a future update but don't have an ETA yet but maybe you can get started on it earlier yourself. I will keep you updated though.
     
  26. alexis78963_unity

    alexis78963_unity

    Joined:
    May 9, 2019
    Posts:
    14
    Got it, thanks a lot for your very quick and detailed answer!
     
  27. JohnAustinPontoco

    JohnAustinPontoco

    Joined:
    Dec 23, 2013
    Posts:
    283
    Thanks! That should help me figure out LODs.

    I recently discovered that there's an import error in the asset. We see this locally and on our build server, on Unity 2020.3.17f1.
    "Unknown error occurred while loading 'Assets/Plugins/Koenigz/PerfectCulling/Resources/Perfect Culling/PerfectCulling ColorTable.asset'."

    It seems like a fairly straightforward ScriptableObject, so I really don't know what's wrong. :\
     
  28. JohnAustinPontoco

    JohnAustinPontoco

    Joined:
    Dec 23, 2013
    Posts:
    283
    Ah! Turns out that file was being tracked as text, not binary in Git LFS. Our fault.
     
    PatrickKa likes this.
  29. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    Just a heads up that version 1.1.6 was released and is available on the Unity Asset Store and should fix your issue.
     
  30. sameng

    sameng

    Joined:
    Oct 1, 2014
    Posts:
    184
    I just bought Perfect Culling, thank you! It works well. It's so much better than Umbra.

    I have some questions. No rush, please answer on your own time.

    1. What's the bottleneck for baking times? Is it mostly GPU? Just for future reference, I'd like to know what to optimize for when I get my build machine up.

    2. Is there a way to clear and refresh the renderers automatically upon bake? I have a few assets that seem to generate objects upon entering/exiting play mode (dynamic meshes) such as Curvy or Volumetric Light Renderer.

    The problem here is that the bake groups list gets filled with some empty null renderers every time I play in the editor.

    It is arduous adding objects one by one, so I do the select-all-renderers click add. However I have to do this every time, for every volume. Is it possible to do it for all volumes in one go? (Add all renderers, then bake)

    3. How does multi-volume work exactly?
    I have a wide spaced, overhead volume, and a close to the ground, high resolution volume.
    Of course, I would only want the volume that the camera is in, to take effect. The volumes do not overlap. Does this work properly? I'm not sure if it's something wrong with my setup, but when I enable/disable the big volume while the player is on the ground, things still get occluded/unoccluded, even though the camera is firmly in the ground volume.

    4. Are there any plans for a macOS native version for the speed up?
    I saw there was a windows native version, is there any chance there will be a native mac version?

    5. Is it possible to manually provide an array of sample points?
    This is sort of a pie-in-the-sky so no worries. But for example, if the player is on a spline, would it be possible to generate sample points only along the spline? My level is quite large, so making a massive volume encapsulating the entire spline is prohibitively big. I thought of using Multi-volume (maybe a volume every 100 units) essentially voxelizing the spline. Is that the way to go?

    Thank you again for making Perfect Culling. It's the best culling system I've ever used!
     
  31. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    Thank you. Glad you enjoy it so far! Maybe consider writing a review to share your experience for even more people to see :)

    1. This is mostly about the GPU but of course in order to keep the GPU busy you also need a decent CPU that can push more work to the GPU. So you should try to pair a good GPU with a good CPU.

    2. That is strange because the bake groups should not change unless you manually add renderers to the bake group. So I'm wondering how they make it in.

    However you can add a PerfectCullingRendererTag and check "Exclude from bake" to make sure you never select them accidentally. Maybe that is enough to solve the problem?

    3. The problem with multi-volume setups is that you ideally do not want them to operate on the same set of renderers because they might disagree with each other.
    Other than that this setup should work. If you can reproduce it in a stripped down project I'd be able to look into it in-depth.

    4. I'm actually considering to get rid of the native renderer because baking became much much faster in more recent Unity versions and a native renderer is pretty much a black box.

    Keeping everything inside Unity allows for custom shaders and project specific modifications. This is pretty much impossible with the native renderer.

    But I'd be happy to hear more opinions on that because it would be a compromise between bake speed and extensibility.

    5. Right now there is no built-in feature for that but you have a couple of options here:
    - You could use a PerfectCullingVolume and write a custom SamplingProvider to exclude all cells that are too far away from the spline (see documentation Exclude cells - Sampling Providers for further information)
    - You could leverage Perfect Culling only to gather visibility information but handle everything else yourself. There is actually an API function for that.

    Basically you pass in the relevant renderers and the view point position and it will return a HashSet containing visible renderers:
    Code (CSharp):
    1.  
    2. // PerfectCullingAPI.cs
    3. /// <summary>
    4. /// Allows to bake a single view point. This might be handy for some editor utilities.
    5. /// WARNING: THIS CHANGES YOUR SCENE!!!
    6. /// </summary>
    7. public static HashSet<Renderer> BakeSingleViewPointNow(Vector3 position, List<Renderer> inputRenderers)
    This wasn't made for baking multiple positions so it might be a bit slow to call this over and over again because it goes through the full setup process again and again but maybe it works for your use-case? Might be worth a try. :)

    - You could inherit PerfectCullingBakingBehaviour and write a custom behaviour for splines
    - You could use multiple PerfectCullingVolume and just toggle them on and off

    I think the first approach might be best. Of course, there is some overhead for empty cells but it might be negligible.

    I hope this helps but feel free to ask for more information :)
     
    Last edited: Mar 18, 2022
    sameng likes this.
  32. sameng

    sameng

    Joined:
    Oct 1, 2014
    Posts:
    184
    I think that's what is happening in my scene--the two volumes are disagreeing and some things that should be visible from the ground are occluded from the air, and thus it's occluded on the ground as well. I sent you a repro to info@koenigz

    So it's better to enable/disable volumes based on where the camera is? It would be great to have a sort of "priority system" for this scenario, or for the system to select the closest volume.

    Thank you for the in-depth response. I'll be happy to leave a review. :)

    EDIT: Maybe a feature for CameraOutOfBoundsBehaviour -> Cull Nothing would fix my multi-volume woes?
     
    Last edited: Mar 18, 2022
  33. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    Just coming back to this thread to let you know I answered your mail and I think I pretty much added what you suggested in your edited post. The updated scripts have been included in the mail. :)
     
  34. littenli

    littenli

    Joined:
    Dec 18, 2019
    Posts:
    33
    Hi, I have a forest scene with trees that can be cut down.
    I pre-baked the forest scene. My question is, when removing a tree gameObject, is there an API to remove the corresponding baked data?
     
    Lars-Steenhoff likes this.
  35. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    You want to remove a Renderer at run-time or you already baked a scene and you want to remove a Renderer at edit-time so you don't need to re-bake? Or something very different?

    There is an API to add/remove renderers at run-time:
    Code (CSharp):
    1.  
    2. PerfectCullingAPI.BakingBehviour.FindBakeGroupWithRenderer(PerfectCullingBakingBehaviour behaviour, Renderer r, List<PerfectCullingBakeGroup> result)
    3.  
    4. PerfectCullingAPI.BakeGroup.AddRenderer(PerfectCullingBakeGroup group, Renderer r)
    5. PerfectCullingAPI.BakeGroup.RemoveRenderer(PerfectCullingBakeGroup group, Renderer r)
    6.  
    However this API does not work at edit-time (probably should make that more clear). For edit-time you can directly grab the bakeGroup array held by the PerfectCullingVolume and remove renderers from it.

    In any way keep in mind that this does never changes the occlusion data itself. If you remove a Renderer Perfect Culling will no longer control it but if this object occluded other objects this information is still unavailable and the only way to bring it back (or rather create it in the first place) is to bake without the Renderer.

    I hope this makes sense but feel free to describe in more detail what your use-case is because I might have missed the point completely. o_O

    EDIT: Sorry, I skipped over the cut down sentence. I guess that definitely implies run-time. In this case I'm afraid you would need to exclude the trees from the bake (you can use the PerfectCullingRendererTag component for that) because everything behind them would still be culled even after removing the Renderer from Perfect Culling. The information for objects behind the trees simply doesn't exist. :(

    Though I'm wondering if you could bake the scene twice (with and without trees) but this probably requires some engineering on your side... But maybe an interesting idea to try :)

    Hmm, but that might potentially also fail because maybe some trees further away had been cut down, too. So probably not possible without baking all permutations and that is most likely unfeasible.
     
    Last edited: Mar 27, 2022
    littenli likes this.
  36. joshcamas

    joshcamas

    Joined:
    Jun 16, 2017
    Posts:
    1,278
    Hello, I have a game that consists of hundreds of "chunks", each being a different scene. Does this baking modify the scene itself? Cause naturally having hundreds of modified files to deal with when I have a team isn't super viable.
     
  37. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    Maybe. It might need to modify the scene to update some settings such as the referenced bake data, etc. If no settings changed only the bake data should need to be updated though. The bake data is stored in a separate ScriptableObject and not part of the scene.
     
    joshcamas likes this.
  38. joshcamas

    joshcamas

    Joined:
    Jun 16, 2017
    Posts:
    1,278
    I see! This looks amazingly powerful :) Non baked meshes cannot be occluders and cannot be ocludees, correct?
     
  39. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    You can pass in "Additional Occluders" and they will be occluders but not occludees because the reference is only used during the bake process and they are not controlled by the asset. This is useful for chunks because you can add renderers from other chunks and have objects culled by other chunks even though they are not loaded - this information simply is baked in.

    For this to work properly you need to bake a volume that is larger than the chunk itself so there is some "outside" and overlapped information.
     
  40. ErosInteractive

    ErosInteractive

    Joined:
    Oct 31, 2016
    Posts:
    1
    Sorry to bug you with a rudimentary question, but: originally my FPS was only going to involve outdoor play. Now I'd like to be able to include indoor (building interior) play as well.

    What would be the best way to tackle culling setup for both a decent-sized city grid and many traversable buildings within that city?
     
  41. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    It really depends on many factors such as:
    - What does decent-sized really mean?
    - Are you loading and unloading level chunks dynamically?
    - What is your target platform and what is your memory budget?
    - Would larger bake times slow down your iteration time?
    - Are there any restrictions for player movement or can the player fly through the sky as well?

    In the most simple setup you would use a single PerfectCullingVolume that covers your playable area. In addition to that you would exclude cells the player cannot reach (for instance up in the sky, etc.). Because the interior would also be contained in the volume it would not require any special treatment. The setup is basically the same with and without interior.

    If your level is very large and you cannot exclude any cells the bake process might take very long. If you need to iterate fast this might be a concern. If you cannot exclude cells because the player can reach everywhere there is not really anything you can do to bake faster because you need this information. In this case you could consider to only use Perfect Culling for the interior and use a different occlusion culling system for the outdoor level.

    But yeah this is a pretty lengthy answer but at the end of the day it depends on the design of your game. If you are making more of an open-world game you might want to look into a fully dynamic occlusion culling system that can also occlude moving vehicles, etc. This will most likely consume 1-2 ms of CPU/GPU time but it might be worth it for an open-world game and gets rid of the bake process.
     
  42. Jakub_Machowski

    Jakub_Machowski

    Joined:
    Mar 19, 2013
    Posts:
    647
    hello does the system works with additive loaded scenes? Also is there a ltot of reconfiguration when using unity build umbra in already?
     
  43. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    Yes. In the most simple setup you would just add a PerfectCullingVolume to all scenes and bake them individually. Culling would be constrained to each individual scene though. In a more complex setup you would also have a PerfectCullingVolume in all scenes but you would make it slightly larger than the playable area. Now you would load all scenes and use the Perfect Culling Bake menu option and select Bake All. This will essentially bake information from other scenes into the occlusion data so they can cull based on information from other scenes.

    There shouldn't be a need for too much reconfiguration.

    I also attached some of the documentation. I figured that might be helpful.
     

    Attached Files:

  44. Notso

    Notso

    Joined:
    Oct 25, 2015
    Posts:
    44
    Hello! I sent an email then found the forum here :)
    So a copy/paste of what I sent:

    Just purchased it today and watched your quick start.
    I keep getting this:

    Exception: GPU returned duplicates. This should never happen. Please re-bake and try to restart Unity if this keeps on happening please file a bug report. Values: 0 and 0, Indices: 0 and 1
    Koenigz.PerfectCulling.PerfectCullingBakerHandle.Complete () (at Assets/Plugins/Koenigz/Perfect Culling/Scripts/PerfectCullingBakerHandle.cs:32)
    Koenigz.PerfectCulling.PerfectCullingBakingBehaviour.CompletePending (System.Collections.Generic.List`1[T] pending) (at Assets/Plugins/Koenigz/Perfect Culling/Scripts/PerfectCullingBakingBehaviour.cs:396)
    Koenigz.PerfectCulling.PerfectCullingBakingBehaviour+<PerformBakeAsync>d__18.MoveNext () (at Assets/Plugins/Koenigz/Perfect Culling/Scripts/PerfectCullingBakingBehaviour.cs:299)
    Koenigz.PerfectCulling.PerfectCullingBakingManager.EditorUpdate () (at Assets/Plugins/Koenigz/Perfect Culling/Scripts/PerfectCullingBakingManager.cs:209)
    UnityEditor.EditorApplication.Internal_CallUpdateFunctions () (at <86dcbaabb0ba406bb15eebecad12f7c0>:0)

    I have restarted 3 times and even made sure only assets with visible mesh were selected (such as not selected enviro weather objects or empties that hold scripts etc..) to eliminate those as an issue.

    So of course since I got that it says the bake failed or corrupted, and that is obvious on play mode, it culls the scene, and never renders it back haha.
     
  45. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    Hey,

    What is your Unity version? Are you on Windows? What is your hardware?

    Could you also try to verify whether the demo scenes bake and work for you?

    I also received your mail but I'm answering here if that is okay for you :)
     
  46. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    Could you also double check that you are indeed using the latest version (1.1.7).

    You can verify this by opening the settings (search for it in the project or select Perfect Culling in the menu and then select Settings).
     
  47. Notso

    Notso

    Joined:
    Oct 25, 2015
    Posts:
    44
    yeah, here is fine, I would have sent here first if I seen it.
    I used the demo_prefabs scene and it seemed to bake without issue.
    I figured my next test would be to just select the large buildings to see if they bake...try to narrow down what it is causing this but could take some time.
    I forgot to paste that info here...
    2021.2.17f1
    Win11
    RTX2080 gpu
    Core i9 9900K
    64gigs Ram
     
  48. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    Hmm. All things considered it definitely sounds like it is triggered by something that is specific to your scene then. If there is any way for you to package it up and send it my way I'd also dig into it myself so you don't need to do it (assuming that the issue also reproduces on my side).
     
  49. PartyBoat

    PartyBoat

    Joined:
    Oct 21, 2012
    Posts:
    97
    Hi! I was wondering how well this asset handles procedurally generated content. I have a project where the base scene is static geometry but I procedurally place many static props to decorate the scene at runtime. Looks like this asset doesn't handle dynamic objects like physics objects, characters, etc. but it does allow baking prefabs. If my prefabs are static prop objects like paintings, tables, light fixtures, etc. that are placed procedurally at runtime but don't move thereafter will the prefab baking work for my case and properly cull these elements?
     
  50. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    245
    The first step would be to bake the static geometry.

    Now you spawn the random prop and you find a renderer that is nearby. You search for this renderer in the bakeGroups stored on the PerfectCullingVolume and you simply add your renderer into the same bakeGroup. What this does is that when the nearby renderer becomes visible your dynamic object will also become visible.

    If you place objects in pre-defined locations you probably could just add a placeholder cube (maybe add a PerfectCullingRendererTag to make it transparent) and bake that. Now you will have even more precise visiblity information for this area and you could again find this renderer at run-time, remove it and add the real object.

    Generally when it comes to prefab what is meant is that you have a part of a level that is a prefab and you can bake culling information for this prefab. If your prefab is just a painting then this doesn't really help you here.