Ecosystem simulation

Making Of / 28 April 2018

The issues of placing plants

Filling an environment with foliage is always a pain and from what I have found, the methods haven't changed much.
With the rising popularity of proceduralism, new techniques are being applied. But they more often then not still rely on basic principles (like scattering points around). Sometimes additional layers are applied, like rules to incorporate environmental factors and other influences. These still only manage to replicate real life when an artist glances over the output and adjust it manually.

Disney to the rescue

Since I had been doing it like this myself, I always accepted these methods as the best ones since they still provided reliability and most of all stability. But, that was before I came across the Disney research paper on simulated ecosystems. (get the paper HERE)
In this paper they propose a method of simulating an environment using adjustable factors and real life data (lots of it).
This seemed like an amazing thing to implement, so. Off I went to create this system using houdini.

A side note

Before I continue, a quick note: The upcoming paragraphs go mostly into my thought process whilst creating the system and the problems I ran into. If you're mostly interested in the results the system produces, feel free to skip to the "The system in action" title.

The process

The first iteration seemed pretty promising, instead of making a cycle based on a single frame I thought it would be interesting to add a frame-range. With this, I would not only be able to simulate a year, but also the months in that year.
Since the system used a lot of real life variables (like temperature, sunlight per day and humidity) I was able to find real life data on those,
pick multiple maximum and minimum values and interpolate between those to simulate a year cycle.

How the variable picking works (in this case the temperature).

This thought ended pretty quickly with the realization that if one year were to be 12 frames then simulating longer time periods would be insanely
expensive. For visualization purposes it would be amazing to see seasons go by as the environment grows but, my goal was a quick solution
So, multiple frames per cycle would probably be a no go.

With that in mind, I compressed the system. Instead of one frame per month I now used one frame per year.
Instead of interpolating between the a-biotic factors (values that are there regardless of the ecosystem like temperature, sunlight and humidity)
I picked one of the maximum values and one of the minimum values (I had two of both to emulate better or worse years, more on that later) and
took the average of those. With this, I successfully compressed the simulation to a single frame per year.
This new approach brought along some new issues though: overpopulation.

For some reason, plants would keep spawning regardless of any factors.
Turns out, I hadn't put a limitation on when the plants could start creating offspring.
In real life this would be pretty fuzzy as it differs a lot per plant, but to solve this I gave every plant an age threshold based on it's other factors,
as to balance the plant a bit.

The results of this were immediately visible as the population still grew, but not as drastically!
I ran into a new problem though: mass extinction and little response to parameter changes (besides the mass extinction).
Up until this point, I had been testing the system on an artificial climate that was for all intents and purposes easy mode:
A heaven with gentle temperatures and plenty of sunlight.
When I changed this to another climate (maritime for instance) the whole population would die off without reproducing.
That's an issue.

Third version

At this point the main script became too cluttered as I had only been patching it during the shift from version one to two.
Because of this, it became very hard to see where the issue was.
To save myself time and improve the system I decided to rewrite it.
This time around, I used functions instead of writing the code down every time, restructured how I stored all the attributes,
added a bunch of parameters for controlling the system and even made an easy interface for creating plants to be used in the system.

Alright, an updated system, an easy to read attribute layout and a bunch of parameters to tweak. This should fix the issue in no time flat!

That is what I hoped for anyway.
For some reason, the simulation still murdered all those poor poor (digital) plants.
But, after running through the code a couple of times I finally found the solution: my relative distribution function!

The first and second version of the distribution function.

Above you can see the first and second version of the distribution function.
A little bit of information about them. Every plant has three values for it's a-biotic factors: Its minimum-, maximum and preferred value.
The minimum and maximum value are used for normalizing the current temperature, sunlight or humidity value. But, the preferred value, is what
drives the peak seen in the first graph and the flat-line in the second.
After looking around a bit, the abundant sunlight and the graph above are what caused the plants to die.
Because the sunlight would be above the preferred value fairly often, the function would remap it to be zero anyway.
Even though, more sun would improve their situation. By making the function go constant after the preferred value the plants wouldn't
receive a zero value, and would continue to live!
Once I patched this out, I finally had a system that would simulate using environmental and biological factors!
Off to simulation tests!

The system in action

Without further ado, lets just see the system in action!

On screen here is a simulation that took place over 36 cycles in a maritime climate.
The amount of species in this scene is four:

A closeup of all plants used in the simulation
  1. Oak tree (light blue, all round plant with low reproduction capabilities)
  2. Summer tree (dark green, tree designed for warm environments with high reproduction rates)
  3. Pine tree (pink, Thrives best in cold environments and has high resilience to hostile environments)
  4. Ribes bush (dark blue, quickly reproducing bush with low space needs and relatively high resilience)

Something of note here, is that the third tree isn't a real life one. It is one I made and specifically designed for warm environments.

What really stands out here is how a large part of the initial generation die off, due to bad placement.
This was very satisfying to watch after a lot of strange bugs break the system.
It also shows how the "weak" plants don't survive. Weak meaning, plants that aren't fit for the environment.
You can see this especially well in the data graph made of this sim:

Percentage of total instances per plant

Here you can see how all plants start of in fairly equal numbers and almost immediately, survival of the fittest kicks in.
Due to its fast reproduction rate, the ribes bush is able to take up all space and win the race by sheer quantity.
The pine doesn't grow much relatively, but holds its own due to its high resilience.

On the other hand, the oak and summer tree don't do so well.
Due to it's low reproduction rate and large space needed the oak simply can't keep up with the exponentially growing competition of the bushes.
And because the temperature isn't warm enough, the summer tree also slowly dies off.

In video, the colours represent a couple of things:
The colour represents the species (mostly for telling things apart) and the brightness stands for the plants fitness.

This fitness value is key to the simulation.
It determines if the plant reproduces (and how much), whether the plant looses life force and whether the plant grows (amount of growth included).
The value is computed by combining all biotic and a-biotic factors. This is done through some fairly simple code like seen below.

fitness = competition * soil_adapt * temp_adapt * sun_adapt

I am able to get away with a simple function like this because most of the heavy lifting is done in those variables used in it.
Speaking of those, this is what they stand for:

  • Competition: How proximity of other plants influences the current one.
  • Soil_adapt: The interaction of the plant with the combined value of soil fertility, water availability and height. 
  • Temp_adapt: How the temperature influences the plant.
  • Sun_adapt: How well the plant handles the current sun values.

Some ideas I have for future versions of the system is making different versions of the fitness function, making the values above interact in different ways.

Now, if you paid close attention to the video, you might notice how the plants in the center don't really spread. Like they are being blocked.
This is the result of the soil value set on the terrain.
Here's the same video again, only this time, it's using the soil value as it's main colour.

In this video, grey is low fertility and brown high.
I added this to see how well the plants would respond to it and it turned out surprisingly well.
This is also one of the main features of this system.
Because you can control the outcome so well by simply adding or removing fertile soil, the whole thing becomes much more friendly.
Which was the initial goal!

Conclusion

After three main iterations, lots of smaller fixes and a lot of crashing due to running out of ram for simulating I got what I looked for:
An easy to use system for realistically placing foliage.
At this point, there's only one question that needs to be answered: Is this system usable.
The answer to this is yes and no.
For a lot of situations this system might be overkill: The simulation time is fairly optimized, but still takes longer than just placing scattered foliage.
On the other hand, this system can apply a large quantity of realistically placed foliage on a large quantity of terrain so in my eyes, large open world games would definitely benefit from it.

Whilst I'm writing this, I'm also rendering out more simulations with different climates and setups so if you're looking for more, stay tuned!