Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Have a look at our Games Focus blog post series which will show what Unity is doing for all game developers – now, next year, and in the future.
    Dismiss Notice

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:
    202
    pc_1950_1300_2.png

    Perfect Culling
    enables you to bake pixel perfect occlusion data for prefabs and your scene. It works by assigning unique colors to all renderers and taking pictures from multiple perspectives. At the end the colors found in the images allow the asset to tell whether a renderer was visible or not.

    Features:
    - Supports transparency
    - Supports multiple cameras
    - Supports pre-baking occlusion for prefabs and instantiating them at run-time
    - Pixel perfect thus very predictable results
    - Support for all build platforms
    - Support for built-in and HDRP/URP render pipelines
    - No performance overhead on GPU and almost no performance impact on CPU at run-time
    - Easy to setup

    Perfect Culling cannot be used to cull objects that have not been baked but only works with baked prefabs and/or scenes.

    Available on the Asset store here:
    https://assetstore.unity.com/packages/tools/utilities/perfect-culling-occlusion-culling-system-193611

    Video that shows how to get started using this asset:


    Short demonstration of what the occlusion culling looks like:


    I hope all of this information gives you a good idea what Perfect Culling is and whether you want to give it a try after it released on the Unity Asset Store.

    I'm definitely interested in what you all think and I'm also very happy to answer questions and respond to your feedback!
     
    Last edited: Aug 8, 2021
  2. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    [RESERVED]
     
  3. niv-

    niv-

    Joined:
    Apr 20, 2021
    Posts:
    10
    Howdy o/

    looks cool, ive got a couple of questions.

    Whats the performance like and is the color lookup real time?
    if so how are you checking what colors are in view?
    also is there a limit to how many unique renderers can be culled?
     
  4. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    Hey,

    The color stuff only happens during occlusion bakes in the Unity Editor. The basic steps are:
    • Save scene
    • Generate a list containing unique colors and apply them to the renderers
    • Setup a camera with 90° field of view
    • Place the camera at the desired sampling position
    • From all 6 angles take a screenshot and write it into a RenderTexture that lives on the GPU
    • Dispatch compute shader that tests all pixels in the RenderTexture and returns the unique colors
    • Now we got a list of colors that we can match back to the color list created earlier
    • The list of visible renderers is written to a ScriptableObject for fast lookup at run-time
    Doing this at run-time without a prior bake step would be unfeasible and some mobile devices couldn't do it at all. The bake step makes sure to resolves this limitation and thats why the asset works on any hardware including less powerful devices - where you'd really need it the most.

    Because all of the hard work already happened in the Unity Editor there is little left to do at run-time. Looking up the list of visible renderers for a camera is O(1) and thus blazingly fast. Now the renderers need to be enabled or disabled. This step only needs to happen if your camera moved into a cell that contains new visibility information. Concluding that if you were to stand in the same position for the entire game you'd only toggle the renderers once.

    There is a group limit of 65535 (2 bytes, unsigned short) for each bake volume. However a single group can contain multiple renderers. For instance the asset automatically organizes LODGroups into groups. You can also create your own groups, of course. Concluding that if you have a bunch of super small meshes or meshes that are always visible together you can easily just make that a single group and they will be culled together. Furthermore you are not restricted to a single bake volume.

    Does this answer your questions? Or did you end up with even more questions now?

    Feel free to ask even more questions. Thank you! :)
     
    PutridEx likes this.
  5. DebugLogError

    DebugLogError

    Joined:
    Jul 24, 2013
    Posts:
    49
    I'm working on a runtime level editor. A "baking" step is fine for my use case. Is it possible to bake the data at runtime in a build?
     
  6. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    I made an attempt to decouple the baking process from editor-only functions but this use-case is definitely not officially supported.

    I'm also seeing a bunch of potential issues here (just some quick thoughts; might be incomplete):
    • The baking process is destructive because it changes the scene materials. In the editor the scene is reloaded and the original scene restored. So you'd also need to reload/restore the level after the bake finished.
    • The occlusion data does not reference renderers directly but it stores indices. You'd need to make sure that your level loading is deterministic to ensure that the list of renderers ends up in the same order.
    • You want to bake as fast as possible but you probably also don't want to show a black screen to the user while the baking is in progress. Doing both might bring the baking process down to a crawl.
    • If you are targeting mobile devices the bake process could make the device run out of charge quickly.
    • You'd probably need to expose baking options, create visualization options (they use Gizmos and wouldn't work in a build for sure), etc.
    • Users that got very low end hardware (especially on mobile) might be unable to bake due to lack of for instance Compute Shader support.
    • Running the game while also baking might blow your memory budget and crash your app (especially on mobile).
    • You need to save and load the baked data and you definitely don't want to use JSON because that would bloat the file size way too much. Not sure if you could still use ScriptableObject but you definitely need to get it back into the data type the asset uses (ScriptableObject + PreferBinarySerialization attribute).
    Concluding that it might be possible but just looking at some of the potential issues it might not be worth it. Of course, I don't know what your game looks like though.

    I hope this helps. :) More questions are welcome, of course. :)
     
    Last edited: Apr 21, 2021
    PutridEx likes this.
  7. niv-

    niv-

    Joined:
    Apr 20, 2021
    Posts:
    10
    Howdy o/

    Thanks for answering my questions.

    I'm working on a game that features huge terrain with sparse points of interest, like towns / farms / bunkers.
    Is it possible to have multiple occlusion boxes on these areas?

    I'm also curious about your "table lookup" is it rounding the position to get the closest cell or is it using a for loop to find the nearest one?

    and my final question, does this system stop the unity default culling? or are both active at the same time?

    As for baking at runtime, i do understand this is not what this asset is meant to do, but i think it would be a useful feature for games where you can build or change the map.

    The destructive material changing thing could be solved via calling Graphics.DrawMesh passing your material as argument, so that you don't have to change the materials on the MeshRenderers.

    This function can also take a camera as argument to render to that camera only, which seems perfect for your system.

    The Camera rendering could be done the same way as ReflectionProbes do, 1 face at a time or brute force render all.

    Anyways, not expecting you to change your asset, just sharing thoughts ^^
     
    DebugLogError likes this.
  8. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    You all are very welcome :)

    Yes, you can have multiple occlusion volumes!

    The cell lookup itself is making use of Spatial Hashing and thus does not need to loop over all cells. Of course, if the camera is outside of the volume the position needs to be clamped to the closest cell to not run out of bounds. Usually this should be fine but if you can be sure that a point of interest is not visible at all you should just disable it manually because the asset only got information about the occlusion within the volume. However if theres enough occlusion opportunities you might be okay without needing to do that (especially if you make the volume slightly larger than it needs to be so it got some more information about its surroundings). Just wanted to bring it up for completeness and transparency.

    You can use the Unity default culling system on top. The question is whether you really want to do that because the Unity default culling does have performance implications (especially on mobile) and can be tricky to tune. That is what ultimatively led to me creating this asset. But no restrictions going with a hybrid approach.

    I will definitely think about the run-time feature a bit more. Thank you! :)
     
    Last edited: Apr 25, 2021
  9. Passeridae

    Passeridae

    Joined:
    Jun 16, 2019
    Posts:
    377
    How is it better than Unity's native occlusion culling system and what is the difference between them?
     
    atomicjoe likes this.
  10. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    I will try to get an actual performance benchmark going to get some hard numbers but let me try to still write about some of the functional differences for now. Anyway keep in mind that I'm the creator of Perfect Culling and potentially biased!

    Even though Umbra (the Occlusion Culling system Unity uses internally) also requires a bake step, this bake step does not generate final data you can lookup. At run-time you pay for traversing a tree structure and performing rendering steps using a software rasterizer to render depth information and evaluating this information. All of this happens every frame on the CPU(!). Furthermore Umbra doesn't work well with procedural levels. On top of that there is not really a lot you can tune about it and you might hit a wall.

    Perfect Culling requires a much more involed bake step but it generates a final set of data. The lookup is instant and doesn't use a tree structure and that makes the lookup O(1). Really the only thing that needs to happen at run-time is turning the renderers on/off. Plus the asset only needs to do that if any camera moved into a different cell and thus requires a state update (for instance a stationary camera would be virtually free performance wise). Last but not least you can pre-bake occlusion for say a complex house prefab that you can spawn dynamically into your scene at run-time. Since the asset is generating pixel perfect occlusion data it is also easier to debug culling issues especially once you understood how the asset works.
     
    atomicjoe likes this.
  11. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    I tried to get some actual numbers. Please see the attached PDF for a more detailed description.

    The bars on the left represent Perfect Culling.
    The red/orange bars on the right represent Umbra.

    Obviously a huge part of the difference comes down to Perfect Culling culling more objects. Though if you start changing the settings for Umbra to make it cull more you will make its CPU overhead even larger.

    TLDR: Perfect Culling performs better because it culls more objects and doesn't hit the CPU in the way Umbra does.
     

    Attached Files:

    Last edited: Apr 25, 2021
  12. Passeridae

    Passeridae

    Joined:
    Jun 16, 2019
    Posts:
    377
    Sounds nice!
    Is there anything particular a potential user should worry about if its used in the interior scenario? Does it have occlusion portals?
    What's your planned release date and price point?
    Thanks:)
     
  13. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    I'd need to know more about how you plan to use the asset to give better feedback but generally interiors make Occlusion Culling systems very happy because there is a ton of culling opportunities.

    Are you in need of occlusion portals to implement doors? Right now the asset does not support portals but this is also a situation where you'd know for sure that the objects are visible or not visible. So what I'd do is just bake the occlusion without the doors. If the occlusion culling system already culls sufficiently you are already done. Otherwise you could combine it with a simple script that enables/disables the entire room based on the door state. Theres also the option to bake multiple sets of occlusion data and swap them out at run-time but I'd really try the easiest approach first.

    The asset already became available because I accidentally enabled auto-publish and I was also thinking the review would take much longer (so kudos to the Unity Asset Store review team). Anyway I already submitted an update to make sure all the improvements I made recently make it in as well. Concluding that you could buy it already but in that case definitely drop me a line info@koenigz.com with your invoice number so I can provide you with the updated package ahead of time. :)
     
  14. LVermeulen

    LVermeulen

    Joined:
    Jun 26, 2013
    Posts:
    36
    Great looking way to do runtime culling! I definitely think it could be designed with runtime baking in mind - right now there is nothing like that available for Unity (while there are definitely other in-editor baking options).
    No idea how you would handle the renderer references though - maybe a unique ID placed on them as a component.
     
  15. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    Thank you for your feedback. Really appreciate!

    Given the huge interest I will definitely explore runtime culling some more. Though before I do that I want to make sure that the core functionality is absolutely stable and feedback related to that is addressed. I hope that makes sense :)
     
  16. ftejada

    ftejada

    Joined:
    Jul 1, 2015
    Posts:
    690
    Hi @PatrickKa !!! It would be good a video with a very large scene with several tiles of Unity terrain, vegetation, trees, etc. and comparing it with the native occlusion of unity seeing the performance of both and how they behave.

    Regards
     
    atomicjoe likes this.
  17. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,688
    You should really highlight this in the asset store page, since it's not clear why use Perfect Culling over Umbra.
    Also, I think $98 is too expensive. Not that Perfect Culling doesn't deserve it, but we're indies here and we're not rich, so you would sell much more lowering the price by half than keeping the high price tag. But that's just my opinion and you have the right to put any price you want, of course.
     
  18. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    Thats great feedback and you are both right that I need to highlight this more! I really appreciate it! Thanks!

    The Unity Terrain is pretty special because it comes with its very own set of optimization features. To make terrains work with Perfect Culling you'd need to give up on that and convert them into meshes. If theres many culling opportunities this might be well worth the trade-off. However if your scene is mostly terrain this asset might not be a good choice unless you are willing to convert it into meshes.

    Definitely wanted to bring this up for transparency. I also put the Unity Terrain on my list of things that I want to investigate further. So maybe theres a better way in the future.
     
    ftejada likes this.
  19. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,277
    Okay that's sound good! now I have a question, I had a similar idea i never got to implement, during researching that idea, i realizedthat per cell the paralax was important within than cell, so here are my question:
    - How do you determine the cell size?
    - how does the cubemap texel size relate to the pixel of the screen?
    - How does parallax within a cell is handled (consider a simple non convex scene with a tower and thing behind it, on horizontal extremum of the cells, the thing are visible, but in the dead center, where you would put the cubemap pov, they would be invisible, which mean the cubemap will have false negative for some position within the cell). This can be mitigated, but not eliminated with smaller cell size, hence the first question. Maybe we query neighbor visibility too?
    - I guess you can support 4billions object right, seems like enough! Is there an extreme optimization possible where we basically cull the polygon soup instead? especially for static non animated objects that we could just merge based on material, then render the list of polygon per material as a single mesh, woudl reduce draw call too.
     
    atomicjoe likes this.
  20. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    Hey,

    I'm happy to answer your questions:
    - The cell size is configured by the user. I think this is important because it allows to find the right balance between bake time and the number of sampling points and thus occlusion data precision.
    - During profiling it turned out to be more efficient to just render six perspectives (also prevents biasing parts of the screen by making every perspective take up the same space) into a single RenderTexture. The entire RenderTexture is 3072x2048 px leaving a single perspective at 1024x1024 px. There is an option to change the rendering resolution though. If you were to create a camera and set the FOV to 90 and the resolution to 1024x1024 you should see what it would look like.
    - You are exactly right here and that is why the asset implements different ways to include neighbor visibility. The first option is on the PerfectCullingCamera and simply looks neighbor visibility up at run-time. This doesn't require another bake and is great for testing (but needs to perform additional lookups at run-time). The other option is to merge neighbor cells after the bake finished (this is an option called Merge-Downsample on the PerfectCullingVolume). This literally bakes the neighbor visiblity into the occlusion data and because merging cells reduces the number of cells it also reduces the size of the occlusion data. It's very powerful and a win-win situation. This can be performed more than once, too. Giving you another option to fine-tune.
    - The asset can address 65535 (unsigned short, 2 byte) groups. You can group smaller meshes or LODs, etc. into a single group and they will be culled together. You can also use multiple volumes which gives you another 65535 groups each. There should be ways to remove the 65535 group limitation but it would increase memory usage and I don't think that many people would really need more than that (plus using multiple volumes is already an option to workaround it).

    For the baking process I have experimented with combining all meshes into a giant one to render the entire level in a single draw call. This performed okay but it was even faster to slice the mesh up into chunks to allow for Frustum Culling.
     
    neoshaman and atomicjoe like this.
  21. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,277
    Just for precision in case you miss the implication, i was talking about per triangle culling assuming unsigned int32. Which mean each cell reference the polygon soup, aka the triangle list, per material, and just pass that. That mean frustrum culling wouldn't be necessary because it would be baked due to the nature of the optimization, assuming the list is per view, not just per cells. That's what crash bandicoot did on psx.

    I had the idea because Google seurat can "compress" complex scene into 10000 tri view area for vr, the techniques is different in that while they take cubemap "views per cell", they compress the result into a polygon soup that is a photogrammetric reconstruction unique to that view. So after some napkin calculus after seeing some demo scene, i realize it would allow visually complex scene on way weaker hardware for negligeable cost. Even a mali 400 can output at least 300 000 tri per frame at 60 frames.

    I just adapted that idea to a per triangle pixel perfect culling. Which would be not as efficient because it wouldn't allow the automatic compression and implicit lod, but still a massive improvement for static scene mesh. Especially because overdraw is a massive problem on mobile, assuming these triangle are pre sorted by depth, it would be a great gain because in a typical scene, assuming free roaming camera, you have no way for the gpu to know which triangle cover which one in concave scene. Of course sorting triangle do not prevent completely overdraw, in case of a big triangle spanning the depth of many small triangle or sumply intersect cases, but it would limit it for all the case whete there is an obvious occlusion (triangle isn't sent) or a big occlusion (front triangle guarantee to cover).

    In fact the tools could also double as a performance check if it goes per triangle, since we know the coverage of each triangle, and the material to which they belong, that would nean for each view, we can infer a performance score due to shader complexity, simply by measuring the coverage of a material from the pov, and having material sorted by their cost. If a costly material get the big enough coverage, we could issue a warning.

    Now that last idea is probably out of the scope of the project, just sharing in case you are interested, feel free to ignore everything i said anyway. Just rambling about some opportunities a d wishes.
     
    PatrickKa likes this.
  22. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    You got some very interesting ideas. I'd imagine that the biggest downside is that you need to upload all this information to the GPU every frame and/or make use a good chunk of your GPU memory so it can live on the GPU.

    I also really like your idea of calculating performance scores and sorting triangles. I just recently created a procedural mesh and I forgot to sort the triangles and performance took a hit even on a high-end system. So yeah that could potentially help a lot.

    Like you said some of it might be very out of scope for this project but your ideas are great and very inspiring and I will keep them in mind for sure! Thank you. I really appreciate! :)
     
    neoshaman likes this.
  23. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,277
    Yeah obviously variant or partial implementations would work, as in case of scene with huge amount of instancing, like grass and tree, you duplicate the tri, so the gain is probably not worth it, like all optimization it's contextual, in case of instancing per object culling is probably the best option due to memory, while per triangle would work with massively unique geometry. Hybrid system is probably the practical usage.
     
  24. MrBlueSky

    MrBlueSky

    Joined:
    Jan 7, 2013
    Posts:
    20
    Hello, Is this compatible with VR (Oculus/OpenVr) and large scenes ?
     
  25. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    It is fully compatible with VR. I'd need to know more about your scenes. Generally speaking any sort of culling works best when there is culling opportunities. Usually large scenes are very open and culling opportunities are more rare. If theres a lot of empty space you'd definitely need to use more than one PerfectCullingVolume.
     
  26. Redrag

    Redrag

    Joined:
    Apr 27, 2014
    Posts:
    166
    I assume this cannot work if I have to shift the world? you know floating point issue.
     
  27. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    What makes you think so?

    Maybe provide additional detail because right now I'm unable to answer your question, I'm afraid. :)
     
  28. Redrag

    Redrag

    Joined:
    Apr 27, 2014
    Posts:
    166
    Normal Unity Umbra culling creates areas that are fixed. So if I shift the whole world then the culling isn’t going to work. I am asking if your system gets around this.
     
  29. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,688
    Can Perfect Culling support moving the entire world?
    Also, can it support different chunks, independent from each other?
    Like, can I store the visibility of a zone on a prefab of a group of objects and use several groups like that? independent from other groups?
    It would be useful for realtime level generation using large chunks of levels.
    And in that case, could the root position of those chunks be moved in the world and still work?
     
  30. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    The occlusion data is relative to the PerfectCullingVolume. If you make sure that it moves the same way as your world everything should still be in sync and cull as you'd expect.

    As mentioned above as long as you move the PerfectCullingVolume along it should work just fine.

    You can make use of multiple PerfectCullingVolume and they will cull independently. Yes. You could even turn this into a prefab and instantiate it.

    Internally the asset operates on a grid and if your camera is not within the bounds of the grid it will be clamped to constrain it back to the grid. If you know that a chunk is impossible to see you'd need to disable it yourself. I can draw a picture if it is unclear what I mean.


    If you move the level by 3 units you will have to move the PerfectCullingVolume by 3 units as well. If you just parent your renderers to the PerfectCullingVolume then that should work, too.

    I hope this information helps but feel free to ask more questions or add even more detail. :)
     
    Last edited: Jun 20, 2021
    atomicjoe likes this.
  31. atomicjoe

    atomicjoe

    Joined:
    Apr 10, 2013
    Posts:
    1,688
    It does! Thanks :)
     
  32. FiveFingerStudios

    FiveFingerStudios

    Joined:
    Apr 22, 2016
    Posts:
    503
    Is it possible to execute baking from a script? I have a custom script that performs light baking and occlusion baking in one step for scenes.
     
  33. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    Yes. The PerfectCullingBakingManager implements functionality that allows you to do that:
    Code (CSharp):
    1. public static System.Action<PerfectCullingBakingBehaviour> OnBakeFinished;
    2. public static System.Action OnAllBakesFinished;
    3.  
    4. public static void Bake(PerfectCullingBakingBehaviour[] cullingBakingBehaviours)
    5. public static void Bake(PerfectCullingBakingBehaviour bakingBehaviour)
    So if you just want to bake all occlusion culling data for the current scene:
    Code (CSharp):
    1. PerfectCullingBakingBehaviour[] bakingBehaviours = GameObject.FindObjectsOfType<PerfectCullingBakingBehaviour>();
    2.  
    3. PerfectCullingBakingManager.Bake(bakingBehaviours);
    Since Bake() runs asynchronously you'd need to make use of the events to get to know when the bake is done.

    Anyway if any functionality is still missing or just doesn't work for you just let me know and I will try to add it :)
     
  34. FiveFingerStudios

    FiveFingerStudios

    Joined:
    Apr 22, 2016
    Posts:
    503

    Awesome.

    One more question.

    My games levels are made up of multiple scenes that I load asyncronously. I bake navigation and lightning and occlusion for each level with those scenes open in the editor at the same time. Does Perfect culling support that?
     
    atomicjoe likes this.
  35. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    I assume you load multiple scenes so you can bake them together thus taking into account the other scenes. That is definitely not supported at the moment. The main problem is that the asset needs stable references to the renderers. This works fine for self-contained situations but if you crossover into different scenes it becomes problematic.

    There might be a way to workaround this for the time being. For instance before you bake you could spawn the surrounding geometry into the scene you are baking and add it to the renderer list. After you are done you can remove the mesh and material (to not waste memory but just keep it as a dummy reference. I'm definitely not a fan of this but it would be an option.

    So yeah you could potentially workaround this limitation but it is not truly supported at the moment. I will add it to my list of things to investigate. I already got an idea how it could work because I believe I could just introduce an additional list of renderers that are taken into account while baking but are not managed by the asset. That would allow to bake occlusion data for an entire scene without any issues of cross references because it is still pretty much self contained as each scene only manages its own references.
     
    Last edited: Jun 28, 2021
    Seith and atomicjoe like this.
  36. FiveFingerStudios

    FiveFingerStudios

    Joined:
    Apr 22, 2016
    Posts:
    503

    I totally get it with the cross scene reference issue. Unfortunately, I'll have to stick with my home grown solution for now....which is just simple colliders/triggers that toggle the renderers. Depending on the scene, I can use Unity occlusion culling, but for some scene its price isn't worth the cost. I was hoping the use your asset. Thanks a lot for insight in how Perfect Culling works. I look forward to seeing it mature as it looks very promising.
     
    PatrickKa likes this.
  37. ohunity

    ohunity

    Joined:
    Jan 19, 2014
    Posts:
    634
    Hey looks promising! I like the concept here, so do you basically bake a texture for each cell then do a lookup based on which cell/cells the camera is near?


    Some questions.

    Is Alpha Cutout supported on these bakes? I see you are replacing materials at bake time, so if alpha cutout is detected, could it replace the material with a cutout version of your replacement shader?

    On a more open map, I see why you would want to have separate volumes as, What happens if occlusion volumes overlap? For example, I can see it being worthwhile to have some large celled, "low res" volumes, in the open areas and higher res cells in more compact areas.

    Are slopes an issue? For example if you are on a terrain, the cell has captured its ref image from under the terrain, the system may think much much more is visible than really is, as I don't imagine the cells are doing any sort of marching. Is there any solution to this? Possibly double sided shaders?

    How about open air space? For example on a slanted map, besides shaping the volume is there anything in place that could potentially optimize the irrelevant cells? Can volumes be rotated?

    Is there any downside to using a ton of different volumes? Is there a minimum amount of memory consumption there?


    All the best!
     
  38. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    The bake happens on the GPU but the results are stored in a ScriptableObject and all run-time calculations are done on the CPU (mostly just a lookup as you mentioned).

    The asset would just treat it as a transparent object thus making it an occludee. Would that be a problem for your use-case?

    Volumes can overlap but they generally should manage an independent set of renderers to avoid conflicts (Volume A saying its visible, Volume B saying its not).

    Sampling below the map can indeed result in funny issues like that. The next update will add some features to prevent them (I can already provide the updated asset via mail though; please provide your invoice details).

    The update introduces two two options:
    - Create a volume that defines where the asset should not sample.
    - Write a script that tells the asset where it should not sample. It will give you a position and you can reject it. To not sample below the terrain you could just perform an upwards Raycast and if it hit the terrain collider its below the map and the position rejected.

    Volumes can be rotated and as mentioned there is gonna be a feature to remove cells from the baking process.

    The visibility is only refreshed when the camera moved into a new cell. At this point all volumes update visibility of renderers they manage. So it should not be a problem because it happens very infrequently. Though there might be a limit to when it becomes a problem but all of this is very depended on the target plaform, general game and scene complexity, etc.

    Anyway there definitely is a minimum memory consupmtion here because every object is using memory. This should be neglibile though. If you can reduce the baking area by using multiple smaller volumes instead of a large one you most likely will make more than up for it.
     
    Last edited: Jun 29, 2021
    ohunity and atomicjoe like this.
  39. ohunity

    ohunity

    Joined:
    Jan 19, 2014
    Posts:
    634
    Thanks for all the information & quick response, going to give this a purchase! Will reach out in the DMs for the new version once I have my invoice number.
     
    PatrickKa likes this.
  40. ohunity

    ohunity

    Joined:
    Jan 19, 2014
    Posts:
    634
    Can't seem to DM so will send an email.

    Also regarding this, I can see why regular transparent couldn't be supported as occluders, but for alpha cutout when the pixels are either 0 or 1, wouldn't this work fine with the baking setup?

    The reason in this case being trees, even if just a few trees are nearby each other they can occlude a lot, one small issue I could forsee is a single pixel coming through one of the cutouts in the tree causing something that is basically not visible to render, maybe there could be a threshold for a certain required amount of pixels before something is drawn?
     
    atomicjoe likes this.
  41. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    Sounds good. You can find the mail address in the asset description. I also sent you a PM just now! Maybe that works now :)

    This is all about performance. The asset ships with an native renderer that performs the baking process outside of Unity. This is round about four times faster because it has been optimized for this specific setup. I could add such a feature but it would require to send even more data to the native renderer so it can perform the bake but it would slow it down.

    However you can disable the native renderer and that will use Unity for rendering. The shader code is included and you could modify it. I will also think some more about this. Maybe there is a better way to solve this.

    You could reduce the rendering resolution. That will essentially do something similiar as it pushes pixels out of the image that are too far away and do not contribute enough. I'd love to allow configuring this more precisely but this is also constrained by performance concerns. I will think some more about it, too.
     
  42. swantonb

    swantonb

    Joined:
    Apr 10, 2018
    Posts:
    109
    Seems like a good asset, i do have a question though, if the frustum culling cant be turned off it will still take the cpu time right? In my project culling takes 3ms. Will this asset cull everything behind camera before frustum culling and the frustum culling time will be scratched? Or it will take 1ms(or less, not sure) on top of frustum culling time?
     
    Last edited: Jul 4, 2021
  43. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    Frustum Culling is always performed by Unity. There is no way to disable it. However since the asset disables renderers there is no need for Unity to have them go through the Frustum Culling process because they are not meant to render anyway. Concluding that you might see improvements here as well because Perfect Culling takes them out of the loop before Unity gets to them. The remaining renderers will be frustum culled by Unity.

    If you are talking about Occlusion Culling (Umbra) though that can be replaced by Perfect Culling and there is no need to use the Unity one anymore. Though you might even be able to use them in parallel (but why would you).

    So maybe take another look at the Profiler because the Culling might also refer to Unity performing its occlusion culling (and that can indeed be pretty expensive whereas Frustum Culling is usually always worth it).
     
  44. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    I'm currently trying to add the necessary API to pass in additional occluders. They are basically just like renderers you add to the PerfectCullingVolume but they are not managed by the asset and thus do not make it into the baked data itself. Just as the name suggest they are only meant to occlude other objects.

    The idea is that you can load in multiple scenes and every baking volume will add the renderers of the other volumes as additional occluders. This way each scene can still occlude correctly and remain self contained without needing a reference to renderers of the other scene.

    I got the necessary API done and will need to do more testing and tweaks but overall there shouldn't be too many steps missing to complete this.

    This feature is probably not relevant for everybody so it might only be accessible via the API. Though I thought about just always add other volumes renderers as occluders but if you are baking prefabs, etc. that would be undesired. Maybe it could be an option on the volume "Include other volumes as occluders".

    The code for my little test is pretty simple though:
    Code (CSharp):
    1.  
    2. public List<Renderer> AdditionalOccluders = new List<Renderer>();
    3.  
    4. // ...
    5.  
    6. PerfectCullingBakingBehaviour[] bakingBehaviours = GameObject.FindObjectsOfType<PerfectCullingBakingBehaviour>();
    7.  
    8. PerfectCullingBakingManager.BakeNow(bakingBehaviours, new HashSet<Renderer>(AdditionalOccluders));
     

    Attached Files:

    Mark_01, atomicjoe and ohunity like this.
  45. SOSolacex

    SOSolacex

    Joined:
    Jan 10, 2018
    Posts:
    121
    I use Gaia's procedural world streaming where scenes load asynchronously. Camera Render drawing and culling can sometimes take up to 10ms in total (5 each !). It's a shame that there isn't really anything to get it to work well with async scene loading like that yet, but I'll certainly keep an eye on this asset.
     
    PatrickKa likes this.
  46. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    I just got baking across multiple scenes working but there is some limitations. I attached a screenshot and you can see that I made the baking volume much larger than the level chunk itself. This is crucial because the asset only got information about the sampled locations. If all samples are constrained to its own level it will never be able to tell that the wall in the neighbour chunk is blocking the view and passing in all the additional occluders is not doing anything and pointless.

    On the positive side the further you move away from the level chunk the less renderers should remain visible thus the memory usage for the overlap should drop over distance.

    I will think some more about it but I believe this is as good as it could possibly work and the culling precision will depend on how much overlap you allow and what your level geo looks like (insufficient volume overlap will result in less culling; no good occluders in the overlapping area will also result in less culling).
     

    Attached Files:

    Last edited: Jul 8, 2021
    dithyrambs and Seith like this.
  47. Seith

    Seith

    Joined:
    Nov 3, 2012
    Posts:
    755
    Hi @PatrickKa I'm very glad to hear you're making progress with the multi-scene situation since this is going to be very important for us (we're working in a large multi-scene streaming configuration)... :)

    Would you have any ETA for when we would be able to test it?
     
    dithyrambs likes this.
  48. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    Hey, I don't have any ETA just yet because I'm still experimenting with it. I also was hoping that it would be even more effective but early tests did show that it can only be as effective as the allowed bake volume overlap which is a bit disappointing but makes sense. So I'm also still trying to see whether there is any way to reduce this limitation.

    I can make a picture if it is not clear what that limitation is about.
     
    Seith likes this.
  49. DanjelRicci

    DanjelRicci

    Joined:
    Mar 8, 2010
    Posts:
    261
    Just discovered this asset and sounds exactly what I need- an occlusion system with little to no overhead at runtime, for densely populated and occluded scenes running on Oculus Quest.

    I have to agree with atomicjoe, It's a steep price for indies once taxes are in (106€!!), so I have a bunch of questions before eventually pulling the trigger:
    - Does it run on Unity OSX? In my case I use a 2013 Intel Macbook with a GT 750m GPU, but wish to switch to a more recent M1 Mac later on.
    - How does it integrate in VR? Does the culling happen at the same time for each eye camera?
    - What if I have an additional camera that I move and render manually every x frames, to which I would like to apply Perfect Culling?
    - Is it ok to use a lot of small culling volumes? With Umbra I use a lot of small culling areas because the player can never leave roads so it makes no sense to bake occlusion outside of it, but such roads are very twisty so the box volumes end up overlapping. Also these small volumes are automatically placed using road splines so I can automate tedious manual work- I would like to replicate the same workflow with Perfect Culling eventually.

    I guess that's all for now, thanks. :)
     
  50. PatrickKa

    PatrickKa

    Joined:
    Apr 30, 2014
    Posts:
    202
    Most of the calculations are done on the GPU in the Unity Editor. Generally the asset works on OSX but the baking time will be about four time slower because the rendering cannot be done using the native rendering tool. I cannot say for sure how well your GPU would work here but I'm leaning towards saying that it might not work good enough for me to recommend it to you.

    The actual culling is performed before Unity even starts the rendering process so it does work with VR rendering techniques. However since the asset only samples points and we all got two eyes you can imagine a situation where a renderer was culled that could still be visible from one eye. You will most likely make use of the merge-downsample iteration that combines neighbour cells into a larger cell and that solves this issue while also reducing the memory requirements. So it is more of a theoretical problem and the asset provides tools to solve it.

    This should work out of the box.

    There is two options:
    - Use multiple volumes
    - Use a single volume and use the volume exclusion feature to cut out sampling points. This can be done by placing volumes or you could also write a little component that for instance performs a Raycast to figure out whether this point should be sampled or not.

    Anyway in case you decide to give the asset a try please reach out to me so I can provide you with an updated version that features the volume exclusion feature I mentioned.

    I hope this helps and feel free to ask even more questions. :)
     
    DanjelRicci likes this.
unityunity