Flying Postcards and Tweening – 3D Billboard Tutorial

Flash 3D API  in the current flash player (10.1)  is very limited, and is no more than a basic perspective drawing. However, it is perfectly suitable for putting flat 2D objects in 3D space – to create what is often called ‘flying postcards’.

Before FP10, Flying postcards used to be very difficult to code, but nowadays it is a simple matter of placing object in the display list and set their transforms with the proper values. This is often used for image transitions in photo galleries, but you could also create very cool effects for games – such as animated logos and splash screens.

In this tutorial I will show how to create a billboard flip. The billboard flip is one of my favorites, since it can be done in many ways and produce many variations with relative ease. It is popular in sports TV graphics, used to display a leader board in games like tennis or golf.

Final Result

The sample project is written in pure AS3 and a tweening library. Check out the demo and full source code here:

First Steps

Start by creating a project and add a tweening library of your choice – my faourite is Greensock TweenMax, but any other tweener will do the job just the same.  In the project, create a class to hold the animated effect, based on Sprite.

The init function in the class should take a bitmap data as a parameter, as well as rows and columns that would define how the image is divided into tiles. Here are the basic steps needed to create a the billboard:

  1. Start with a source bitmap and break it down to grid sections according to the desired formation
  2. For each piece create a display object and place it in an array
  3. Add each piece as a child while setting its coordinates to match its grid placement
  4. Set the rotation along X to 90 degrees for all pieces.
  5. In turn, tween the X rotation of  each piece to reveal itself, creating an animated sequence.
public class BoardAnim extends Sprite
{
	private var _tileArray:Vector.;
	private var _vGap:Number=0;
	private var _rectWidth:Number;
	private var _rectHeight:Number;
 
	public function init(srcImage:BitmapData, cols:int, rows:int):void
	{
		_tileArray = new Vector.();
 
		_rectWidth = srcImage.width / cols;
		_rectHeight = srcImage.height / rows;
	}
}

Your source bitmap could be anything: an actual image or a Flex ui component, for that matter anything that implements the IBitmapDrawable interface will do. For this demo, I chose an image with an actual leaderboard list. To simplify, I will use a 1×10 grid, which will create horizontal strips.

Divide and Conquer

The key here is creating a tile array based on the bitmap: on initialize,  we take our source bitmap and split it into grid pieces. Each piece will be an individual display object, so we can animate it independently.

While the choice for the tile objects may be bitmaps, I opted to go with shapes – both to save memory and simplify the code , since all you need to do is draw the matching tile directly into the shape using BitmapFill. The code below demonstrates how to do that with a transformation matrix that is is used to translate the offset of each tile.

var piece:Shape;
var mat:Matrix = new Matrix();
 
for (var i:int = 0; i < cols; i++) 	{
   for (var j:int = 0; j < rows; j++) 	{
	// Create the tile piece
	piece= new Shape();
	piece.x = i * _rectWidth;
	piece.y = j * (_rectHeight + _vGap);
 
	// Set the offset on the matrix
	mat.tx = -(i * _rectWidth);
	mat.ty = -(j * _rectHeight);
 
	// Draw tile bitmap directly on shape
	piece.graphics.beginBitmapFill(srcImage, mat, false);
	piece.graphics.drawRect(0,0, _rectWidth, _rectHeight);
	piece.graphics.endFill();
 
	addChild(piece);
	_tileArray.push(piece);
   }
}

The Domino Effect

For a starting position, we want to place all our tiles standing like domino pieces. This is done by setting the rotation along the X axis to 90 degrees (or -90) – for a flat ‘postcard’ shape this makes the tiles completely invisible, and as we tween the rotation towards zero they would slowly be revealed.

One problem: the projection is set as perspective relative to the parent object so they might not show orthogonal. To get around this, set each piece with its own perspective projection with the center located on its top-left corner:

// Set projection center to piece origin

	var pproj:PerspectiveProjection = new PerspectiveProjection();
	pproj.projectionCenter = new Point(piece.x, piece.y);
	pproj.fieldOfView = 45;
	piece.transform.perspectiveProjection= pproj;

To create a nice domino effect for our tiles, we will tween them in sequence with a short delay of few milliseconds from one tile to the next. This generic function will do just that:

	// Tween tiles in sequence
	//
	private function playSequence(dur:Number, vars:Object):void
	{
		const DELTA:Number= 0.04;
		var start:Number=0;
 
		for (var i:int = 0; i < _tileArray.length; i++) {
			vars.delay= start;
			TweenLite.to(_tileArray[i], 1, vars);
			start+= DELTA;
		}
	}

Use the above function to create the intro sequence, by tweening X rotation to zero and easing out with quadratic easing:

	public function playIntro():void
	{
		playSequence(0.6, { rotationX:0, ease:Quad.easeOut});
	}

The same way, using the playSequnce function, lets us put a cool outro animation, that will fold each piece in turn. This is done by tweening the rotationY property to 90 degrees and the alpha to zero.

Thats’ it. Note that we’ve accomplished all this in one simple class with only 100 lines of code!  short and sweet.

I suggest using the demo code as a starting point and try out different images and different combinations of timings and easing types, as much as the tweener can offer. The possibilities here are really endless, and getting cool effects is only a matter of testing out different settings.

Also be sure to check the second part on Compex Fly-ins.