Gas giant shader
Procedural generation is a fun way to create endless combinations of almost anything you can think of. Gas giant shader It works by predictably generating random numbers and then mapping those numbers to a set of rules that you define.
Here I will discuss how I generated gas giants for my procedural passion project as of June 2023. (It works on the internet, check it out!)
The structure of the project
All you need for this tutorial is a 3D engine of your choice. I’ll be using BabylonJS, but anything that can handle shaders and a bullet will work fine.
BabylonJS works on the web via WebGL and WebGPU, making it easy to distribute and open source!
You can set up the new project with a node, a typescript, and a webpack using the template I used for this tutorial: Gas giant shader
GitHub – BarthPaleologue/Babylon template
Contribute to the development of BarthPaleologue/Babylon templates by creating an account on GitHub.
We don’t need the whole template code, just a sphere with a simple camera and light. In the src/ts/index.ts file, place the following code in place of the existing one:
First, we need a pseudo number generator (ie a deterministic sequence of random numbers assigned to a seed). The seed will ensure that we don’t lose the beautiful planets we will create. Gas giant shader
Any RNG will do, but I use Squirrel Noise:
Most out-of-the-box RNGs have an even distribution, and Squirrel Noise is no different. This means that we have an equal chance of getting any number between 0 and 1.
If we stick to the unified generation, our results will be everywhere. It would be much better if we could put a higher probability of numbers around a certain value we choose. This way we keep most of the diversity but gain much more control over it.
To achieve this goal, we will use the normal distribution because it has a nice bell curve that we can compensate for in whatever way suits our needs.
Create a beautiful color palette
If we distort the colors of our gas giants they will be very ugly, so we have to be careful. I use 3 different colors, two light colors and one darker to balance it out.
To make color selection easier, we use the color space HSV (Hue, Value, Saturation) instead of RGB. The advantage of HSV is that we can directly choose the shade we want.
For the first light color, we randomly choose a shade around the blue area (here 240). We allow for high variability by setting a standard deviation of 30 to 240.
To get the second light color, we can choose the complementary color of the first. It will be a harmonious combination as long as we do not increase the saturation too much.
In HSV, getting the complementary color is easy: we just need to take the hue of our first color and add or subtract 180 (it’s on the other side of the color wheel).
On the other hand, the darker color can be of any shade, it will be very subtle because we choose a very low brightness.
It’s shadow time!
Now that we have our color palette, we need to render the cloudy surface of our gas giants.
We will first create a class to extend the BabylonJS ShaderMaterial according to our needs. We will call them GasPlanetMaterials.
As you can see, the core of the code remains the same. We simply pass it to the shader with setColor3 and setVector3.
The camera can move, as can the light source and the planet. So we pass them to the shader in an update method called “every frame”.
Your IDE might be a little annoyed because we’re trying to import shader files that don’t already exist but don’t worry, we’ll fix that very soon!
In your index.ts file you can instantiate this with:
The part where things get interesting
Now we have to program the shader, which I think is the most interesting part!
Shaders are divided into two parts: one is the vertex shader for moving (ie changing the mesh to a different shape) and a fragment shader for coloring the pixels in the mesh. That’s what we’re most interested in here, we want beautiful colors on a simple sphere.
I’ll quickly get to the vertex shader here:
The idea is to have several V
The sound is good, but it doesn’t sound like huge gas clouds. Solution? More sound of course!
We will decide where to test our sound based on more noise!
This technique is called domain warping and is very useful for getting interesting shapes that look more like giant gas clouds.
Can we create the fragment hatch now?
So first we have our example point with the starting value:
If we keep it, then we get a uniform distribution of sound over our planet, but gas giants are not uniform!
To put it simply, for each point on the planet we will sample a tone three times: once for domain distortion and twice more to interpolate between our three colors.
If you look at a gas giant like Jupiter online, you might see something like this:
One of the most striking features of gas giants is their horizontal band of clouds that span the entire planet. With simple domain warping, we don’t get these color bands.
To solve this problem, instead of sampling the noise at the position of the planet (+ the domain distortion noise), we sample the noise at the position of the planet and stretch it vertically to compress the clouds horizontally. In our fragment shader we will add something like this:
Could it be better?
This is a good start, but we lack the atmosphere that will make it much more believable.
If you’re using BabylonJS, you can use the plugin I created to easily add atmospheres to your scene:
All you need to do is download two files and add two lines of code to get:
It’s much better! You can experiment with the settings or even randomize them to get what you want.
All code up to this point is available at:
The shader code is by no means particularly fast because we calculate the noise in real-time. To speed up rendering, you can save the noise as a texture and then sample the texture in the shadow. However, you need to create a different texture for each seed.
About the rings
I wanted to keep it as simple as possible and I realize it’s already quite long. I might make an addition to explain the rings, the link will be posted here anyway.