Every 6 months or so, I get a strong urge to do some more digital world-building. This usually ends up in a new approach towards terrain generation, but this time I tried to tackle a specific problem: weather patterns. Instead of trying to create visually interesting landscapes with special algorithms, I would instead generate simple “rough terrain” with Perlin-Noise and see if I could use it as a source for a weather machine. I can say now that it was a full success, but not without its problems along the way.

Why even build dynamic weather for your map? First off, its a fun coding project that poses interesting challenges. Secondly, if you have ever done any world-building, you will appreciate the additional dynamics such as erosion and vegetation made accessible through climate effects.

For this project, my map was divided into a grid. A height-map was generated using Perlin-Noise. This gave me simple hilly terrain, and below a certain height was designated water. Using this height-map, a simple wind-map was generated, by generating a random time-dependent global wind-vector. When the wind-vector pointed uphill in a grid-cell, the wind speed was higher, and when it pointed downhill the wind speed was lower.

Wind-Map: A lighter color indicates a higher wind speed. The wind-vector is global, and is imposed on every grid-cell to determine that cell’s speed. The wind vector is generated using (x,y)=Perlin(t,t)

The wind map was responsible pushing around the other two primary maps: The temperature and humidity maps (in some way representing the energy and mass balance of the system). The wind would act as a convective force to move humidity and temperature around, projecting them onto their next grid iteration using  the speed as a magnitude of the wind-vector. They would then also each have their cells averaged with each neighbor, as a way to diffuse the temperature and humidity. They also each had generative terms, coupled via cloud and humidity maps, to increase and lower their values.

The humidity-map was fed by bodies of water, where higher temperatures would lead to faster evaporation. Humidity was lost via rain, which would bring it back to the ground.

Humidity-Map: Fed by bodies of water, with occasional fronts disappearing from rainfall.

The temperature map would be fed by sunshine, which would be available anywhere where there weren’t any clouds. Temperature would also decrease as the air was pushed up-hill, and would increase as it was pushed downhill. It would also be decreased if it was raining.

Temperature-Map: Mostly follows the cloud patterns.

Cloud and precipitation maps (boolean) would have a value in a cell appear above certain threshold values of temperature and humidity, in a way so that you could have warm humid air cool down and lead to precipitation in a grid cell. The each formed interesting patterns, and were designed in such a way so that rain would behave more impulsively.

Cloud-Map: Undergoes occasional phase-shifts as the wind turns. Clouds can be seen rolling over the tops of peaks, moving along the landscape continuously and appearing and disappearing organically.
Rain-Map: Appearing in a more sporadic manner, rain tends to form at the end of the lake where the wind is headed, as the warm humid air cools and moves uphill and cools. It also appears on the sides of peaks as the wind blows it up

In effect, this is just a large ode system, where the grid cells and their respective temperature, humidity, rain, cloud and wind speed values are coupled to each other in time, along with the values of their neighboring cells.

Some issues were encountered at the boundary though. When projecting the temperature and humidity fields via convection, the cells on at least one side of the grid will project into the  grid, but won’t be projected onto. This leads to some issues in the movement of the temperature and humidity maps. This was what eventually lead me incorporate the “smoothing” via diffusive effects (the averaging/blurring of the values with the cells neighbors after every convective movement). It was also helpful to reduce the overall wind speed magnitudes, such that the depth of affected cells would be minimized.

In my project, I decided to use this dynamic weather system to try to create high-detail vegetation maps. I would simulate the weather for a total of one year (each time-step was considered a day), and I would create average maps that could be used to generate vegetation. This way I had many parameters to work with: average sunshine, average humidity, average rainfall, average temperature and average wind speeds.

First, I created general biomes using these average maps, and then planned to populate each biome with a certain random number of plants, and then have them grow more specifically using the average map values. I never got around to populating this parameter-space with plants, but instead wondered if I could render this all isometrically and see if I could draw a tree at all. So I did that instead.

Warning: Programmer art. I messed up the tile set I had made, which is why there are two iterations of block style. Also, for a short moment you can see the isometric map-view I tried first. Then I did a more high LOD rendering of the Perlin-Noise height-map.

Its not suitable for high-detail renderings of weather, but works fine if used on a macro-scale and is updated perhaps once an in-game hour. The system is fast enough to render the weather and cloud patterns extremely quickly, but the weather system itself would need to be re-balanced with a smaller increment per time-step. 

I would like to add that the tuned weather system worked remarkably well, even for different terrain. The system was good at generating the weather patterns using maps from all seeds I threw at the height-map generator, each time giving unique weather patterns and phase-shift behavior.

The entire code can be found under: https://github.com/weigert/proceduralweather

Press “Space” to cycle between game views.

Leave a Reply