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”]
[/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, yes sorry that’s a mistake. I think I was playing around with it and forgot to change it back. I’ll fix it over the weekend 🙂
@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.
@malte hmmm not sure about that one. My first aim was to get it working with fills with basic lighting on. Perhaps I’ll look into gradients later 🙂
I like it, will have to play around with the code.
I was just looking at this post on Johnny Chung Lee’s blog about drawing in 3D.
//procrastineering.blogspot.com/2009/07/rhonda-3d-drawing.html
You probably seen it but I thought it was very cool and had a great interface.
@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.
thanks Boris, Don and Phillip, glad you like it!
np, seb. Keith’s Spinny Draw is here
//www.bit-101.com/blog/?p=1614
Great minds think alike 😉 But I think your idea of a 3d drawing api is distinct from this effect, which is just one possible application of it.
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 Stu, I’d definitely be interested in expanding on it. I’m just not sure this is the best way to build it right now. So, feedback welcomed!
great!!
thank you
i want to be able to fill the cube
and to clear the drowing
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.
i am trying to make a 3d camera
but when the camera is in rotation
the camera dont move like i want
it move like it should be
only in 0 rotation
please add 3d camera
//zik99.007sites.com/flash2/3dDraw.swf
you move the angle with E,Q
Hi Zik, I’m not sure I understand what you mean? You’d like to be able to move a camera?
cheers
Seb
yes
//zik99.007sites.com/flash2/3dDraw.swf
look
you can move with the arrows
but when you press E or Q to call g3d.rotateY(angleY);
when you press up the camera move in angleY angle and not forward
like it should be.
Hi Zik, that’s cos you’re moving in world space when you need to be moving in camera space. If you see what I mean. In other words, your camera is broke 🙂
please add a 3D camera to your class
[…] I started thinking, that might look kinda cool in 3D. Then I remembered Seb Lee-Delisle had created a ridiculously simple to use 3d drawing api, so I put the two together and came up with the below (roll over to spin the tree around and click […]
[…] year Seb Lee-Delisle posted about how it would be nice to be able to draw in 3D with the same ease as you can draw in 2D, using the flash drawing API. It inspired me to try […]
made my own drawing API
i would like you to help me improve the API
//cookbooks.adobe.com/post_3d_line_based_engine-17116.html
what would you like me to do? Doesn’t the code I made do the job you need?
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);
}
}
}
[…] didn’t even know Seb had written this wicked little engine, until he heard me moaning on Twitter, and offered it as a possible solution. I had kinda come to […]
[…] platform agnostic (i.e. no reliance on Papervision3D), combined it with Seb Lee-Delisle’s simple 3D drawing api and came up with the […]
[…] for kicks, I strolled over to this joint, downloaded 6 .gml files and started fooling around with Seb Lee-Delisle’s Graphics3D and my own Bayer Mosaic PixelBender filter and came up with the little thing below. It just loops […]
just found out about it, but nice!
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