The example below shows a progression of taking a texture map from a Bryce 3D texture page, and mapping it to a sphere using the various methods of the BitmapData class. I’ve been very excited about the ability to push around the pixels but hadn’t really taken it for a spin (har har).

The reason for doing this example is to have interesting spinning globes added to my thrust example for my eventual site redesign. I’ve been playing with this example for the last week, and while it isn’t completely done, I wanted to go ahead and quit obsessing and post it ;) Click the steps 1 through 5 to see the progression. There is a description of what is going on at each step below.


Step 1, Find the picture: I did a Yahoo! Image Search for “earth image” and found SnyderWeb (heh) which has excellent images of all of the planets and notable moons from our solar system. I took this enormous image and shrunk it down to 300 by 150 like you see in the example.

Step 2, Resize per line: The image starts as a rectangle, so the poles are really stretched. Each line of pixels needs to become two times the number of pixels needed (front and back of planet) to be displayed ob screen for that latitude. I do the calculations on how many pixels I need per line to make a circle, and use draw() to scale the big line down to the size of the line I need.

The picture above represents the final product of the full image with each line scaled as needed (left justified). In reality I am also using the copyPixels() method to duplicate each line (though not shown above). This will save calculation time when I need to be able to display the part of the globe where there would be a seam.

Step3, Give it a whirl: For my first attempt at making the globe spin, I go through each line of the warped image, and display the correct number of pixels to make a circle. To make the rotating effect, I am using a ratio that represents the amount to rotate out of one full rotation. I then find the pixel in the line that is at the same ratio and start displaying the pixels from there.

Each line then moves at different rates because the ratio is the same per line, but the line length is different. At .5 ratio, a line of 10 pixels would start copying from 5, but in a line of 50 pixels, it would start copying from pixel 25.

While this give an animating globe, you will notice that the continents don’t actually curve around the surface of the earth. It doesn’t look quite right (though I was still pretty excited when I got this far and Flash 8 was still running like a dream).

I’ve also added a couple of filter effects to make the planet have some nice lighting. Notice that the bright spot is not just a white alpha gradient. It is a blurred shape with a screen filter to actually add the channels together to change the overall lightness under the hot spot.

For my website purposes I really am going to stop here. My planets will be more like Saturn or Jupiter (amorphous banded things), so the curvature won’t be apparent. Also, as you’ll notice in the next step, the processor is going to be hit pretty hard.

Step 4, curving the X axis: Let the processor abuse begin! This new graphic warping of the X-axis can’t be done one time at the beginning like Step 2. This needs to be done every step of the rotation because when pixels are at the edges they will be crunched, and when in the middle they will be stretched. During a full revolution, every pixel of the base graphic will at some point be at the edge and also at the middle.

This being said, I can do one set of calculations once at the beginning of the animation. For each row of X pixels, I can calculate the distortion deltas. At each rotation step I can just apply this array of distortion values to the currently displayed pixels. for instance, the array may be something like [4,3,2.5,2, etc.] which means I should take the first four pixels of the line and draw them as one pixel (somehow). then for the next new pixel of the graphic I take the next three pixels and make them one. By the time you reach the middle of the graphic, the values are substantially below 1, because instead of multiple pixels becoming one, the pixels are being stretched/duplicated.

Once this is done we have a globe where the continents curve away at the sides. There are now just two problems. First, the processor is running very slowly. But the more serious problem is that my continents are too short now (well, they actually always were). To counteract the processing issue, I’m caching each calculated bitmap. After one rotation, if I call for an image that I have created once, I can pull it out of an array, rather than recalculating. You’ll notice a really big performance improvement after one rotation, but be aware that it comes at a cost. To cache the images, you have to store them in memory. For the 100 unique calculated states <eg> it takes about 8MB of memory.

Step 5, back to the initial Warp:
So the last image warp (Y axis to show curvature) can be done in the beginning since since pixels never move along the Y axis. To do this, I just repurposed my line warping function and applied it vertically instead of horizontally. Once this is done all of the continents are the right aspect ratio, and then I declare victory.

What is next? So I’m happy with where things are with this, but I do have some more work to do.

  • work on anti-aliasing better. Some of my warping scripts should be doing a better job of smoothing. You will notice that some of the coasts are a bit off where a pixel is sticking out here and there. The more warps that are applied, the more pronounced the effect is.
  • Optimize the code. I think I can squeeze out some more performance by re-examining some of the code.
  • Throw it away and do a poly-based 3D texture mapper. This works fine for X-axis rotation, but If I wanted to play god and roll the earth like a pool ball, this script just won’t cut it.