Eat The Planet
Disclaimer: This post is a condensed version of a series of blog entries originally written in 2017 for an older version of this website. I’ve revived them here to preserve and share the journey of creating my procedural planet generator. The content has been slightly updated and cleaned up for clarity, but it remains a snapshot of my progress and ideas from that time.
For a quick visual glimpse of the project, check out these two trailers I made back in 2017:
Now, back to the blog post…
An Almost Hex Planet Procedural Generation#
Over the past few weeks, I’ve been working on a procedural planet-generation algorithm that creates a globe composed mostly of hexagonal tiles. I’ve seen many map generators that inspired this project, but I wanted something that goes beyond 2D maps—something that creates an entire planet.
Summary:
The algorithm starts by generating a procedural mesh subdivided into hundreds of tiles. It uses tectonic plates to determine elevation and form continents. Heat, humidity, and winds are then simulated to create a climate system. Finally, biomes are assigned to each tile based on these factors.
Quick Tour:
- Procedural mesh generation: Start with a regular icosahedron and subdivide it. Next, create a dual polyhedron to form a sphere made up of hexagons and a few pentagons.
- Tectonic plates & elevation: Assign tiles to tectonic plates and give them movement vectors. The interaction between these plates creates elevation: mountains, trenches, and so on. Elevation is then smoothed and adjusted, resulting in oceans (elevation < 0) and land (elevation > 0).
- Winds: Currently random. Large-scale wind vectors are assigned and then blurred for smoother patterns.
- Temperature: Tiles receive heat based on their position relative to the equator. Heat spreads through wind and radiates back into space if it becomes too intense.
- Humidity & precipitation: Ocean tiles add moisture that the wind spreads across the planet. Where relative humidity is high, rain forms.
- Biomes: Each tile’s biome is determined by temperature, elevation, and precipitation ranges.
Procedural Mesh Generation#
To start, I began with a simple icosahedron and subdivided it to form the base sphere. Managing subdivisions and neighbors was simplified by using a half-edge data structure (i.e., a doubly connected edge list). Once I had a detailed sphere, I generated a dual polyhedron, converting original vertices into faces—this gave me a planet made up mostly of hexagons and a few pentagons.
The subdivisions helped create a solid mesh structure, but I needed more than just triangles. By forming the dual polyhedron, I ended up with a tessellation of hexagons and pentagons. The pentagons are unavoidable, as a perfect hex-only sphere is impossible.
With the dual polyhedron complete, I got something like this:
This tiled sphere became the foundation upon which everything else was built. Because you cannot form a perfect sphere solely out of hexagons, pentagons are unavoidable.
Tectonic Plates#
Next, I created tectonic plates by selecting several “root” tiles and assigning each tile to its closest root. This effectively formed plate boundaries.
Then, I assigned a movement vector (rotational) to each plate around the planet’s center:
Using these boundaries, I calculated pressure where plates meet. Depending on their interaction (colliding, pulling apart, or sliding), I formed features like mountain ranges or trenches. After smoothing elevations inward, areas below zero elevation became ocean, above zero became land.
Here is one example after processing elevation:
And another view, highlighting different continental features:
The tectonic-based elevation gave the world more realistic geological complexity.
Planet Climate#
With elevation done, I tackled climate. Although I hope to eventually have a system where winds depend on temperature gradients, I started with random wind “roots” for simplicity. This allowed me to spread heat and humidity across the globe, testing my simulation loop.
The steps are:
- Assign random wind “roots” and derive wind directions from them.
- Spread heat from the equator and balance it through wind and radiation.
- Compute humidity from oceans and let wind distribute it. High relative humidity leads to rain.
An example of a random wind pattern:
Heat distribution: tiles near the equator get more sunlight and thus more heat. Wind moves heat around, and if a tile gets too hot, it radiates heat into space. After enough simulation steps, I ended up with stable but varied temperature zones.
Another perspective shows the transitions between cooler and warmer regions:
Humidity comes from the oceans and is carried by the wind. When relative humidity gets too high, it rains, adding a hydrological cycle to the simulation. Over many iterations (like simulating a year’s worth of days), precipitation patterns emerge.
Pathfinding#
For pathfinding, I implemented A*. I reorganized tile data so each tile knows its neighbors, making it easy to traverse the globe. A tile-based traversal cost can later be assigned based on biome or terrain.
This sets the stage for strategic gameplay, where units could navigate varied landscapes efficiently.
Biomes#
After establishing temperature, precipitation, and elevation, it was time for biomes. Each tile got a biome depending on its climate and height. Initially, I gave each tile its own material, which looked interesting but caused performance issues due to the massive number of draw calls.
To fix performance, I later grouped tiles by biome type, drastically reducing draw calls and boosting FPS.
Improving Tile Materials#
To enhance the planet’s look, I improved the atmosphere rendering and adjusted materials, for example by slightly lowering ocean tiles to give depth and a more 3D look.
By adjusting colors and ocean depth, the visuals became richer and more appealing:
Reworking Rendering#
To optimize rendering further, I combined tiles of the same biome into single sections, reducing thousands of draw calls down to about twenty. This optimization let me comfortably handle large maps without frame rate issues.
Here you can see two much more expansive planets running smoothly:
Tile Resources & Meshes#
Next, I introduced resources. Certain biomes have a chance to spawn resource-bearing features: trees for wood, stone deposits for minerals, etc. Using instanced static meshes for these resources kept draw calls low while adding richness and variety to the planet’s surface.
From forests to mineral deposits, these features help turn the planet from a static background into a living world.
Modular Meshes#
Just different colors on tiles wasn’t enough. I wanted 3D meshes that blend smoothly between tiles, like connecting mountains across multiple tiles. To achieve this, I experimented with mesh relaxation (like Lloyd’s Algorithm) to regularize tile shapes and carefully aligned modular pieces.
I aligned each tile’s meshes by choosing a reference neighbor and rotating at 60-degree increments rather than relying solely on neighbor centroids. I also scaled meshes based on tile area to prevent overlap.
Now, with modular features and lowered ocean tiles creating cliffs, the planet has taken on a truly dynamic 3D appearance:
As the planet evolves—through changes in mesh generation, tectonics, climate simulation, and resource distribution—I’m getting closer to a fully playable environment. It’s been a challenging yet rewarding journey, and I look forward to refining the details and adding new layers of gameplay on top of this procedural world.
note from Filippos in 2024: unfortunately this project never made it to a complete game…