PDF

This page describes the code used in the Papervision3D clouded planet Earth tutorial and source post.

Planets and Earth

Since I’m trying to learn Papervision3D to make a spaceshooter, I’ve decided to make a generic Planet class and a subclass, Earth, which provides specific planet details such as textures and clouds. This way I can easily create new kinds of planets, including ones with procedurally generated textures.

In pseudo code, here’s how the Planet and Earth classes work together:

So in effect I’ve separated how the planets are created from how the materials are created, which greatly reduces the boilerplate code we’d need and gives us a proper place to keep our embedded textures.

Planet code

Let’s begin with the Planet baseclass.

As you can see the constructor is rather large. This is because there are many aspects of the planet’s quality you can control. In addition there are some parameters that go to Planet’s superclass RealtimeDisplayObject3D. I haven’t mentioned this class yet, because it is outside of the scope of this article and I’ve written a blogpost about it earlier. In short, it is a very simple class that performs updates based on time events rather than frame events, so that we can update a planet in realtime (such as the clouds) instead of how many fps we get.

The quality parameter only controls the quality of the main sphere with the land texture. In theory it could be passed down to the subclasses in the createMaterial() methods giving the subclasses like Earth a chance to change the quality of the materials. This way you could for example create three versions of the same planet for different distances from the camera, so that far away planets have very low detail quality.

The glowsize constant determines both the size of the masking discs and the planet’s glow. These need to be the same size since otherwise you could get a glow outside the planet. Also, I’ve been unable to determine the right size for the planes with the gradient masking discs to exactly cover the planet, so I’ve used a magic modifier of 1.06.

As you can see the sphere’s are created with materials obtained from other methods like createPlanetMaterial(). These are provided by the Earth subclass.

For these planes to work they should always face the camera, or otherwise the planet’s fresnell glow for example would completely mess up. For this I use planetMask.lookAt(camera), which works fine except that they face the opposite direction. For some reason the lookAt() function makes the planes look at the opposite direction.

To solve this you can make the material doublesided, or you can just flip the normals (faces) of the planes.

I’ve used layers for everything here, because now I can manage exactly what is shown on top of what. This is necessary since the default sorting mode is Z-based; In this scenario it can happen that the glow is rendered beneath the spheres. To avoid a lot of boilerplate code I’ve made a utility function out of this in a class I made called PV3DUtil.

This is a tricky bit I had to use Google a lot for. In Flash, alpha masks only work if both the masked sprite and the masking sprite are cached as bitmaps. Ultimately, everything in Papervision3D is drawn to ordinary bitmap objects. Luckily the Papervision3D folks realized this and added many opportunities to make use of this: in our case by masking spheres by planes through the use layers.

This method creates the gradient masking disc, which is opaque until the very end. There is a fading border on the edge of about 1 or 2 pixels thick to take of the edge of the mask.

gradient mask

So this mask is applied to the entire planet, both land/cloud spheres. The planet’s glow goes on top of all this which has the exact same size as the mask so that it fits nicely.

This should be straightforward. Rotate the planet a little bit as well as the clouds. Make the glow plane look at the camera and have the masking planes do the same by simply copying this information from the glow plane.

One note is in order perhaps: I’ve mentioned Planet extends RealtimeDisplayObject3D. I haven’t used this to use realtime rotation for the planets, which I could’ve done as well. Instead, rotation is done based on frame events while Earth updates the clouds animation (not rotation) based on time events.

Earth code

One of the neat things of having subclasses for planets like this is the fact that you can now store textures per planet in a separate class. To me that’s nice and clean code.

This is the magical realtime cloud object. We’ll store a reference to it in Earth, so we can update these clouds as we see fit. This realtimeCloudsTexture is actually a glorified Sprite which is used in a shaded material.

The last four parameters are planet rotation speed, cloud rotation speeds, realtime update frequency in millimeter and phase value per second spread out over the updates per seconds (the frequency).

This is where it gets interesting. Here, we’re creating a PhongShader using the geological data texture, so that we can apply a sunlight to it. In addition we’re using a heightmap as bumpmap to make the planet’s surface a little bit more dynamic and interesting.

Phong shaded geological texture

The cloud material is exactly like the geological data material, except instead of passing a BitmapMaterial into the ShadedMaterial, we’re passing in a MovieMaterial. This is because now we can specify that our texture has transparency and that it is animated. Transparency because we still want to see the Earth underneath the clouds and animated because we’re providing realtime clouds updates.

Phong shaded clouds texture

Cloud code

As stated in the blog post, the clouds have an alpha channel which is updated in runtime with a perlin noise map.

So the phases represent the progression of the clouds in time and map directly to the octaves properties in the perlin noise map we’re using. The cloudsBitmap passed in is never modified. Instead we treat it like a blueprint, copying it each frame and applying the alpha channel modifications. This was necessary to avoid stacked alpha channel modifications.

So this is actual code that modifies the cloud coverage. Four steps happen here:

  1. Create a low quality progressed perlin noise map
  2. Resize the perlin noise map to the size of the clouds texture
  3. Apply the resized noise map to a copy of the clouds texture blueprint
  4. Draw the entire combination on itself as the new clouds sprite used in the moviematerial