Deconstructing Flash 10 3D

Nov 10 2008 Published by under ActionScript, Flash

Send to Kindle

In the comments of this post, Emanuele Cipolloni put forth the idea that Flash 10 3D is simply done behind the scenes using drawTriangles. That was a interesting realization for me. Made sense, so I decided to test it out. Basically, how would I create a 3D engine like Flash 10 3D using drawTriangles?

1. I’d get the bounds of an object as a rectangle.

2. Create a bitmap of that width and height and draw the object into it.

3. Transform the four corner points of the bounds using standard 3D formulas.

4. Use these transformed points as vertices for triangle drawing, and the bitmap as a bitmap fill.

Here’s what I came up with. The image on the left (the only image you can see at first) is simply an imported bitmap in a movie clip sitting on stage. Click on it, and I do steps 1-4 repeatedly, drawing the triangles in the right part of the stage. The rotationY is increased on each frame.

Essentially, the same thing. The built in version is a lot smoother and cleaner looking, but I’m only using two triangles. And I think they are throwing some smoothing into the mix somewhere. (Perhaps even a slight blur???)

Here’s the code. Beware, it’s crappy, crappy, crappy code. Done on the train and bus on the way to work. Begs to be cleaned up, but I’ve proved my point and probably won’t do much more with it unless I can think of some practical use for it.

[as]var r:Rectangle = box.getBounds(box);

var bmpd:BitmapData = new BitmapData(r.width, r.height, true, 0);
//var bmp:Bitmap = addChild(new Bitmap(bmpd)) as Bitmap;

bmpd.draw(box, new Matrix(1, 0, 0, 1, -r.x, -r.y));
var rotY:Number = 0;
var scales:Array;
root.transform.perspectiveProjection.projectionCenter = new Point(200, 140);

var running:Boolean = false;
stage.addEventListener(MouseEvent.CLICK, onClick);
function onClick(event:MouseEvent):void
{
running = !running;
if(running)
{
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
else
{
removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
}
function enterFrameHandler(event:Event):void
{
tick();
}

function tick():void
{
var ry:Number = -rotY * Math.PI / 180;
scales = new Array();
var p0:Point = rotateY(r.top, r.left, ry);
var p1:Point = rotateY(r.top, r.right, ry);
var p2:Point = rotateY(r.bottom, r.right, ry);
var p3:Point = rotateY(r.bottom, r.left, ry);

var vertices:Vector. = new Vector.();
vertices.push(p0.x + 600, p0.y + 140);
vertices.push(p1.x + 600, p1.y + 140);
vertices.push(p2.x + 600, p2.y + 140);
vertices.push(p3.x + 600, p3.y + 140);

var indices:Vector. = new Vector.();
indices.push(0, 1, 3);
indices.push(1, 2, 3);

var uvtData:Vector. = new Vector.();
uvtData.push(0, 0, scales[0]);
uvtData.push(0, 1, scales[1]);
uvtData.push(1, 1, scales[2]);
uvtData.push(1, 0, scales[3]);

graphics.clear();
graphics.beginBitmapFill(bmpd);
graphics.drawTriangles(vertices, indices, uvtData);

rotY += 3;
box.rotationY = rotY;
}

function rotateY(xpos:Number, ypos:Number, a:Number):Point
{
var x1:Number = xpos * Math.cos(a);
var z1:Number = xpos * Math.sin(a);
var foc:Number = root.transform.perspectiveProjection.focalLength;
var scale:Number = foc / (foc + z1);
scales.push(scale);
return new Point(x1 * scale, ypos * scale);
}[/as]

Send to Kindle

13 responses so far

Leave a Reply