8 min readJust now
–
Hello, Ash here! This article is gonna be a big one ’cause today we’re finally gonna dive **deep **into procedural world generation! There’s gonna be a lot of interesting stuff here — I made all the visualizations here myself!
What does “procedurally generated” mean?
Before we start, let me introduce myself and show you some cool stuff you can do with this technique. My name is Ashley (it’s my nickname, actually), I’m 20 years old and I study computer science. I got interested in procedural generation about 5 years ago while I was playing Minecraft. That’s really early tbh, and I only knew how to print characters to console back then, so my very first attempt looked like this:
Press enter or click to view image in full size
I used “.” and “#” charac…
8 min readJust now
–
Hello, Ash here! This article is gonna be a big one ’cause today we’re finally gonna dive **deep **into procedural world generation! There’s gonna be a lot of interesting stuff here — I made all the visualizations here myself!
What does “procedurally generated” mean?
Before we start, let me introduce myself and show you some cool stuff you can do with this technique. My name is Ashley (it’s my nickname, actually), I’m 20 years old and I study computer science. I got interested in procedural generation about 5 years ago while I was playing Minecraft. That’s really early tbh, and I only knew how to print characters to console back then, so my very first attempt looked like this:
Press enter or click to view image in full size
I used “.” and “#” characters to represent air and ground. This one is dated April 1st, 2021.
I didn’t even use Perlin noise. Instead, I spaced out pillars of different height and connected them with some curve formula I found on the internet (it was Bézier curves as I realized later). Of course, that is a really bad technique. It is non-deterministic, sometimes discontinuous and impossible to convert to 3D (even though it doesn’t seem that bothered me back then)
But, of course, I didn’t stop there. A year after, it was my school project — a pretty ambitious one, actually. While others only made presentations describing other peoples’ research, I was making a python game with procedurally generated world.
Press enter or click to view image in full size
Terrain generated in my early game
I spent about six months on this project. And I didn’t really nail it — it didn’t have character controls and building system so I just photoshopped that for my presentation. But it did have a decent world generator so I got “100%” for my project!
Now I practice this as my hobby. Here’s some of my latest works:
Press enter or click to view image in full size
Press enter or click to view image in full size
This one was inspired by John Kunz’s artwork
Press enter or click to view image in full size
I can hear you say “Hey! AI can now do that!” Yeah… No. Well, I’m pretty sure it can draw something similar, I doubt it would ever be able to do something like this:
You can find it in better quality on my Shadertoy
A procedurally generated video! So what does “procedurally generated” even mean? **Procedurally generated means generated by some definite procedure — in other words, program. **You can even write a program which will color your screen green or red based on the number you give — it will also count as procedurally generated.
Even though AI does play a big role in our lives nowadays, it is important to say that we probably can’t call mashing hundreds of terabytes of data together to get an image a “definite procedure”. While AI can generate impressive images, it’s not practical for deterministic, large-scale game worlds — especially when we need reproducibility and low runtime cost.
How are worlds generated?
In order to make this guide as accessible and easy-to-understand as possible because there are almost no guides on this topic, I’ll start from the really ground basics. Trust me, I’ve been through it :)
As you may have seen before in this article, procedural content generation is truly some kind of art — the art of drawing gorgeous landscapes or abstract paintings… with code and math instead of actual brushes! But don’t worry — You absolutely don’t need to be a programmer or mathematician to be involved (even though this knowledge won’t be superfluous). We’re gonna use node based editor so you don’t have to learn how to code.
To generate a world, we need a ground level first. It is actually really simple — you just place blocks where Y is less than your chosen base level. To keep it simple, we’ll say that it’s zero. Like that:
y < 0
This is “the function”. This function just tells us whether we should place a block or not at the specific coordinates. Running this function for every block on our grid will draw us a landscape:
Press enter or click to view image in full size
I’ll show you 2-dimensional slice of the world, but the same principles work in 3D
That’s basically it! All we need to do is to “invent” a function that will determine whether the block is solid or not. And that’s the most interesting part. Is there any function that can represent hills? Our intuition says that we can try adding sin(x) to our function. It does look like “hills”, after all!
y < sin(x)
Press enter or click to view image in full size
You can start noticing the issue here. It’s repetitive. But we can try adding more sine waves with different frequencies and amplitudes to make the terrain more interesting:
y < sin(x) + cos(x/4) - sin(x*2)/2
Press enter or click to view image in full size
Better. But still repetitive. That’s the property of the sine waves. We need something random. We can use (random) function for that!
y < random(x)
Press enter or click to view image in full size
Too chaotic. That’s actually just a white noise. For every block, we choose a random number independently from its neighbors. We need something that could combine these two properties. Something that would be continuous but random. And there is a solution! It was introduced by Ken Perlin in 1982 — the Perlin noise!
The Perlin noise
y < simplexNoise(x)
Press enter or click to view image in full size
We actually use the Simplex noise here — an improved version of Perlin noise designed in 2001. This version was made by the same Ken Perlin so we can safely call this “Perlin noise” as well — The outcome is practically the same. The book of shader’s article describes the math behind Perlin noise well— you may check it out if interested!
So that is it - the continuous function that produces random result! This function is used everywhere, not only in terrain generation: it is used in generated textures, animation effects, foliage distribution. This is the actual naturally-looking randomness!
I’ll tell you more — the trick with adding sine waves works here as well!
y < simplexNoise(x) + simplexNoise(x*2)/2 + simplexNoise(x*4)/4 + ...
Press enter or click to view image in full size
Each added noise function with double the frequency and half the amplitude is called an “octave”. You can also hear people calling this “fractal noise”. This basically means that new octaves are added making this noise self-similar. This technique makes our noise much more interesting by adding finer and finer details.
This technique is so common that people usually expose it as a parameter to the noise function:
y < simplexNoise(x, octaves=5)
You can already see hills and mountains here. By playing with frequencies and amplitudes you can already make different biomes — hills and valleys using low-frequency low-amplitude noise and mountains using high-amplitude noise.
Density
But let me tell you something — using only this technique does not provide that much flexibility. You can’t generate sheer cliffs, flat plateaus and floating islands — all the things that make Minecraft worlds so interesting. So let me introduce you to the new technique:
density = -y + simplexNoise(x, octaves=5)
Press enter or click to view image in full size
Welcome density! From now on we’re gonna draw everything as greyscale gradient. Everything below -1 is black, everything above 1 is white and everything in between is shades of gray. I’ll outline areas with 0 density with green line — that’s where border of our terrain is gonna be.
So why would we even need this at the first place? What we’re actually working with is density field, not a curved plane. Each block (each pixel, in this case) has its own density. As before, we only place blocks where the density is positive. Adding sine waves made sense because we had exactly one solution for each X. But that’s not a limit in 2D grid (especially in 3D grid like Minecraft and Hytale have).
Let me show you the 2-dimensional Perlin noise. I’ll hide the green lines for now.
density = simplexNoise2D(xy, octaves=1)density = simplexNoise2D(xy, octaves=5)
Press enter or click to view image in full size
Press enter or click to view image in full size
These are the images you’ll see if you google “Perlin noise”. Now let me show you a trick: we can take our base flat terrain —
density = -y
Press enter or click to view image in full size
…Add the Perlin noise to this:
density = -y + simplexNoise2D(xy, octaves=5)
Press enter or click to view image in full size
…And now we have a new type of terrain — it can generate sheer cliffs and floating islands. The interesting part is that we can combine properties we want with simple arithmetic! What we did now is combined horizontal properties of flat world with naturally-looking randomness of Perlin noise — isn’t it cool?
Press enter or click to view image in full size
The article gives a friendly introduction to procedural terrain generation, showing how Perlin noise and simple math alone can be used to create natural-looking game worlds, and how density fields make it possible to build cool features like cliffs, caves, and floating islands. Of course, this is just a surface of an iceberg so in future articles, we’ll try to dive deeper!
That’s all I got for today. In the next article, I’ll show you how to extrapolate these techniques to Hytale — we’ll make our own world generator. Subscribe if you don’t wanna miss it!
You also may be interested in my other articles — I often talk about worldgen in my blog. I also got lots of tutorials and technical explainers here (with cool images!)
It was Ash. Thanks for reading. Bye! 🐾