Create procedural planet globes

Original author: metriximor
  • Transfer
Distortion, seamless noise and how to work with them.

image

We generate a planet


One of the simplest ways to generate a planet is to use noise. If we decide to choose it, then we have a couple of possible options. Let's look at each and determine the best:

  • Perlin Noise is the easiest option. The Perlin noise was developed by Ken Perlin in 1983, it has a couple of drawbacks - visual artifacts and the speed when generating large images rather low compared to other options.
  • Simplex Noise (Simplex Noise) - was developed by Ken Perlin in 2001 as an attempt to eliminate the defects of Perlin noise; this is a very worthy and quick solution, but it has a serious drawback: the use of three-dimensional simplex noise is protected by a patent, which makes it quite expensive.
  • Open Simplex Noise - KDotJPG was developed with one simple goal: to create a modern and free version of simplex noise, relatively fast and without distortion.

Of these three, I personally prefer Open Simplex Noise, which I use in my personal projects. It is worth noting that in the current OpenSimplexNoise implementation , additional work will be required to gain easy access to scale, octaves and generators . There is a lot of information on the Internet about what each of these elements does, and I highly recommend that you study it. However, in my article I will not talk about this.


Here's what Open Simplex Noise looks like with 16 octaves.

Seamless noise


The noise is endless, which means that if we just create a canvas with a 2: 1 aspect ratio to get an equally spaced projection , it will not be looped when superimposed on the sphere (I express gratitude to this amazing website), but on the horizontal seam and at the poles huge differences.

image

Noise created without seams.

image

Notice the huge seams that appeared when the noise was applied to the sphere.

There are many ways to fix this; For example, in this excellent post of Red Blob Games [ translation on Habré] it was enough just to generate an island using a function that receives the distance to the center as a variable and sets the height 0 at the edges to minimize seams.

However, this is not what we need. We want to generate a planet with the possibility of the existence of the north and south poles, and for this we will need more complex mathematical calculations.

Spherical overlay


A method that can generate spherical planets is to convert the Cartesian coordinates of our canvas to spherical coordinates, generate noise based on these coordinates, and then convert the noise back to Cartesian coordinates and apply it to the canvas.

However, this implementation has its limitations, the causes of which are shown in an amazing post by Ron Valstar . Most importantly, the forms of the continents in this case look extremely strange and distorted, and therefore we will not use this option.

image

Spherical noise overlay. Strange shapes and distortions make the continents pretty ugly.

image

But at least there are no more seams.

Cubic overlay


As a result, I used the second method, taken from a post by Ron Valstar and a series of articles by acko Making Worlds . They describe the generation of a globe through the generation of a cube and its "inflation", as if it were a balloon, until it was an example of the shape of a sphere.


Image taken from acko.net. It explains the concept of a cubic map in a simple visualized way.

Now we just need to generate six faces, which is quite simple, there are many ways to do this.

In the end, I decided to create an array and populate it with data. I converted the 2D coordinates of the canvas to the 3D coordinates of the cube, and then generated noise for each of these 3D coordinates so that I saved them to 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);
		}                
	}
}

In this way, we can create a cubic map that can easily be converted to an equally spaced projection using the wonderful code written by Bartosz .

image

Algorithm generated cubic map.

image

Equidistant transformation of a cubic map.

image

A cubic map globe rendered on maptoglobe.com .

As you can see, an equidistant map has much more beautiful forms, and when superimposed on a sphere, it creates results similar to spherical superposition, without all its drawbacks. By the way, equidistant projection can be easily converted by different programs, for example, NASA G.Projector , into almost any type of card.

Finally


Generating an entire planet can seem like a daunting task, and although noise when used correctly is a pretty powerful tool, it has its own problems that people have been facing for many centuries, such as overlaying a globe on a 2D canvas with minimal distortion.

The solution I proposed creates very roughly generated planets that do not take into account tectonic plates, rivers, chains of islands and even mountains, and therefore it can be used only as a demonstration or as a basis for more complex simulations.

In fact, it only creates a matrix of values ​​in a certain range of values. For grayscale images, this is 0-255. The values ​​are then converted to a pixel that creates an image similar to the first image in grayscale, or to an image in the range from -11000 to 8000 to simulate a real-world height difference, after which the pixels are colored in accordance with the height intervals (for example, values ​​from 0 5 are colored in sand color to simulate the coast) .

In building the universe, God used higher-level mathematics.

- Paul Dirac

Also popular now: