Search Unity

Frustum/distance-culling of GPU-instanced objects with the Job System

Discussion in 'C# Job System' started by Nyanpas, Sep 29, 2019.

  1. Nyanpas

    Nyanpas

    Joined:
    Dec 29, 2016
    Posts:
    406
    [update] I managed to improve the culling jobs by using Unity.Mathematics. It was previously 1ms, now it is down to 0.5ms. I also tested twice the amount, as in 18 million objects, and still got the same result, except it takes a little longer to setup at start.

    Greetings,
    I have been looking at a way to handle large scale GPU-instancing (using Graphics.DrawMeshInstanced()) and found that using the Job System for culling worked well for my project. I am down to an average of 0.5ms thread-time handling over 9.1 million instanced objects placed on the meshes of the terrain. Hereby follows how it works:

    jobcullen.gif
    This is an overview of the camera which all the lines connect to (they show visible triangles), and the triangles which has GPU-instanced objects on them. There are several scheduled Jobs in place, the first one being based on area distance alone, the others are per area. This way I can split up the batches needed for DrawMeshInstanced() per area, and process less objects per update as they all get handled from a list generated by the visibility received from the first Job System. The jobs are scheduled based on size and time, as they do not need to be called every frame. Currently the first job system works at most once per second, and the per-triangle ones once work at most every 0.2 seconds.

    edwardjobcullen.gif
    Here is how the culling works from the ground level. Currently the max distance is set to 4096 units which is the same as the far clipping plane of the camera, and the per-triangle area distance is set to 1024 units. The viewing angle is set to 135 degrees. With distance/frustum-culling only at most a few thousand objects are rendered at once.

    ingamecullen.gif
    This is what it looks like from the game camera. Sorry about the terribly low capture-rate FPS, this runs much better.

    The main Update()-logic is a for-loop within a for-loop that runs over lists populated with the Matrix4x4s of the visible objects gathered from comparisons performed in the Job Systems. Due to large batches being an issue on WebGL (this game is made for that platform) I've had to include another for-loop for them as well, as I have only been able to get this to work with smaller batches under 100 per batch so far. The system is far from perfect, and lots of improvements can be done.

    My next version of this will include man-made structures as well, and once I get ECS in, almost anything moving that will be needed to be drawn in large quantities.

    You can see a live version of it if you are interested. Due to it being a very early tech-demo, the game will hang a bit at the start as it populates the 9.1 million instances, and I haven't come as far as including that in the initial start-up loading:

    WebGL-demo
     
    Last edited: Sep 30, 2019
  2. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Is there a reason for not just using the Entities Hybrid Renderer which solves this particular problem out of the box?

    Including workflows for converting game object scenes, loading / unloading them efficiently

    It was used on the megacity demo:
     
    tatoforever and Lars-Steenhoff like this.
  3. Nyanpas

    Nyanpas

    Joined:
    Dec 29, 2016
    Posts:
    406
    Because I wouldn't know where to start when it changes all the time, and I haven't found enough documentation about how to use it. This is all I find when I look for it on the internet:

    https://forum.unity.com/threads/hybrid-renderer.617494/

    I have extremely limited time for this project, and do not have much time to spend looking at code in repositories, especially when they are very elaborate. I wanted a system that for now foregoes ECS until it gets to a stage I can use it in my project. I started this project almost two years ago now and having to rewrite code for every ECS-update will not make it progress.