The Living Reef is a reef simulation hosting over 700 A.I. controlled fish from over 9 different species created in Unity. The project was built to be displayed on The Cube at The Queensland University of Technology for the general public to interact with. Our goal was to really push what has been previously done with creating an under water world so I thought I would explain some of the tech that went into The Living Reef ‘s development and showcase the project.
To make the fish move in a life like manner I incorporated Boids – a distributed behavourial model developed by Craig Reynolds. Boids are pretty much the de facto standard for anything that flocks or schools so I won’t spend too much time explaining, but in short, the model works by calculating the separation, alignment and avoidance of a fish’s neighbours, taking into account weightings for these three components and iterating over the entire school.
This was the first time I had developed a Boid system using Unity’s job system. By utilizing jobs I could take advantage of threading to make efficient use of the CPU cores resulting in a lot more fish in the scene!
I also used the job system to roll my own custom physics system which brings me to a useful tip – when using IJobParallelForTransform the game object’s transform can’t be nested and needs to be on the root otherwise it will all run in the same job!
Initially I wanted to use the full DOTS stack, so that the fish would be better managed in memory for further performance increases, however our animations were complex, with blending on multiple layers and the animation support in DOTS was just not there yet.
The next step was terrain avoidance. With over 700 fish controlled by AI, terrain avoidance had to be cheap to run. Most Boid systems control avoidance by adding a repelling force when near an obstacle. It would be too slow to dynamically calculate this, so I opted to create a three dimensional grid over the world and calculate offline via raycasting a vector to the terrain in each cell. As a fish swims along, it simply looks up which cell it is in to retrieve the terrain vector information. This works well but as the fish swam along it did exhibit some jittering. To improve this I sampled the neighbouring grid cells to that of the fish and obtained a weighted average which helped smooth this jitter.
Finally I added support for a predator and prey system by leveraging the Boid system. Different fish have different tags. Sharks > Large Fish > Medium Fish > Small Fish. During the Boid calculations the closest predator is found for the fish (if any) and then this flee force is added into the combined force for the fish that’s then fed into the custom physics system. For predators it’s a similar process except it’s an attract force. This system really helps makes the scene feel alive.
Check it out
A lot of experimentation and research went into the project and there are a few topics I have not yet covered. I’ll save them for their own dedicated posts. If you are ever in Brisbane, Queensland, Australia, come check out The Living Reef at The Cube. It’s open to the public free of charge.