It’s no secret that Unity has been blazing a trail on the AEC front lately. One of the selling points of Unity Reflect is that it enables us to “Easily bring our Autodesk Revit, BIM 360, Navisworks, SketchUp, and Rhino models into AR/VR“. Some extremely impressive AEC apps are being developed with Unity, including real time AR apps like the one shown below. (In fact YOU can build this app right now. The course is available here on Udemy.)
Inspired by these amazing apps and having never used Unity before, I started to kick around some ideas for a small project that I could reasonably expect to complete in a weekend. Something to familiarize myself with the Unity APIs without falling too deep into the rabbit hole. I ended up settling on a Gravity Simulator, specifically an N-Body Simulation. Having a fair bit of experience with Direct3D and other Graphics APIs I thought this to be an attainable goal, especially since Graphics Libraries are generally more difficult to use than full blown Game Engines like Unity or Unreal.
The simulation uses Newton’s Law of Universal Gravitation to calculate the gravitational force between two given masses in space. Each Point Mass exchanges it’s gravitational force with every other point mass in the simulation 20 times per second. For simple simulations with a small number of point masses, a single CPU core can handle these calculations in real time. An early Saturday build shown below demonstrates that the simulation is functioning as intended, albeit on a small scale.
For large numbers of point masses however, optimizations are required to keep the simulation running smoothly. The number of particle-particle interactions needing to be computed increases on the order of N2, and so direct integration of the differential equations can be prohibitively computationally expensive.
In the end I did not use any of the linked optimizations as they were outside of the scope of what I was trying to accomplish. I did however come up with some of my own optimizations that enabled the simulation to run smoothly even when simulating hundreds of particles. Notably, caching the GameObject.Transform.Position was significantly faster. I identified early on that the Getter of this Property was very slow given this use case. Lean collision detection was also added, as merging point masses can quickly lower the number of particles in the simulation. These initial optimizations (and a handful of others) helped to create the procedurally generated simulation below.
At some point late Saturday night I opened a beer, confident that I too could build awesome things in Unity. It was a good day. I wasn’t finished however, and decided that evening that my Unity N-Body Simulation needed to end with a bang. Perhaps not a Big Bang, but I at least wanted to simulate two galaxies colliding. I estimated that making this even somewhat believable would require at least doubling the number of particles in the simulation.
Unlike the Millennium Run which simulated over 10 billion particles and took a super computer over a month to execute, this simulation evolves and renders itself in real time on a far smaller scale. The optimal approach was likely to use Compute Shaders to offload some of the work to the GPU. Today’s GPUs are far better suited for this sort of thing. Given the scope and my current lack of Unity knowledge however, I opted to push my CPU further by splitting the simulation up into multiple parallel threads.
Overall I am satisfied with the result. It does a good job of simulating what our impending collision with Andromeda might look like. As an added bonus, I learned how to create some fairly complex simulations in Unity.