Papervision Planetarium (Flex Code – NOMAD constellations)

Intro

I was having so much fun writing chapter 4 (on particles) that I could not resist creating a Planetarium. There are so many things you can do with particles like make fire, smoke, a flock of birds, or even the planetarium shown below.

Click on the image below to view the demo and then we’ll discuss how it was made. And get ready for some major hacking.

Papervision Planetarium

Papervision Planetarium

These are real constellations above found on sites like NOMAD and they use standard astro-celestial coordinates.

Web Stuff

Demo:
http://www.professionalpapervision.com/demos/web/planetarium/

Download: (Choose Planetarium)
http://code.google.com/p/flex3cookbook1/downloads/list

How to Video:

How it was Made

If you’re a Papervision purist, stop reading, close this post, and go for a cup of coffee. We are going to hack the heck out of Papervision, and it’s going to get ugly! On the other hand, if you’re ready to rock let’s get started.

The good news is that the entire code is only about 200 lines (counting spaces). Coming from the 2D Flash 8 world that’s pretty amazing. There are two parts to this hack. Creating a SkyMap class and creating the main Flex application which uses the SkyMap class.

Steps for creating the SkyMap class

  1. Create a Flex Project – call it Planetarium.
  2. Put Cairngorm in your Flex libs folder. To learn more about Cairngorm check out the video tutorials tab at the top of the blog (choose installing Cairngorm). I go over MVC architecture there. The purpose of Cairngorm is to hold the stellar data. Now you could have used just an array and an XML import, but since I build Learning Management systems I just couldn’t help myself. And yes, I just swatted a fly with an elephant – I confess!
  3. Place the Papervision classes in the src folder and open up the ParticleField class found in org/papervision3d/objects/special folder. Make a duplicate of it and name it SkyMap and then change its public class name and constructor name to SkyMap. In order to get stars you’ll need to use the ParticleField ParticleMaterial class that I expanded added to in a previous post on

    Putting Stars and More into a Skybox (Source)

    Otherwise, you’ll only get circles and squares. I like stars better!

  4. Place your sky map data into an xml file using CSV. Check this out on the how to video to see an example.
  5. Now change the public class by eliminating length, width, and depth variables and add a radius variable in their place.
  6. Finally eliminate the random particle equations (for x, y, and z) and substitute in the celestial equations which use the xml data brought into the Cairngorm array using HTTP services. This code is shown below;

private function createParticles(size:Number):void
{
var c:int;
var r:int;

//Lively Modifications Add Particle Stuff
var myPartNum:Number = modelLocator.myStarData.length/4;
for( var i:Number = 0; i < myPartNum; i++ )
{
var myX:Number=skyRadius*(Math.cos(2*Math.PI*modelLocator.myStarData[4*i]/24)*Math.sin((90-modelLocator.myStarData[4*i+1])*Math.PI/180));
var myZ:Number=-skyRadius*(Math.sin(2*Math.PI*modelLocator.myStarData[4*i]/24)*Math.sin((90-modelLocator.myStarData[4*i+1])*Math.PI/180));
var myY:Number=skyRadius*Math.cos((90-modelLocator.myStarData[4*i+1])*Math.PI/180)
var mySize:Number=size*(3-modelLocator.myStarData[(4*i+3)]);
addParticle(new Particle(material as ParticleMaterial, mySize, myX, myY, myZ));
}}

Steps for creating the main Flex Application

This main application is just a hack of the panorama application created in the post on

Creating a Spherical Panorama in Papervision

Here are the steps;

  1. Grab the Spherical Panorama class and rip off the package tags and remove the public class and add void to the constructor function.
  2. Create the appropriate Cairngorm folders including a singleton file in the model folder named ViewModelLocator and place an array myStarData in the singleton.
  3. Make sure that both your main Flex application and the SkyMap class have the appropriate import and variables strings to bring in Cairngorm and the myStarData model locator array.
  4. Put a HTTP services command in Flex that brings in your star data and make sure your application tag contains a call to start up your HTTP services.
  5. Parse that data in an Array Collection and comma split it and place that data into your model Locator array.
  6. You’re done! The array is now available for your SkyMap. Run your program.

To see the code for both the SkyMap class and the main Flex Application click on the more button below. Or better yet, just download it from the link provided above.

SkyMap Class

package org.papervision3d.objects.special {
import org.lively.model.ViewModelLocator;
import org.papervision3d.core.geom.Particles;
import org.papervision3d.core.geom.renderables.Particle;
import org.papervision3d.materials.special.ParticleMaterial;
/**
* @Author Ralph Hauwert hacked by Lively
*/

public class SkyMap extends Particles
{

private var skyRadius:Number;
/* private var fieldHeight:Number;
private var fieldWidth:Number; */
private var quantity:int;
private var color:int;

//Add Lively Cairngorm
private var modelLocator:ViewModelLocator=ViewModelLocator.getInstance();

/**
* The ParticleField class creates an object with an amount of particles randomly distributed over a specied 3d area.
* @param material The Material for the to be created particles
* @param color The color of the created particles
* @param container An alternate container to render to, if needed.
* @param fieldWidth The width of the area
* @param fieldHeight The height of the area
* @param fieldDepth The depth of the area
*/
public function SkyMap(mat:ParticleMaterial, quantity:int = 200, particleSize:Number=4, skyRadius:Number = 2000)
{
super(“ParticleField”);

this.material = mat;
this.quantity = quantity;

this.skyRadius = skyRadius;
/* this.fieldHeight = fieldHeight;
this.fieldDepth = fieldDepth; */

createParticles(particleSize);
}

private function createParticles(size:Number):void
{
/* var width2 :Number = fieldWidth /2;
var height2 :Number = fieldHeight /2;
var depth2 :Number = fieldDepth /2; */
var c:int;
var r:int;

//Lively Modifications Add Particle Stuff
//Spherical equations
/*
x = r*cos(2*Math.PI*rac/24)sin(Dec*Math.PI/180);
y = r*sin(2*Math.PI*rac/24)sin(Dec*Math.PI/180);
z = r*cos(Dec*Math.PI/180);

*/

var myPartNum:Number = modelLocator.myStarData.length/4;
for( var i:Number = 0; i < myPartNum; i++ )
{

/* var myX:Number=skyRadius*(Math.cos(2*Math.PI*modelLocator.myStarData[4*i]/24)*Math.sin((90-modelLocator.myStarData[4*i+1])*Math.PI/180));
var myZ:Number=-skyRadius*(Math.sin(2*Math.PI*modelLocator.myStarData[4*i]/24)*Math.sin((90-modelLocator.myStarData[4*i+1])*Math.PI/180));
var myY:Number=skyRadius*Math.cos((90-modelLocator.myStarData[4*i+1])*Math.PI/180) */

var myX:Number=skyRadius*(Math.cos(2*Math.PI*modelLocator.myStarData[4*i]/24)*Math.sin((90-modelLocator.myStarData[4*i+1])*Math.PI/180));
var myZ:Number=-skyRadius*(Math.sin(2*Math.PI*modelLocator.myStarData[4*i]/24)*Math.sin((90-modelLocator.myStarData[4*i+1])*Math.PI/180));
var myY:Number=skyRadius*Math.cos((90-modelLocator.myStarData[4*i+1])*Math.PI/180)

var mySize:Number=size*(3-modelLocator.myStarData[(4*i+3)]);

addParticle(new Particle(material as ParticleMaterial, mySize, myX, myY, myZ));
}
}

}
}

Main Flex Application

<?xml version=”1.0″ encoding=”utf-8″?>
<mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml&#8221; layout=”absolute” creationComplete=”getMyStarData.send()” backgroundGradientAlphas=”[1.0, 1.0]” backgroundGradientColors=”[#010000, #092B76]“>
<mx:Script>
<![CDATA[

import caurina.transitions.Tweener;

import flash.display.Sprite;
import flash.events.*;
import mx.events.*;
import flash.events.KeyboardEvent;

import org.papervision3d.cameras.*;
import org.papervision3d.events.InteractiveScene3DEvent;
import org.papervision3d.materials.BitmapMaterial;

import org.papervision3d.materials.special.ParticleMaterial;
import org.papervision3d.materials.utils.MaterialsList;
import org.papervision3d.objects.primitives.*;
//Lively Mod
import org.papervision3d.objects.special.SkyMap;
import org.papervision3d.render.BasicRenderEngine;
import org.papervision3d.scenes.Scene3D;
import org.papervision3d.view.Viewport3D;

import mx.collections.ArrayCollection;
import mx.rpc.events.ResultEvent;

//import org.papervision3d.objects.prims2d.*;

//Cairngorm
import org.lively.model.ViewModelLocator;
private var modelLocator:ViewModelLocator=ViewModelLocator.getInstance();

private var viewport: Viewport3D;
private var scene: Scene3D;
private var camera: FreeCamera3D;

private var renderer: BasicRenderEngine;
private var clickMe: Boolean;

private var particlemat:ParticleMaterial;

//Lively Mod
private var stars:SkyMap;
private var cone: Cone;
private var skybox: Cube;

//Parameters for Keyboard and Cylinders

private var speed:Number=1; //Forward Back
private var rotspeed:Number=2; //Rotation
private var highspeed:Number=30; //Flying
private var radius:Number = 800; //Radius
private var numOfItems:int = 13; //Number of items
private var anglePer:Number = (Math.PI*2) / numOfItems; //Layout Rotation angle

//Declare Buttons and Boolen Values

private var leftArrow:Boolean = false;
private var rightArrow:Boolean = false;
private var upArrow:Boolean = false;
private var downArrow:Boolean = false;
private var pageUp:Boolean = false;
private var pageDown:Boolean = false;

private var myMouseDown:Boolean = false;
//Parameters
public var myWidth:Number=100000;
public var myHeight:Number=100000;
public var myDepth:Number=100000;

//Array Collections for myStarInfo
[Bindable] private var myStarInfo:ArrayCollection;

public function SnowFall():void
{

//viewport = new BasicRenderEngine(width, height, scaleToStage, interactive);
viewport = new Viewport3D(550, 400, true, true);
pv3Canvas.rawChildren.addChild(viewport);

//instantiates a Scene3D instance
scene = new Scene3D();

//instantiates a Camera3D instance
camera = new FreeCamera3D();
camera.zoom=100;
//renderer draws the scene to the stage
renderer = new BasicRenderEngine();

var myPartNum:Number=modelLocator.myStarData.length/4;

particlemat = new ParticleMaterial(0xffffff,1,ParticleMaterial.SHAPE_STAR);
stars = new SkyMap(particlemat,myPartNum,10, 5000);
scene.addChild(stars);

camera.x=camera.y=camera.z=0;

camera.zoom = 6;
camera.focus = 100;
//camera.rotationX=90;

//set up enterFrame event
addEventListener(Event.ENTER_FRAME, onEnterFrame);

addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
addEventListener(MouseEvent.ROLL_OVER, onMouseUp);

function onMouseDown() : void
{
myMouseDown = true;

};

function onMouseUp() : void
{
myMouseDown = false;

};

//define enterFrame Method, render the PV3D Scene and animate the primitive
function onEnterFrame(e:Event):void
{

renderer.renderScene(scene, camera, viewport);
if (myMouseDown)
{
if(camera.zoom<15){camera.zoom+=.1;}

}else{if(camera.zoom>6){camera.zoom-=.1;} }

camera.rotationY = camera.rotationY + (mouseX – stage.width / 2) / 500;
camera.rotationX = camera.rotationX – (mouseY – stage.height / 2) / 500;
if (camera.rotationX <= -90)
{
camera.rotationX = -90;
}
else if (camera.rotationX >= 90)
{
camera.rotationX = 90;
}// end else if

}
}

//Resulty Handler Frame Data for SWF Background
private function resultHandler(event:ResultEvent):void{

myStarInfo=event.result.myStarData.myStars;

//myDataArraymyStarInfo
trace(myStarInfo[0]);

modelLocator.myStarData= myStarInfo.getItemAt(0).split(“,”);

SnowFall();

}

]]>
</mx:Script>

<mx:HTTPService id=”getMyStarData” url=”data/myStarDataIs.xml” result=”resultHandler(event)”/>

<mx:Canvas x=”10″ y=”10″ width=”841″ height=”527″ id=”pv3Canvas”>
<mx:Label x=”12″ y=”11″ text=”Click to zoom” color=”#FEFFFF” fontSize=”12″/>
</mx:Canvas>
</mx:Application>


About these ads

2 Responses to Papervision Planetarium (Flex Code – NOMAD constellations)

  1. [...] An awesome tutorial by the great Michael Livel on how to create a Papervision Planetarium at his blog. The amazing thing is that the entire code is no more than 200 lines. Read here. [...]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: