Procedural planetary surfaces
Gaia Sky is able to procedurally generate planetary surfaces, cloud layers and also atmospheres. These can be applied to planets and moons to modify their looks. The elements that can be procedurally generated are, then, the model surface, the cloud layer and the atmosphere.
Contents
Hint
The techniques and methods behind the procedural generation of planetary surfaces in Gaia Sky are described in detail in this external article, and also in this other older article.
The procedural generation module is accessible via two distinct ways:
Using the procedural generation window to generate and modify surfaces, clouds and atmospheres interactively, in real time when Gaia Sky is running. The results are not persisted, and are lost on restart. There is an option to save the generated textures to disk as image files.
Specifying the procedural generation parameters for each object in the object’s descriptor file. This way allows for the textual definition of bodies and their procedural generation parameters. The files can be loaded at startup and distributed so that other Gaia Sky users can use them.
In the next sections, we first learn how to use the interactive procedural generation in Gaia Sky, and then we present an overview of how the process works, and how to make use of it in data files.
Using procedural generation
This section describes how to use the procedural generation module at runtime during a session.
You can bring up the procedural generation dialog by right clicking on any planet and/or moon to bring up the context menu, and then clicking on Procedural generation…. A more straightforward way is focusing on the object and clicking on the procedural generation icon in the camera info panel. This brings up the procedural generation window. In it, there are three tabs for surface, clouds and atmosphere. Use the controls in each tab to modify each of the procedural generation and atmospheric scattering parameters. Apply them in real time with the Generate [layer] buttons. Use the Randomize [layer] buttons to randomize all the parameters.
To the bottom, there are three controls.
Randomize all – randomize the surface, clouds and atmosphere of this planet or moon.
Generated texture resolution – this slider defines the texture resolution for the procedural generation. Higher resolution means more visual fidelity, but more GPU memory usage and longer processing times.
Export textures to disk – export the generated textures to disk as JPEG image files. The actual saving to disk is done in a separate thread, so this should not slow things down by a lot. The default export location is
$data/default-data/tex/procedural
(see System Directories). The exported textures are named as follows:[name]-biome.jpeg
– biome texture. Contains the elevation in the red channel and the moisture in the green channel. See Noise parametrization for more information.[name]-diffuse.jpeg
– the diffuse texture, containing the base color.[name]-specular.jpeg
– the specular map.[name]-cloud.jpeg
– the cloud layer.
Surface tab
![_images/procedural-surface.jpg](_images/procedural-surface.jpg)
The surface tab
The surface tab contains some buttons to the top (in blue) that auto-generate surfaces with parameter presets:
Earth-like – generate a planet with mountains and seas.
Snow world – generate a cold planet, with mostly snow. It may also have lakes and seas.
Rocky planet – generate a planet of rock. May also have lava.
Gas giant – generate a gas giant.
Below the preset buttons, you can find the Generate Surface and the Randomize Surface buttons.
Generate Surface – use the current noise parameters, look up table and hue shift to generate a new surface.
Randomize Surface – randomize all surface parameters and automatically generate the surface.
Then, we find the properties of the surface generation itself:
Color look-up table – the look-up table to use to generate the diffuse map for the surface.
Hue shift – an angle by which to rotate the look-up table colors in the HSL color space. This enables generating several different color palettes from the same table.
Height scale – the physical height value (in km) to map to the value 1 in the elevation map.
Add civilization (lights) – if enabled, the generation process creates an emissive map that simulates cities and civilizations by means of emissive regions (lights), visible on the dark side of the planet.
To the bottom, we find the noise parameters to generate the surface. These are described in Noise parametrization.
Clouds tab
![_images/procedural-clouds.jpg](_images/procedural-clouds.jpg)
The clouds tab
The clouds tab contains two buttons at the top:
Generate Clouds – use the current noise parameters, look up table and hue shift to generate a new clouds layer.
Randomize Clouds – randomize all parameters and automatically generate a new clouds layer.
Below the buttons, we find the Cloud color color picker, to indicate the base color of the clouds layer.
To the bottom, we find the noise parameters to generate the clouds. These are described in Noise parametrization.
Atmosphere tab
![_images/procedural-atm.jpg](_images/procedural-atm.jpg)
The atmosphere tab
The atmosphere tab contains two buttons at the top:
Generate Atmosphere – use the current atmospheric scattering parameters to generate a new atmosphere.
Randomize Atmosphere – randomize all atmospheric scattering parameters and automatically generate a new atmosphere.
Below, we find all the atmospheric scattering parameters. Those are:
Wavelengths – the values of
for the red (
), green (
) and blue (
) channels. These are the Rayleigh scattering rates of different light wavelengths.
Light brightness – the brightness of the illuminating star.
Kr – Rayleigh scattering constant.
Km – Mie scattering constant.
Fog density – density of the simulated fog when inside the atmosphere.
Fog color – the color of the fog.
Number of samples – number of samples to use to compute the atmospheric scattering in the shader.
![_images/randomize-all_s.jpg](_images/randomize-all_s.jpg)
A few planets created using the randomize all button.
Surface generation process
The surface generation process starts with the generation of the elevation and humidity data. The elevation data is a 2D array containing the elevation value in at each coordinate. The humidity data is the same but it contains the humidity value, which will come in handy for the coloring. First, let’s visit our sampling process.
Seamless (tilable) noise
Usually, noise sampled directly is not seamless. The noise features do not repeat over a period, so it can not be stitched together without presenting seams. It can not be tiled. In the case of one dimension, the straightforward approach is to sample the noise using the only dimension available, in a line, in :
![_images/noise-sampling-1d.png](_images/noise-sampling-1d.png)
Sampling noise in 1D leads to seams
However, if we go one dimension higher, to 2D, and sample the noise along a circumference embedded in this two-dimensional space, we get seamless, tileable noise.
![_images/noise-sampling-2d.png](_images/noise-sampling-2d.png)
Sampling noise along a circumference in 2D space is seamless
We can apply this same principle with any dimension by sampling in
. Since we need to create spherical 2D maps, we do not sample the noise algorithm with the
and
coordinates of the pixel in image space. That would produce higher frequencies at the poles and lower around the equator. Additionally, the noise would contain seams, as it does not tile by default. Instead, we sample the 2D surface of a sphere of radius 1 embedded in a 3D volume, so we sample 3D noise. To do so, we iterate over the spherical coordinates
and
, and transform them to cartesian coordinates to sample the noise:
The process is outlined in this code snippet. If the final map resolution is , we use N
steps and M
steps.
for (phi = -PI / 2; phi < PI / 2; phi += PI / M){
for (theta = 0; theta < 2 * PI; theta += 2 * PI / N) {
n = noise.sample(cos(phi) * cos(theta), // x
cos(phi) * sin(theta), // y
sin(phi)); // z
theta += 2 * PI / N;
}
}
Noise parametrization
The generation is carried out by sampling configurable noise algorithms at different levels of detail, or octaves. To do that, we have some important noise parameters to adjust:
seed – a number which is used as a seed for the noise RNG.
type – the base noise type. In Gaia Sky, this can be perlin 1, simplex 2, voronoi (worley) 3 or curl 4.
scale – determines the scale of the sampling volume. The noise is sampled on the 2D surface of a sphere embedded in a 3D volume to make it seamless. The scale stretches each of the dimensions of this sampling volume.
octaves – the number of levels of detail. Each octave reduces the amplitude and increases the frequency of the noise by using the lacunarity parameter.
persistence – determines by which factor the amplitude is reduced in each successive octave.
frequency – the initial frequency of the first octave.
lacunarity – determines by which factor the frequency is increased in each successive octave.
turbulence – this is a boolean value that indicates whether we apply the absolute value function to the result.
ridge – creates ridge noise. If true, the noise value is inverted.
number of terraces – the number of discrete terraces in elevation. Set to 0 to disable terraces.
terrace smoothness – the smoothness factor in the transition between terraces.
range – the output of the noise generation stage is in
and gets map to the range specified in this parameter. Water gets mapped to negative values, so adding a range of
will get roughly half of the surface submerged in water.
power – power function exponent to apply to the output of the range stage.
![_images/noise-types-annotated.jpg](_images/noise-types-annotated.jpg)
The different types of noise, sampled raw with no fractals
The final stage of the procedural noise generation clamps the output in the given range to again, so that all negative values are mapped to 0, and all values greater than 1 are clamped to 1.
We generate two noise maps, for elevation and humidity. The elevation is used directly as the height texture. The humidity is used, together with the elevation, to determine the diffuse color of each final pixel using a look-up table. The humidity value is mapped to the coordinate, while the elevation value is mapped to
. Both coordinates are normalized to
before sampling.
![_images/procedural-lut_s.png](_images/procedural-lut_s.png)
The look-up table mapping dimensions are elevation and humidity
The look-up can also be hue-shifted by an extra hue shift parameter, in . The shift happens in the HSL color space. Once the shift is established, we generate the diffuse texture by sampling the look-up table and shifting the hue. The specular texture is generated by assigning all heights equal to zero to a full specular value. Remember that all negative values were clamped to zero, so zero essentially equals water in the final height map.
Finally, the normal map is generated from the height map by determining elevation gradients in both X and Y. This is only generated when ‘elevation representation’ is set to ‘none’ in the settings. If it is set to ‘tessellation’ or ‘vertex displacement’, the normal vectors are computed from the slope of the triangles themselves and the normal map is not needed.
Footnotes
Cloud generation process
The clouds are generated with the same algorithm and a different parameter set as the surface elevation. Then, an additional color parameter is used to color them. For the clouds to look better one can set a larger Z scale value compared to X and Y, so that the clouds are stretched in the directions perpendicular to the rotation axis of the planet.
Descriptor files
This section describes how to set up the procedural generation using JSON descriptor files and how to express the parameters seen in the previous section in these descriptor files. The format is thoroughly documented in this section.
The procedural generation parameters for surfaces and clouds are described in the material
and cloud
elements. The material
element lives inside the model
element. By contrast, there are no procedural generation parameters that can be set in the atmosphere
element itself. It just holds the atmospheric scattering parameters. However, the atmosphere element as a whole can be randomized. Let’s see how to randomize these elements in the next section.
Randomize all
The easiest way to add procedural generation to an object is by using the randomize
element. It is an array which can contain the strings "surface"
, "cloud"
and "atmosphere"
. It can optionally be accompanied by a seed
element, specifying the seeds for each of the elements to randomized. A seed is a 64-bit number used to initialize the RNG (random number generator) so that it always produces the same random number sequence. If you omit the seeds the system will randomly generate them. Otherwise, they are matched to elements by their order of appearance in the arrays. If the seeds array is not long enough, the first seed is used. Let’s see an example:
{
"name" : "Exonia f",
"randomize" : [ "surface", "cloud", "atmosphere" ],
"seed" : [111, 222, 333]
}
In the snippet above we have omitted all the usual elements (color
, size
, ct
, etc.) except the name. The last two elements specify the components to randomize and their seeds. In this case, the model would take the seed 111, the cloud would take the seed 222 and the atmosphere would take the seed 333.
If any of the elements were not present in the randomize
array, it would not be generated. If the element object is present, it will be picked up though, but only if the randomize
array does not contain it. The randomize
array has precedence.
Surface description
Some of the textures in the material element, making up the surface of the body, can be procedurally generated. The procedural generation parameters are specified in the material
element inside the model
element. Let’s see an example:
"model" : {
"args" : [true],
"type" : "sphere",
"params" : {
"quality" : 400,
"diameter" : 1.0,
"flip" : false
},
"material" : {
"height" : "generate",
"diffuse" : "generate",
"normal" : "generate",
"specular" : "generate",
"biomelut" : "data/tex/base/biome-smooth-lut.png",
"biomehueshift" : -15.0,
"heightScale" : 14.0,
"noise" : {
"seed" : 993390,
"scale" : 0.1,
"type" : "simplex",
"persistence": 0.5,
"frequency" : 5.34,
"lacunarity" : 2.0,
"octaves" : 10,
"numTerraces": 3,
"terraceSmoothness": 15.0,
"range" : [-1.4, 1.0],
"power" : 7.5
},
}
}
Usually, the diffuse
, height
, normal
and specular
elements contain texture image file locations. However, if they are set with the special token "genearte"
, they will be procedurally generated by the system using the process described above.
Color look-up table
The color look-up table is specified in the biomelut
element as a pointer to a data file. The hue shift is specified in biomehueshift
, and contains the shift value in degrees.
Noise parameters
The noise parameters described in this section above can be specified in the noise
attribute. The parameters translate 1-to-1 to what is described above, so they are pretty much already covered. If the noise parameters are not there, they are randomly initialized. These noise parameters are used to produce the elevation data and the humidity data.
Cloud description
The clouds description goes in the cloud
attribute. It contains the size of the clouds sphere (in km) and the parameters for the model.
Then, in cloud
we can either specify a texture image file, or we can use the reserved token "generate"
. If this is there, we can specify the noise parameters just like in the material. If the noise parameters are not there, they are randomized automatically.
"cloud" : {
"size" : 2430.0,
"cloud" : "generate",
"params" : {
"quality" : 200,
"diameter" : 2.0,
"flip" : false
}
"noise" : {
"seed" : 1234,
"scale" : [1.0, 1.0, 0.4],
"type" : "simplex",
"persistence": 0.5,
"frequency" : 4.34,
"lacunarity": 2.0,
"octaves" : 6,
"range" : [-1.5, 0.4],
"power" : 2.5
}
}
Atmospheric parameters description
The format for the atmospheric scattering parameters is documented in this section. If the value atmosphere
is in the array of randomize
, the atmospheric scattering parameters will be randomized automatically.