Multitexturing for "realistic" planet rendering

I am working in a project that requieres accurate rendering of planets. Some planets may have as many as 4 textures.

Coloured Texture
Normal Map Texture
Night side texture
Cloud texture

The program will run in a card that has 4 texturing units, so I am hoping that it is possible to achieve all the effects without using shaders. For now I haven’t implemented Normal Mapping, because it is only important for close ups (which is not vital right now), however I am having problems with night+cloud texturing.

I am relativly new to multitexturing (had only used it for detail texturing using GL_ADD_SIGNED_EXT), so I know my logic is failing somewhere. After looking at the results I have to assume GL_PRIMARY_COLOR_EXT is not giving me what I expected (the lighting value for a pixel) in the third pass. I have a working version using glBlend, but it requires 2 passes, and therefore is a tad slower.

Here is the relevant code:

// Earth texture (Unit 0)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
// Cloud texture (Unit 1 or 2)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT,  GL_PRIMARY_COLOR_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT,  GL_PREVIOUS_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT,  GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT,  GL_INTERPOLATE_EXT);
// Night texture (Unit 1 or 2)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT,  GL_PREVIOUS_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT,  GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT,  GL_PRIMARY_COLOR_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT,  GL_INTERPOLATE_EXT);

Earth texture is loaded as GL_BGR
Cloud texture is loaded as GL_LUMINANCE
Night texture is loaded as GL_LUMINANCE

I have tried rendering first the night texture, then the clouds, and the other way around. Here is a screenshot of the results I am getting:

Thanks in advance for your time and help.

Your use of + is flawed and your final image seems to ignore cloud alpha (looks like it’s a homogeneous atmospheric value), and your penultimate image seems wrong by and reasonable conclusion (there is no night contribution).

Here’s what you need, + means addition and * means modulation, illumination is the sunlight term (dot product with normal). You may want to do something fancier w.r.t. clouds or even split out the lights and give a bit of burn through the clouds:

(Earth * illumination + night * (1-illumination)) * (1-cloud_alpha) + cloud_color * illumination * cloud_alpha

You could refactor this if you like, I’ve split it by cloud alpha hence all the illumination modulations. It’s all easy in a shader.

Adding atmosphere would be a similar term to clouds, you’d probably sum the alpha and blend the colors (if different) with clouds before the rest of the calculations.

Obviously it assumes lights get switched off during the day and based on your images exaggerates the artificial light contribution.

Thanks for your help!! but could you please elaborate a bit more?? (code snipptes would be useful)

You suggest the equation

(Earth * illumination + night * (1-illumination)) * (1-cloud_alpha) + cloud_color * illumination * cloud_alpha

the first factor, call it p1 = (earthillumination+night(1-illumination)

is achieved by this code: (I think)

// Earth texture (Unit 0)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
// Night texture (Unit 1)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT,  GL_PREVIOUS_EXT); // earth
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT,  GL_TEXTURE);      // night
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT,  GL_PRIMARY_COLOR_EXT); // illumination
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT,  GL_INTERPOLATE_EXT);   // p1 == earth*illumination+night*(1-illumination)

The problem I see is that now I need to multiply (MODULATE) this resulting color by a second term p2=(1-cloud_alpha) and add the third term p3=(cloud_colorilluminationcloud_alpha).

The multiplication for term p2 can be achieved by then doing:

// Cloud alpha (Unit 2)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT)
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT,  GL_PREVIOUS_EXT); // p1
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT,  GL_TEXTURE);      // cloud_alpha
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT,  GL_MODULATE);     // p2 == p1*(1-cloud_alpha)

But now I would need to use a 4th texturing unit for the rest, remeber I need to achieve earth+clouds+night in just 3 texturing units.
I think maybe I am missing something very obvious, please help me understand.

PS: The Cloud texture (as the night texture) is really just a grayscale texture loaded as GL_LUMINANCE, I can convert it to GL_LUMINANCE_ALPHA if requiered, but the data would just be duplicate.

Since you don’t have a cloud color but only cloud alpha, I assume the clouds should be white. Then you can leave the cloud color term out of dorbies equation. Then you have just another interpolation of the result of stage 1 with the illumination and cloud alpha.

(Earth * illumination + night * (1-illumination)) * (1-cloud_alpha) + illumination * cloud_alpha

So unit 0 and 1 would be as you posted, and unit 2 would be GL_INTERPOLATE with GL_SRC_COLOR(GL_PREVIOUS), GL_SRC_COLOR(GL_PRIMARY_COLOR), GL_ONE_MINUS_SRC_ALPHA(GL_TEXTURE)…

I agree perfectly with your logic, but some clarifications, remember that clouds is a GL_LUMINANCE, so the only thing I DO have is COLOUR, not ALPHA, just thought I would clear that up.

Now you suggested:
“So unit 0 and 1 would be as you posted, and unit 2 would be GL_INTERPOLATE with GL_SRC_COLOR(GL_PREVIOUS), GL_SRC_COLOR(GL_PRIMARY_COLOR), GL_ONE_MINUS_SRC_ALPHA(GL_TEXTURE)”

Now remembering that I have GL_LUMINANCE and not GL_ALPHA the last line would change to:

GL_ONE_MINUS_SRC_COLOR(GL_TEXTURE)

and now, if we change the order of sources (swap source0 with source1) we can change that last line to:

GL_SRC_COLOR(GL_TEXTURE)

And the final code becomes:

GL_SRC_COLOR(GL_PRIMARY_COLOR),
GL_SRC_COLOR(GL_PREVIOUS),
GL_SRC_COLOR(GL_TEXTURE)

Which is EXACTLY what I had tried in my original post. I DO NOT understand why this is happening, could this be some kind of driver bug???

The funny thing is that the multitexturing works fine for clouds, and works fine for nightlights, but when using both of them it breaks.

PS: Just so you know, I tried the code you suggested AS IS, and got the same results as I did originally.

Well, I don’t know anything of cloud rendering but it seems to me that your “cloud color” is indeed the alpha Overmind spoke of. You use the cloud to determine how visible the earth ist, right? So youc an ideed use it as alpha.

What equation where you going to implement at the beginning?

Just so you know; after doing a flash update of my vid card and updating my drivers (I was running on a laptop with linux) everything works properly. Sadly I know don’t know weather it was the driver update or the flash upgrade that fixed the problem. I think the problem was that only the first two texturing units were working/enabled for some reason.

To the admin: I suggest deleting this whole thread, as nothing new may be learnt from it (other than updating your drivers and flashing your vid card frequently).

PS: I am very sorry for wasting your time, the thing is, I always doubt my coding before even beginning to think in a driver/hardware bug.

I do earth rendering with a decal, a gloss map, and a terminator ramp (1D). The specular reflections from the water & ice are visually significant (look at Mexico in this picture.) The terminator ramp lets me control the light over the terminator directly. Obviously I’m using shaders.

I include a fogging effect at the planet limb to represent looking through more atmosphere. I also include an atmosphere (separate shader) that provides a front lit haze beyond the limb, and a back lit haze when looking toward the sun.


Knowing what the earth really looks like is important. Here is an example of a photo from space and a rendering of the same place.

It’s still an interesting thread.

Would that be useful ?
http://home.comcast.net/~s-p-oneil/

SeskaPeel.