I started to work the implementation of gas giants. My current approach is to use an outer sphere with atmospheric scattering, similar to the ones used on my Earth-like planets, and a set of layers ( six at the moment ). All of those are generated and displayed with the LOD ( level-of-detail ) algorithm used in the terrain engine, except that the spherical surface is not displaced by a heightmap.
Each layer corresponds to a cloud layer with various colors and transparencies. Each layer is textured with a cube map, so I started to generate a "gas giant style" texture for each layer with random color combinations and turbulence. Here's an example of such a texture:
The upper layers in altitude get a lower transparency while the deeper layers get more and more opaque. The bottom-most layer is fully opaque, a bit like the ground.. but I don't expect anybody to really see it, since so deep in the atmosphere, any spaceship would be dead for long..
The 6-layers idea wouldn't look very good if the layers were individually visible. Fortunately, I am hoping that with good fogging, particle/wheather effects, and good scattering, everything will blend together quite well.
The gas giant texture is procedurally generated by stretching fBm noise with a large non-uniform factor, like ( 1, 30, 1 ). This generates the straight strips. To break the straightness (english?), I am actually using another fBm which returns the amount of stretching to do. In the end, it looks like this:
float res = noise.fBm(ray * (4, 4, 4) );
res = noise.fBm(ray * (1, 20 + res * factor, 1));
The first factor, (4, 4, 4), determines the size of the turbulence "features"; while the second factor ( factor ) determines how stretched the atmosphere looks. Gas giants planets are rotating very quickly around themselves, which is why their clouds are so stretched. This factor will later be determined by the astrophysical parameters of the planet like its rotation speed.
The color table at the moment is quite random. I have to study colors of gas giants and how to generate "interesting" colors. The transparency is also a function of the noise value, plugged in a simple formula. I have to tweak it too.
In the future, I will also have to experiment storms like the big red spot on Jupiter, and wheather effects such as those mentioned particles, but also lightning, etc..
While working on the shaders for gas giants, I realized that my scattering equations were not giving me the expected results.
I don't know if anybody wondered.. imagine that a gas giant didn't have any cloud - just imagine a huge ball of gas in space. How would it look like ?
Let's say the camera is in the upper atmosphere of the gas giant. The sky would appear like it does on Earth: fading from black to the sky color ( blue on Earth ), with some white haze at the horizon..
But there would be no ground. So what would you see underneath ?
Scattering equations, if I'm doing no mistake, say that it should fade back to black. The exctinction coefficients depend on how much atmosphere is traversed, and underneath the camera.. there's a lot of atmosphere to traverse.. so it should be black.
Unfortunately, in my previous atmospheric scattering implementation, I saw an ocean of... white. Certainly, I was wrong somewhere.
That's pretty much the point I decided to rewrite my atmospheric scattering shaders from scratch, carefully watching the results of all the terms of the equations.. and in GLSL !
Until now, I've been using assembly shaders ( in OpenGL, ARB_vertex_program and ARB_fragment_program ). Usually, it was good enough, as shaders were quite simple ( a few tens of instructions at most ). But scattering shaders are a whole new beast, requiring to intersect rays and spheres, and evaluating complex equations. I was loosing too much time to debug my ASM shaders, so I decided that it was time to switch to GLSL..
I expected the GLSL implementation to be straightforward.. how wrong I was. I spent pretty much my whole last week on it. For some reason, the GLSL interface works in a pretty different way than ASM shaders; in particular, shader constants do not belong to a specific shader ( vertex shader, or pixel shader ); but to a program, which is a pair vertex + pixel shader.
It's probably not clear, but let's take an example. You have a vertex shader called VertexShader1 and a pixel shader called PixelShader1. VertexShader1 uses a constant called AtmosphereParams. To assign a value to this constant, you have to query the location of this constant in the program.. the location is an ID, so maybe it'll return 1.
Now, let's say that you use the same vertex shader but a different pixel shader: PixelShader2. Well, here is the problem: if you query the location of the constant AtmosphereParams in VertexShader1, it might return another location ID.
Fixing the issue required introducing the concepts of "virtual" constant IDs, and "real" constant IDs, and mapping one to another in real-time depending on which pair "vertex shader + pixel shader" is bound..
Once my GLSL implementation was complete, I started to experiment with the GLSL language, and so far no problem with it, it's pretty easy and much easier than coding everything in assembly.