Distortions, Seamless Noise, and how to handle it.

Generating the planet

One of the simplest ways to generate a planet, is to use noise, which gives you a couple of options on which noise to use, let’s inspect each one and determine the best option:

  • Perlin Noise – Perlin Noise is the most basic option, it was developed by Ken Perlin in 1983, however it has a couple shortcomings, there are a couple visual artifacts and it’s speed at generating large images can be quite slow when compared to the other alternatives.
  • Simplex Noise – Simplex Noise was designed by Ken Perlin in 2001 in an attempt to address Perlin Noise’s shortcomings, it’s a pretty decent and fast solution however it has a major drawback, the use of 3D Simplex Noise is protected under a patent, which makes using it a pretty expensive affair.
  • Open Simplex Noise – Open Simplex Noise was developed by KDotJPG with one simple goal in mind: make a modern alternative to Simplex Noise that is free to use, that has no distortions and is relatively fast.

Out of the three I personally prefer Open Simplex Noise and is what I use for my personal projects. Do take note, the current implementation of OpenSimplexNoise needs some extra work so you can get easy access to the scale, octaves, and seeds. There is a multitude of guides out there on the internet explaining what each of these does and I highly recommend a read, however, that is not what I want to talk about in this blog post.

This is what Open Simplex Noise with 16 octaves looks like.

Seamless noise

Noise is infinite, which means if we simply give it a canvas with a ratio of 2:1 to make an equirectangular map it will not loop when you eventually try to put the map on a sphere(shoutout to this amazing website), and you will get massive variations on the horizontal seam and on the poles.

There is a multitude of ways to fix this, on this amazing blog post Red Blob Games only needs to generate an island, using a function that takes distance from the center as a variable and setting it height 0 at the edges minimizing seams.

However, this is not what we want. We want to generate a planet, with the possibility for north and south poles and to do that we are gonna need some more complex math calculations.

Spherical Mapping

A method that can generate spherical planets would be to convert the cartesian coordinates of our canvas to spherical coordinates, generate noise based on those coordinates and finally convert that noise back to cartesian and map it to the canvas.

However this implementation has its limitations, and the why and how it happens is demonstrated by Ron Valstar in this brilliant blog post mainly the fact that the shapes of the continents look extremely weird and distorted and therefore is not what I want.

Cube Mapping

The second method I ended up using was motivated by both Ron Valstar’s post and acko’s Making Worlds series of blog posts, in them, they describe the generation of a globe through generating a cube and then inflating it as if it was a balloon until it’s shaped like a sphere.

All credits to acko.net for this image, it explains the cube map concept in a easy way to visualize.

Now we simply have to generate six faces which is easy enough, there is a multitude of ways to do it.

The way I ended up doing it was by creating an array and then populating it with data. Converting the 2D coordinates of a canvas to the 3D coordinates of a cube and then generating noise for each of these 3D coordinates to then store them in the corresponding 2D coordinate value.

//Z STATIC
for(int y = 0; y < cubeFaceSize; y++) {
	for(int x = 0; x < cubeFaceSize * 2; x++) {
		//Generates FRONT
		if(x < cubeFaceSize) {
			cubeMap[cubeFaceSize+x][cubeFaceSize+y] = noise.noise3D(x, y, 0);                    
		}
		//Generates BACK
		else {
			cubeMap[cubeFaceSize*3+(x-cubeFaceSize)][cubeFaceSize+y] = noise.noise3D(cubeFaceSize-(x-cubeFaceSize), y, cubeFaceSize);
		}
	}
}
//X STATIC
for(int y = 0; y < cubeFaceSize; y++) {
	for(int x = 0; x < cubeFaceSize * 2; x++) {
		//Generates LEFT
		if(x < cubeFaceSize) {
			cubeMap[x][cubeFaceSize+y] = noise.noise3D(0, y, cubeFaceSize-x);                   
		}
		//Generates RIGHT
		else {
			cubeMap[cubeFaceSize*2+(x-cubeFaceSize)][cubeFaceSize+y] = noise.noise3D(cubeFaceSize, y, x-cubeFaceSize);
		}
	}
}
//Y STATIC
for(int y = 0; y < cubeFaceSize * 2; y++) {
	for(int x = 0; x < cubeFaceSize; x++) {
		//Generates TOP
		if(y < cubeFaceSize) {
			cubeMap[cubeFaceSize+x][y] = noise.noise3D(x, 0, cubeFaceSize-y);          
		}
		//Generates BOTTOM
		else {
			cubeMap[cubeFaceSize+x][cubeFaceSize*2+(y-cubeFaceSize)] = noise.noise3D(x, cubeFaceSize, y-cubeFaceSize);
		}                
	}
}

This way, we can generate a cube map, which is easily converted to an equirectangular map thanks to the amazing code snippet provided by Bartosz.

As you can see, the equirectangular map has much better-looking shapes, and when wrapped around a sphere it produces similar results to Spherical mapping without all its downsides, besides, an equirectangular projection can be easily converted by multiple programs, such as NASA’s G.Projector to basically any kind of map that has ever existed.

Closing Thoughts

Generating an entire planet can be a daunting task, and although noise can be quite a powerful tool if used properly it is still bound to problems that humans have had for centuries, such as how to map a globe to a 2D canvas with minimal distortion.

The solution I propose here only produces very roughly generated planets, with no regards whatsoever towards tectonic plates, rivers, proper island chains, or even mountain ranges and therefore is only really meant to be used as a demonstration or starting basis for more advanced simulations.

In fact, it only really produces a matrix of values within a certain specified range, for the greyscale images they are within 0 to 255 and are then converted to a pixel producing an image similar to the first greyscale image or on a range from -11000 to 8000 emulating real-world height differences and then painting the same color for height intervals.(eg: between 0 to 5 paint it in a sandy color to emulate beaches)

God used beautiful mathematics in creating the world.

Paul Dirac

8 thoughts on “Mapping Planets

  1. This is cool! Only skimmed, but didn’t look like you tried out generating the land/features directly on the sphere itself. If you know you’re going to just have a sphere, why not take Red Blob Games’ approach of being able to generate land at arbitrary locations, randomly generate onto the sphere, then just deal with land collisions / merging during creation?

    Liked by 1 person

    1. I figured it would just be easier to generate an entire planet all at once and ensure that no seams can generate rather than generating land like Red Blob’s approach and then having to staple them together.

      Besides, that approach is best suited to generate islands, and I want entire continents, I guess a case could be made that a continent is just a gigantic island but that would mean having some sort of grid with variable cell sizes to be able to generate islands and then merging them correctly which would be quite a task to program.

      Like

    1. I don’t understand, that’s what I did, except instead of getting 3D noise from a sphere, I got it from a cube because it ends up beeing the same and the math is way easier to explain

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s