Categories
General

Simple Flash 3D drawing API

I’m most passionate about hiding complexity with simple APIs, which is one of the reasons I’m so excited about Hype.

A few weeks ago Peter Elst told me that he was trying to find a simple way to draw 3D shapes, and so I helped him with a bit of code. He’d done some great work, and it really inspired me to continue to simplify things even more.

[kml_flashembed publishmethod=”dynamic” fversion=”9.0.0″ movie=”/wp-content/uploads/manual/2009/Draw3DTest.swf” width=”550″ height=”400″ targetclass=”flashmovie”]

Get Adobe Flash player

[/kml_flashembed]

So I spent a couple of hours putting together an experiment to see whether I could build a simple 3D drawing API for Flash that works more or less exactly like the 2D Flash drawing API.

I’m not sure whether this was the right approach but I thought it would be a fun experiment nonetheless and a great way to canvas opinion and get some feedback and ideas!

So here it is FlashDraw3D. The first thing you do is create a Graphics3D object:

var g3d : Graphics3D = new Graphics3D(this); 

As you can see you pass it through a reference to the DisplayObject that you want to draw into. Once you’ve made it you can then draw into it :

g3d.lineStyle(1, 0xff0000, 1); 
g3d.moveTo(-10, 0, -10);
g3d.lineTo(10, 10, 10); 

With of course the same syntax as the 2D drawing API except with 3 (x, y, z) coordinates instead of 2 (x, y).

And just like the flash drawing API has a drawRect, we have a drawCube :

 
g3d.drawCube(0, 0, 0, 100, 100, 100);

I’ve also added a couple of extras :

 
g3d.rotateY(); 

Just to show that it’s 3D :-). I really should have added rotateX and rotateZ but hey I only did it in a couple of hours. 🙂 I’ll add it soon I promise.

And also some handy 2D to 3D converting commands :

g3d.moveTo2D(mouseX, mouseY, 0);
g3d.lineTo2D(mouseX, mouseY, 0);

Where you can pass through 2D screen co-ordinates that are converted to a 3D position at the z depth you gave it. In the example that comes in the code base this is used to draw in 3D with the mouse.

Please note : it’s very much a rough prototype and it’s absolutely not optimised at all! It’s incomplete and poorly documented. I’m just putting it out there to see what you think.

Download the code at //code.google.com/p/flashdraw3d/source/checkout and give it a try! I’d love to hear any suggestions you have. (Polite ones anyway 😉 )

Here’s the code for the above example :

package  
{
	import flash.events.Event;
	import flash.events.MouseEvent;

	import com.sebleedelisle.draw3d.Graphics3D;

	import flash.display.Sprite;
	[SWF (width="550", height="400", frameRate="30", backgroundColor="#000000")]

	/**
	 * @author Seb Lee-Delisle
	 */
	public class Draw3DTest extends Sprite 
	{
		public var g3d : Graphics3D;
		private var isMouseDown : Boolean;

		public function Draw3DTest()
		{
			
			g3d = new Graphics3D(this);
			
			g3d.lineStyle(1, 0xff0000, 1); 
			g3d.moveTo(-10, 0, -10);
			g3d.lineTo(10, 10, 10); 
			
			g3d.drawCube(0, 0, 0, 80, 80, 80);
			
			g3d.drawCube(100, 100, 0, 80, 80, 80);
			
			
			
			stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown); 
			stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp); 
			addEventListener(Event.ENTER_FRAME, enterFrame);
		}

		public function enterFrame(e : Event) : void
		{
			if(isMouseDown)
			{
				g3d.lineTo2D(mouseX, mouseY, 0);
			}
			
			g3d.rotateY(2);
		}

		public function mouseDown(e : MouseEvent) : void
		{
			isMouseDown = true; 
			g3d.moveTo2D(mouseX, mouseY, 0);
		}

		public function mouseUp(e : MouseEvent) : void
		{
			isMouseDown = false; 
		}
	}
}

36 replies on “Simple Flash 3D drawing API”

This is really great. I like that it is not optimized and very simple. These are the kind of things that are great for learning from.

I like this idea, will check out the code. I’m just wondering why, in your example above, when you press the mouse down, it starts drawing at z – depth = 0, but then in the enterframe, its continuing to draw at z = 100. This results in a straight line from z=0 to z=100 which rotates around the axis. Shouldn’t the z values in these two calls be the same ? this is a lot like Keith Peters spin & draw thingy.

@bigfish, I’ve fixed this now, thank you! I wondered why it didn’t quite look right 🙂 Not sure if I’ve seen Keith’s thing? I hope I didn’t accidentally steal anything 🙂

how would that be working with gradient fills. I tried to implement it in the papervision graphics3d but transforming the gradient in 3D was beyond my skills. I would love to see a 3D gradient engine.

@Mark Reilly yes I saw this first a few years ago when Amit Pitaru showed it at FlashForward a few years ago and I have since met James Paterson several times. But to be clear, this isn’t anything like Rhonda, it’s just a little experiment to see if I can convert the Flash drawing API into 3D.

Great work and I concur with Philip – I would rather see more ‘rough’ coding experiments than a precious few highly refined and documented to death. As long as the author readily states that the work is very early prototype (ish?), then what’s the harm?

Thanks for sharing the code. A lot of people have been complaining about the drop in creative work in flash lately, but what you’re sharing has the spirit of inventiveness people need to help them think outside their boxes.

ahhhh I think in this case we probably stole the same thing (ie Rhonda and others of James and Amit’s work). But yes this is more about the API so thank you for bringing back to that 🙂

Hey Seb, I’m loving the simplicity of this. Some projects I find PV3D too excessive when I want to produce a simple effect, but there really aren’t that many alternatives. Do you think you’ll expand it?

Hi zik! You can clear by calling graphics3d.clear() from memory. I was going to make a beginFill work, but it’s not that straightforward. What if you make a shape that isn’t flat? It gets complicated. But I’ll think about making a simple version and see how it works.

you couldn’t rotate your 3d camera and then move you camera
like it should be
it didn’t “kill” the points you don’t see
and i didn’t like to work with class and flash

thank you for this code it helped understand how to do one

made it to a class
it do more with less line’s(well it doesnt let you change color)
you can draw and save point’s rotate the camera
and remove line’s you don’t see(still need to improve)

var g:LineEngine=new LineEngine();
g.lineTo3d(10,10,100);
g.moveTo3d(10,10,100);

g.addPoint(10,10,100);
g.addMP(10,10,100);
g.moveX(5);
g.rotY(5);
g.render();
i could even made it even bater
if i knew how can i make 2d vector like i did with Array

package{
import flash.display.Sprite;
public class LineEngine extends Sprite {
private var DEG_TO_RAD : Number = Math.PI/180;
private var model:Array=new Array();
public var len:int=model.length;
public function LineEngine() {}
public function render():void {
/*drow all the 3d points(update the view)*/
this.graphics.clear();
this.graphics.lineStyle(1,0);
var X:Number;
var Y:Number;
var Z:Number;
var dis:Number;
var RX:Number;
for(var i:int=0;i0 && dis<1000 &&RX-1000){
if(model[i][0]==”l”){
this.graphics.lineTo(RX,Y *(200/(Z)));
}else{this.graphics.moveTo(RX,Y *(200/Z)); }
}else{
if(dis<1000){
Z=1;
this.graphics.moveTo(X*(200/Z),Y *(200/Z));
}
}
}
}
public function addPoint(X:Number=0,Y:Number=0,Z:Number=1):void{
/*add 3d point*/
model.push(["l",X,Y,Z]);
len+=1;
}
public function addMP(X:Number=0,Y:Number=0,Z:Number=1):void{
/*add a 3d move point*/
model.push(["m",X,Y,Z]);
len+=1;
}
/*all the next public function move the 3d camera*/
public function moveX(speed:Number=10):void{
for(var i:int=0;i<len;i++){
model[i][1]+=speed;
}
}
public function moveY(speed:Number=10):void{
for(var i:int=0;i<len;i++){
model[i][2]+=speed;
}
}
public function moveZ(speed:Number=10):void{
for(var i:int=0;i<len;i++){
model[i][3]+=speed;
}
}
/*all the next public function rotate the 3d camera*/
public function rotY(angle:Number=7):void{
for(var i:int=0;i<len;i++){
var cosRY:Number = Math.cos(angle * DEG_TO_RAD);
var sinRY:Number = Math.sin(angle * DEG_TO_RAD);
var tempZ:Number=model[i][3];
var tempY:Number=model[i][2];
model[i][2] = (tempY*cosRY)-(tempZ*sinRY);
model[i][3]= (tempY*sinRY)+(tempZ*cosRY);
}
}
public function rotZ(angle:Number=7):void{
for(var i:int=0;i<len;i++){
var cosRY:Number = Math.cos(angle * DEG_TO_RAD);
var sinRY:Number = Math.sin(angle * DEG_TO_RAD);
var tempX:Number=model[i][1];
var tempY:Number=model[i][2];
model[i][1] = (tempX*cosRY)-(tempY*sinRY);
model[i][2] = (tempX*sinRY)+(tempY*cosRY);
}
}
public function rotX(angle:Number=7):void{
for(var i:int=0;i<len;i++){
var cosRY:Number = Math.cos(angle * DEG_TO_RAD);
var sinRY:Number = Math.sin(angle * DEG_TO_RAD);
var tempZ:Number=model[i][3];
var tempX:Number=model[i][1];
model[i][1] = (tempX*cosRY)+(tempZ*sinRY);
model[i][3]= (tempX*-sinRY)+(tempZ*cosRY);
}
}
public function lineTo3d(X:Number=0,Y:Number=0,Z:Number=1):void{
this.graphics.lineTo(X*(200/(20+Z)),Y *(200/(20+Z)));
}
public function moveTo3d(X:Number=0,Y:Number=0,Z:Number=1):void{
this.graphics.moveTo(X*(200/(20+Z)),Y *(200/(20+Z)));
}
public function addCube(xpos : Number, ypos : Number, zpos : Number, width : Number, height : Number, depth : Number) : void {
var hw : Number = width*0.5;
var hh : Number = height*0.5;
var hd : Number = depth*0.5;
addMP(xpos – hw, ypos – hh, zpos + hd);
addPoint(xpos + hw, ypos – hh, zpos + hd);
addPoint(xpos + hw, ypos – hh, zpos – hd);
addPoint(xpos – hw, ypos – hh, zpos – hd);
addMP(xpos + hw, ypos – hh, zpos + hd);
addPoint(xpos + hw, ypos + hh, zpos + hd);
addPoint(xpos + hw, ypos + hh, zpos – hd);
addPoint(xpos + hw, ypos – hh, zpos – hd);
addMP(xpos + hw, ypos + hh, zpos + hd);
addPoint(xpos – hw, ypos + hh, zpos + hd);
addPoint(xpos – hw, ypos + hh, zpos – hd);
addPoint(xpos + hw, ypos + hh, zpos – hd);
addMP(xpos – hw, ypos + hh, zpos + hd);
addPoint(xpos – hw, ypos – hh, zpos + hd);
addPoint(xpos – hw, ypos – hh, zpos – hd);
addPoint(xpos – hw, ypos + hh, zpos – hd);
}
}
}

This is really awesome. Exactly what I was searching for. I just wish it was compatible with the built in motion class. Is it possible to sort this out?

For example, try this and watch the 3D shape distort as it reaches the top of the stage.

var t=new Sprite()
addChild(t)

var g3d : Graphics3D = new Graphics3D(t);
g3d.lineStyle(2, 0xff0000, 1);
g3d.moveTo(50, 50,0);
g3d.lineTo(50, 100, 0);
g3d.lineTo(100, 100, 0);
g3d.lineTo(100, 100, -100);

stage.addEventListener(Event.ENTER_FRAME,function(){t.rotationX++})

I downloaded your code but I’m getting the following error when running it
Graphics3D.as, Line 116 1061: Call to a possibly undefined method update through a reference with static type Point3D.

Hi Si,

this code library is pretty old now, I haven’t even looked at it for years. In fact I haven’t even opened Flash for as long as I can remember! So I’m sorry but I can’t help with this problem. Perhaps I should take the code down?

Seb

Comments are closed.