During game development I faced the necessity of creating particle fields. In Star Fields game I used Papervision but I had to rewrite some Papervision classes to enhance the funcionality and add some visual effects. Now I try to use Away3D which will be the first Flash engine using FP 11 native GPU possibilities. Away 3 Lite is using native 3D Flash classes and thats why I have choose it for this purpose.

A set of interesting particles design can be found at this link
http://www.simppa.fi/blog/gallery/
And some here
http://blog.rackdoll.nl/?p=646
and a very good explanation of perspective projection in AS3.0 in depth
http://bgstaal.net/blog/?p=57
and some info for advanced developers
http://unitzeroone.com/blog/2009/03/18/flash-10-massive-amounts-of-3d-particles-with-alchemy-source-included/
and some stuff for very advanced devs
http://labs.adobe.com/technologies/pixelbender3d/


I want to use sprites 3D for particles because it gives better performance. Away 3 Lite has a class Sprite3D. Unfortunately this Away class doesnt have such necesary properties like screenZ, and if you need some complex visual effects, or even a simple effect of fog you cant create it. For comparision the Away 3 Lite class Mesh and Object3D has this property. Also we could need Matrix3D properties which also are available in Object3D but not available in Sprite3D. So at this point I made a conclusion that Sprite3D class is not usefull for particles systems, but Object3D is ok but not for sprites3D which gives better performance and which can show images which are not rotated.


I tried to find a way to use sprites in 3D and found a very good tutorial which explains simple 3D transformations using FP10 native class
http://blog.rackdoll.nl/?p=1033
and here is the official documentation
Matrix3D documentation
Using native clases and methods we dont need Away 3D, but maybe we could use Away3D by extending Object3D to use it with sprites? Yes, we can use Object3D's properties like object3D.viewMatrix3D.position.x but that will be much slower. I made some tests and using 800 objects3D which are not rendered (visible=false) and extracting the values from viewMatrix3D gives less than 8 frames/second on my quadQore. Using native methods of FP10 gives me almost 50 frames. So the difference is almost 10 times. Thats why I decided to use native methods.


At this point my conclusion is that using Away3D 3 Lite for particles is very slow. Soon will be released next version of Away3d - Away3D 4. You can read about it here http://away3d.com/away3d-4-0-alpha-release-broomstick
I think its GPU methods will increase the performance but for now lets proceed with what we have.


If we use only adding and manipulating DisplayObject instances we can get this swf:





Using this code:

 
package {
 
import flash.display.Bitmap
import flash.display.BitmapData
import flash.display.DisplayObject
import flash.display.Sprite
import flash.events.Event
 
public class ParticlesField extends Sprite {
 
public var stars:Sprite = new Sprite()
public var pointsVector:Vector.<Vector3D> = new Vector.<Vector3D>()
protected var iter:int
 
	public function ParticlesField() {
		addParticles()
 
		addChild( stars )
 
		addEventListener(Event.ENTER_FRAME, frameListener)
	};
 
	public function addParticles():void{
		for(iter=0; iter<800; iter++) {
 
			pointsVector.push(new Vector3D(Math.random()*800 - 400,
							Math.random()*500 - 250, Math.random()*900 - 450) )
 
			var tempStarData:BitmapData = new BitmapData(5, 5, true, 0xaaFFFFFF)
			var tempStar:Bitmap = new Bitmap(tempStarData)//Star_1()//Bitmap(tempStarData)
			tempStar.x = pointsVector[iter].x
			tempStar.y = pointsVector[iter].y
			tempStar.z = pointsVector[iter].z
			tempStar.rotationY+= Math.round( Math.random()*800 )
			stars.addChild( tempStar )
		}
		stars.x = 300
		stars.z = 500
		stars.y = 150
	};
 
	protected function frameListener(evt:Event):void{
		stars.rotationY++
	};
 

This example gives me around 35 frames per second on quadCore. The swf from above has FPS meter so you can see results on your machine. I dont expose the code for FPS meter but you can find this one at http://mrdoob.com/blog/post/582


So we got a particles field but in my case I need sprites 3D, not rotating planes.
Lets say I got this .png star with alpha channel. Star
I think its not necessary to describe how to use embed bitmaps.
In Flex I use something like this

 
[Embed(source="/ASSETS/Star_1.png")]
public static const Star_1:Class
----------------------------------
var tempStar:Bitmap = new Star_1()
 

And, we need to control the appearance of the stars in dependence of their position. We have 2 ways of getting the coordinates of the particles on screen:
a.
Using DisplayObject.transform.matrix3D.transformVector() method.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/geom/Matrix3D.html#transformVector()
If we have some points as instances of Vector3D their coordinates remains the same no matter of rotating or scaling the parent container. But we need to rotate the container and extract new coordinates of the points.
For that we can use this code:

 
	protected function frameListener(evt:Event):void{
		stars.rotationY++
 
		var iNum:uint = 0
		var tLength:uint = pointsVector.length
 
		for( var i:uint=0; i<tLength; i++){
			if(spritesVector.length<=i){
				spritesVector[i] = new Star_1()
				addChild( spritesVector[i] )
			}
			var tVector3D:Vector3D = new Vector3D(pointsVector[i].x, pointsVector[i].y, pointsVector[i].z )
 
			tVector3D = stars.transform.matrix3D.transformVector(tVector3D)	
 
			spritesVector[i].x = tVector3D.x
			spritesVector[i].y = tVector3D.y
		}
	};
 

This method gives me around 32 FPS.


b.
Using local3DToGlobal() method of DisplayObject class
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObject.html#local3DToGlobal()
This method gives us the x and y coordinates of the display object projected to the screen.

 
			var tempLocation:Point = stars.local3DToGlobal( pointsVector[i] )	
 
			spritesVector[i].x = tempLocation.x
			spritesVector[i].y = tempLocation.y
 

This method gives me around 35 FPS. The difference is not big, only 2 frames per second.
But there is one issue, using local3DToGlobal() we cant get the z coordinate of the particle. Thats why we need to use transformVector() method if we want to use z space.


So here is the swf example:


With this code for frameListener() function:

 
	protected function frameListener(evt:Event):void{
		stars.rotationY++
		var tVector3D:Vector3D = new Vector3D()
		var tLength:uint = pointsVector.length
		for( var i:uint=0; i<tLength; i++){
			if(spritesVector.length<=i){
				spritesVector[i] = new Star_1()
				addChild( spritesVector[i] )
			}
			tVector3D = pointsVector[i]
			tVector3D = stars.transform.matrix3D.transformVector(tVector3D)
 
			spritesVector[i].x = tVector3D.x
			spritesVector[i].y = tVector3D.y
			spritesVector[i].scaleX = spritesVector[i].scaleY = tVector3D.z / 800
		}
	};
 



Also you can use this code which could increse the productivity in some cases:

 
			var  tempZ:Number = tVector3D.z / 800
			if( tempZ > 0.2 ){
				spritesVector[i].visible = true
				spritesVector[i].scaleX = spritesVector[i].scaleY = tVector3D.z / 800
			}else{
				spritesVector[i].visible = false
			}
 



In all examples I used 800 particles and you can see the framerate at embed swf examples statistics in left upper corner.