Reply to comment
Create the Earth and heavens in less than an hour with Away3D
3D is one of the many cool things made possible with Flash Player 9 and the super fast Virtual Machine. This tutorial will show you how to create a realistic looking interactive earth, complete with a sun and a starlit sky. Scared? Don't be - it's easy with Away3D!
3D is all the rage in the Flash community these days. There are several engines available and each has strengths and weaknesses. Carlos Pinho has compiled a nice list of what's available. For this tutorial, we'll use the engine called Away3D that can produce some really beautiful results.
This is how the finished result of this tutorial will be. Click and drag with the mouse to orbit the earth.
The scene is obviously not technically correct, but good enough for our purpose.
Step 1: Getting the software
Create a folder on your harddrive and name it "Earth3D". Download Away 3D from the main download page http://away3d.com/downloads/. The version used for this tutorial is 2.0 and it's called "away3d_2_0_0.zip". This tutorial should work with later versions when they arrive.
Put the file in the "Earth3D" folder you just created and expand it. When expanded, you'll get a new folder called "away3d_2_0_0". Inside the folder, you'll find two more folders called "away3d" and "nochump". Move these two folders into the "Earth3D" folder and delete the "away3d_2_0_0".
Open Flash, create a new Flash file (Actionscript 3) and save the file in the "Earth3D" folder as "earth3D.fla". Set the background to a dark color. That's it for the preparations.
Step 2: Preparations
If you don't have too much experience with Actionscript 3, some of this code may seem new to you. I'm assuming that many of those testing this may be designers with limited AS3 experience, so if you're a seasoned coder you may skip ahead of explanations like the one below.
For Away3D to work, we'll need to tell Flash what parts of the 3D engine we want to use. This is done using the "import" statement. There are several parts we need, so multiple import statements are required. You can probably guess from the names what some of these will enable us to do.
Click frame 1 on the timeline and open the Actions panel. Copy the code below and paste it into the Actions panel.
// import the required parts of Away3D import away3d.containers.*; import away3d.core.base.*; import away3d.primitives.*; import away3d.materials.*; import away3d.core.utils.Cast; import away3d.cameras.*; // import some filters we'll use later import flash.filters.BitmapFilter; import flash.filters.BitmapFilterQuality; import flash.filters.BitmapFilterType; import flash.filters.GlowFilter;
We'll also need to store some variables to hold information about rotation, mouse interaction and more. Copy and paste the lines below just after the import statements.
// variables var move:Boolean = false; var lastPanAngle:Number; var lastTiltAngle:Number; var lastMouseX:Number; var lastMouseY:Number; var skies:Sphere;
Step 3: Setting up the 3D environment
Just as in Flash, Away3D has a stage where you do your "drawing". In Away 3D, we refer to this as a Scene3D. Since this is 3D, we can move freely around between 3D objects. For this purpose we'll need a camera. Away3D offers 3 kinds of cameras:
- Camera3D - Moves around freely in 3D-space
- TargetCamera3D - Targets an object
- HoverCamera3D - Hovers around an object
Since we want the camera to orbit the earth, we'll use a HoverCamera3D. This is also the camera that is the easiest to use for beginners trying out 3D. Notice that in the code below we'll set both zoom and focus, just as on an ordinary camera.
In addition we'll also need a viewport (View3D). Paste the code below after the existing code.
// Set the scene
var scene:Scene3D = new Scene3D();
// Create and set up the camera
var camera:HoverCamera3D = new HoverCamera3D({zoom:2, focus:200, distance:400});
camera.targetpanangle = camera.panangle = -180;
camera.targettiltangle = camera.tiltangle = 15;
camera.yfactor = 1;
var view:View3D = new View3D({scene:scene, camera:camera});
// Add viewport to the Flash display list so it's visible
addChild(view);
// Adjust view
view.x = 230;
view.y = 200;
Apart from creating the Scene, Camera and View, we are also setting some initial properties. The HoverCamera is always looking at the centre of the stage (unless you change this) and we use the properties "panangle" and "tiltangle" to rotate around this point in 3D space. Now we have all we need except something to look at. We'll start be creating a basic looking sphere that will be our basis for the earth. Paste the code below after the existing code.
var globe:Sphere = new Sphere({material:"blue#white",radius:150,segmentsH:18, segmentsW:26});
view.scene.addChild(globe);
view.render();
As you see from the code above, we are sending some properties into the constructor function. The material, the radius and the number of triangular segments the sphere is built from. We'll use more complex textures later, but for now we'll just use a standard blue wireframe material with white edges. The radius property should be obvious, but segmentsH and segmentsW sets the mesh resolution for our sphere.
Now it's time to test the file! Hit CTRL+Enter (Apple-Enter on Mac) to view our sphere through the camera. By adjusting the panangle, tiltangle, zoom, focus and distance parameters, you can experiment to see how the HoverCam works.
Step 4: interactivity
Viewing the sphere is alright, but we want to be able to play around with it ourselves. To do this, we have to read the position of the mouse, but only when the mouse-button is pressed. Paste the code below after the existing code.
function MouseDown(event:MouseEvent):void
{
lastPanAngle = camera.targetpanangle;
lastTiltAngle = camera.targettiltangle;
lastMouseX = stage.mouseX;
lastMouseY = stage.mouseY;
move = true;
}
function MouseUp(event:MouseEvent):void
{
move = false;
}
function onEnterFrame(e:Event):void
{
// rerender viewport
var cameraSpeed:Number = 0.3; // Approximately same speed as mouse movement.
if (move) {
camera.targetpanangle = cameraSpeed*(stage.mouseX - lastMouseX) + lastPanAngle;
camera.targettiltangle = cameraSpeed*(stage.mouseY - lastMouseY) + lastTiltAngle;
}
camera.hover();
view.render();
}
addEventListener(Event.ENTER_FRAME, onEnterFrame);
stage.addEventListener(MouseEvent.MOUSE_DOWN, MouseDown);
stage.addEventListener(MouseEvent.MOUSE_UP, MouseUp);
The first of these three functions will be executed when the user clicks the stage. We set this up by creating a function that will accept mouse input (a MouseEvent). At the end of the code block above, we connect this function to the stage using the "addEventListener" command. At the click, we record some values from the camera and mouse and then set the "move" variable to true, allowing rotation. The next function is set up the same way, but it only turns off the "move" variable.
The last function will be executed on every frame. If the mouse is down (move is set to true), we'll update the rotation based on the current and former mouse position. These last two steps are the most complex parts of this tutorial. From here on it's all fun - export the SWF to give the sphere a spin!
Step 5: Adding a texture
When looking for a suitable texture for the Earth, I came across JHT's Planetary Pixel Emporium a great site offering beautiful texture maps of the earth and the rest of the planets in our solar system. All the textures are based on publicly available sources and can be used freely. The site offers some extremely high resolution images at a nominal charge as well as freely downloadable ones in low resolution. We'll also use some modified versions of these so, we've collected the ones we'l use in this ZIP file (3.1Mb). Download and expand the file in your project directory.
Back in Flash, select File -> Import -> Import to Library and locate file "earthmap1k.jpg". Once the file is imported, open your Library (Window -> Library), right click the image and select "Linkage" from the dropdown menu. Check the "Export for Actionscript" checkbox.
This will allow us to use the image directly in Away3D like this:
globe.material = new BitmapMaterial(Cast.bitmap("earthmap1k.jpg"));
Export the file to see the earth in all it's glory.
Step 6: Add some skies
It looks good, but kind of flat don't it? Let's see what we can do about that. The earth has an atmosphere with skies around it. If we add this, it'll provide depth. Away3D can use any bitmap that Flash supports as a texture. By adding a sphere with a transparent PNG file depicting the clouds, we'll be able to see the globe behind the skies. We can also rotate the skies separately from the earth itself for some added depth.
Import the file "earthcloudmap.png" to your Library and use the Linkage dialogue to make it available for Actionscript as done before. This images is composed of two of the files from JHR's site.
skies = new Sphere({material:"earthcloudmap.png",radius:153,segmentsH:18, segmentsW:26});
view.scene.addChild(skies);
Export the movie. Looks a bit broken maybe? What is happening here is that Away3D does not render the two spheres properly by default.
Locate the line in the code where we created our view and change it to this:
var view:View3D = new View3D({scene:scene, camera:camera, renderer:Renderer.CORRECT_Z_ORDER});
This last parameter will make the 3D engine do a proper Z-sort of all objects. We will also need to import a new class at the top of the document for this to work:
import away3d.core.render.*;
This line will import the required renderer. The result looks better, but it's also a little slower. Export to see the result. Let's make the skies move a bit as well?
Change the onEnterFrame function to this:
function onEnterFrame(e:Event):void
{
// rerender viewport
var cameraSpeed:Number = 0.3; // Approximately same speed as mouse movement.
if (move) {
camera.targetpanangle = cameraSpeed*(stage.mouseX - lastMouseX) + lastPanAngle;
camera.targettiltangle = cameraSpeed*(stage.mouseY - lastMouseY) + lastTiltAngle;
}
camera.hover();
view.render();
if(skies)
skies.rotationY += .015;
}
The two last lines here is the only change. If the skies exist, we'll apply a slight rotation to it (0.015 degrees per frame). This makes the scene even more convincing. Test it and see for yourself.
Step 7: Add stars
Let's add the stars while we're at it. When looking for a stars texture, I found this tutorial created for a different purpose. The resulting image looks like it could work and since this is a published tutorial from an educational resource with sample files created from scratch, we'll assume that it is legal to use the "star_map_small.jpg" texture for our purposes.
The camera itself is positioned 400 units from the centre of the Scene. As long as we make our sphere larger than 400 units, the camera will be inside the sphere, looking at the inside of it. Let's try this out:
var heavens:Sphere = new Sphere({material:"star_map_small.jpg",radius:1200,x:0,y:0,segmentsH:9, segmentsW:9});
view.scene.addChild(heavens);
When you append this to the end of the code, you won't see any stars. The reason is that if a 3D mesh is double sided, it'll require twice as many calculations. 3D engines save where they can to achieve the maximum speed possible. If you wish, you can turn on rendering of both sides, but you can also flip the direction of the material like this:
heavens.invertFaces();
When you append this to the end of the script, the stars will light up. Also note that since this is a dark texture with details that are hard to see, we're only using a low resolution sphere (9x9 segments).
Step 8: add the sun
While we're at it, let's add the sun as well. Import the "sunmap.jpg" image and update the Linkage option to Export for Actionscript as we did with the formers materials.
var sun = new Sphere({material:"sunmap.jpg",radius:50,x:150,y:100,z:600,segmentsH:6, segmentsW:6});
view.scene.addChild(sun);
This will make a new sphere with the sun-texture. It'll be quite small and positioned slightly above (Y-axis) and to the right (X-axis) of the gobe. It'll also be further away from the earth (Depth, Z-axis). When you test now, you'll see the sun just behind the earth upon startup and it'll move along when you rotate.
Step 9: Optimize
There is one problem however. Even though the sun is only 6 by 6 segments, the performance is beginning to suffer. To make sure it plays smoothly, we should optimize a bit here. The amount of triangles is the main issue here, so let's reduce it. While good-looking, the extra globe for the skies is the main cause of our problem. It consists of many polygons and it requires the renderer to use the proper Z-sorting.
The other way to solve this is to combine the skies and the globe texture into one (sometimes referred to as a "prebaked" texture). In reality, the skies are much closer to the surface of the earth so this will actually add more realism (or at least we can use that as an excuse). We'll start by commenting the two lines where we make the skies (two slashes in front of the code):
// skies = new Sphere({material:"earthcloudmap.png",radius:153,segmentsH:18, segmentsW:26});
// scene.addChild(skies);
Next, lets import "earthmap1k.png" to the Library. This is a new texture that I've made using Photoshop that combines the two images into one. Set it up for use with Actionscript as before and append this line of code to the existing script:
globe.material = new BitmapMaterial(Cast.bitmap("earthmap1k.png"));
We'll also set the camera back to using the simple renderer that don't enforce the Z-order of objects. Replace the line that sets up the View3D with this line:
var view:View3D = new View3D({scene:scene, camera:camera, renderer:Renderer.BASIC});
These two tricks will increase the playback speed a lot.
Step 10: Nightmode
The idea of the "prebaked" texture can be taken further. Let's do a little Photoshop work and combine the nigh image from HR into the day image. Import "earthmap1k_night_day.png", set it up for use with Actionscript and append the lines below:
var newMaterial:BitmapMaterial = new BitmapMaterial(Cast.bitmap("earthmap1k_night_day.png"));
globe.material = newMaterial;
Much better, isn't it? Did you notice how the night-time lights flicker when you rotate?
Step 11: Atmosphere
Let's add the finishing touch. By setting the "ownCanvas" property, any 3D object in Away3D can use standard Flash filters. Copy and append the code below and we're at the final stage of this tutorial:
var myFilter1:Array = new Array() myFilter1.push(new GlowFilter(0xFFFFAA, 1, 25, 25, 3, 1, false, false)); sun.ownCanvas=true; sun.filters=myFilter1; var myFilter2:Array = new Array() myFilter2.push(new GlowFilter(0xFFFFFF, 0.4, 15, 15, 2, 1, false, false)); globe.ownCanvas=true; globe.filters=myFilter2;
Closing words
This tutorial is just a start. Why not add the entire solar system? JHR has all the textures you need. How about adding a zoom feature or a camera that can move freely (did I hear spaceship?). How about a lens flare? The possibilities are almost endless.
While Away3D is easy to work with, it currently suffers from a lack of documentation. This will likely improve over time and the Away3D team lists several learning resources at their main site. The best way to learn is however to look at other people's code. For this tutorial, we learned a lot from this example published by Rob Bateman, one of the Away3D developers. This one also explains some of the other materials and shaders that Away3D offers. Click here to download the finished FLA file for this tutorial.
Before starting to build your own 3D worlds, keep in mind that the Flash Player has it's limits and that 3D Flash is still in it's infancy. Adobe has already sneaked that they will add some hooks in Flash Player 10 that will enhance this seriously, but until then we'll have to limit the scope of our projects. We also know that Adobe is talking directly to the makers of both Papervision3D and Away3D to make sure that these engines are ready soon after the launch of Flash Player 10. In the meantime, let's play, learn and have fun with what we can do at this stage.
Recent comments
1 week 22 hours ago
4 weeks 3 days ago
4 weeks 3 days ago
4 weeks 3 days ago
6 weeks 2 days ago
6 weeks 4 days ago
6 weeks 6 days ago
8 weeks 1 day ago
8 weeks 3 days ago
8 weeks 3 days ago