One feature I've always wanted to implement: asteroid fields. Vast fields of rocks that can span across huge distances.
The problem: performance degradation from updating and rendering a large number of bodies.
The solution: use a smaller number of bodies, local to the player position, which are updated and displayed when in defined asteroid field areas. Perform updates using the Unity Job System for improved performance.
The first videos show the result of an infinite asteroid field. A clipping distance is used, hence asteroids will pop in and out of view at the boundary.
How it works: asteroids are initially spawned around the players local position as far as the defined viewing clipping radius. Each asteroid is checked to determine if it falls within a defined asteroid field area. If it is, then show it, otherwise we hide it from view. We then move each asteroid based on the players velocity. When an asteroid goes past the boundary of the clipping area we re-spawn at another random position at the boundary edge.
This works well and performance is improved using the Job System over a single threaded process. These asteroid fields demos were run within the Unity editor so performance would be improved in the build without the editor overhead. One problem I will have is figuring out a balance for lower end systems as access to such a system is currently out of picture right now. I will be using Unity Analytics to help, once a playable build is made available, I will be able to compare performance across a range of systems as players engage with the game.
Currently, on my dev build performance starts to drop when 7500 bodies are visible. This was not the huge performance boost I was expecting using the Job System, so I may have to also experiment with the Entity Component System.
In the version two video, below, there are now asteroid debris and dust clouds.
Flying through an infinite asteroid field with dust clouds and debris gave me a sense of claustrophobia that I had never had before. I just wanted to get out yet there was no end...
So flying through an infinite asteroid field can probably get frustrating. We can limit the field of the asteroids by introducing asteroid field zones. A simple game object with a script that defines the asteroid field radius. Then create any shape and size of asteroid field you want by overlapping spherical fields.
The one thing that is pretty obvious in 3D space is that it's big and to fill that space you need rather large objects and lots of them. I like the idea that the player needs to exercise some caution and attention while flying through a field. Introducing the Kamikaze asteroid!
The kamikaze will spawn directly in the players path to give them something to avoid. A pretty basic idea that took too long to implement :) To avoid being overwhelmed, Kamikazes can be stopped from spawning in when enemies are near. Right now, enemies are always near :/ That's something to think about.
The Unity Job System
I mentioned earlier a problem with rendering and updating a large amount of bodies. On my dev PC I could get 3000 asteroid bodies at a steady 30FPS before performance would drop. With the Job System I was able to increase this number to approx 5000 before, once again performance would drop. This was not the huge performance gain I was looking for. However, updating the asteroids positions and rotations was not exactly a heavy burden, even with such a large number. No, it's all about the rendering. I can clip the visual range of the asteroids and going down to 1000 from 3000 clipping range provided an huge increase in performance. Reducing the clipping range meant less bodies visually displayed.
Further performance improvements?
If I want to have more asteroids, or improve performance on lesser systems I need to either reduce the visual range (not preferable) or find a more efficient way of rendering a large amount of bodies. After some investigation I came across GPU instancing. First you can already enabled that feature, with limitations, by ticking the appropriate box in the material for the asteroid. Something I have done above, which I forgot to mention. However this is not an in depth technical article, I couldn't even go that deep with my current level of knowledge.
The question now: do I implement Mesh Instancing at the code level using Graphics.DrawMeshInstanced(). I had a simple solution running and it certainly gives the performance gains needed. However they are empty shells and another head ache to approach another day.
I hope you find this article useful, especially when considering how to implement your own asteroid field. The main benefit of this implementation is simulating an infinite asteroid field with a limited number of recycled bodies. Leaving and re-entering an asteroid field at the same point over and over will result in unique looking fields each time. If you are looking to create asteroid fields that remain persistent then this solution will not provide that.