Spinny 3D Trees

I know, I know. Recursive trees are a thing that have been done to death by – well – pretty much everyone.

I just picked up a nice book on Processing the other day though and one of the first examples it gives is a nice recursive tree. In order to better understand the java/processing involved, I thought I’d take the time to convert it to a language I know. Actionscript, that is (in case you were wondering).

After I got it ported and figured out what it was doing and why, 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 to generate a new one).

Get Adobe Flash player

If you’d like to have a play with it yourself, the code’s below (and of course you’ll need Seb’s stuff from the link above).

Main

package {
 
	import com.sebleedelisle.draw3d.Graphics3D;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	import geom.Point3D;
 
	/**
	 * 3D recursive tree based on processing example from
	 * "Processing: Creative Coding and Computational Art"
	 * http://www.amazon.com/Processing-Creative-Coding-Computational-Foundation/dp/159059617X/
	 * 
	 * Using Seb Lee-Delisle Graphics3D lib
	 * http://sebleedelisle.com/2009/11/simple-flash-3d-drawing-api/
	 * 
	 * 
	 * @author Devon O.
	 */
	[SWF(width='400', height='600', backgroundColor='#C0C0C0', frameRate='31')]
	public class Main extends Sprite {
 
		public static const DARK_BROWN:uint = 0x5C3317;
 
		private var counter:int = 0;
		private var counter2:int = 0;
		private var xg:Number = 5;
		private var yg:Number = 40;
		private var zg:Number = 5;
		private var trunkSegments:int = int(Math.random() * 4 + 3);
		private var pts:Vector.<Point3D> = new Vector.<Point3D>();
		private var branchLimit:int = 325;
		private var trunkLength:int = int(Math.random() * 50 + 130);
		private var lean2:Vector.<Number> = new Vector.<Number>(trunkSegments + 1, true);
		private var radius:Number = 8;
 
		private var _g3d:Graphics3D;
 
		public function Main():void {
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
 
		private function init(e:Event = null):void {
			removeEventListener(Event.ADDED_TO_STAGE, init);
 
			// just some quick text
			var tf:TextField = new TextField();
			tf.selectable = false;
			tf.mouseEnabled = false;
			tf.defaultTextFormat = new TextFormat("_sans", 11);
			tf.autoSize = TextFieldAutoSize.LEFT;
			tf.text = "Click to generate a new tree.";
			tf.x = int(stage.stageWidth * .5 + 20);
			tf.y = int(stage.stageHeight - tf.height);
			addChild(tf);
 
			_g3d = new Graphics3D(this);
 
			trunk();
 
			addEventListener(Event.ENTER_FRAME, rotate);
			stage.addEventListener(MouseEvent.CLICK, drawTree);
		}
 
		// set all vars back to original
		private function reset():void {
			counter = 0;
			counter2 = 0;
			xg = 5;
			yg = 40;
			zg = 5;
			trunkSegments = int(Math.random() * 4 + 3);
			pts = new Vector.<Point3D>();
			trunkLength = int(Math.random() * 50 + 130);
			lean2 = new Vector.<Number>(trunkSegments + 1);
			radius = 5;
		}
 
		private function drawTree(event:MouseEvent):void {
			_g3d.clear();
			reset();
			trunk();
		}
 
		private function rotate(event:Event):void {
			var ratio:Number = ((stage.mouseX / stage.stageWidth) - .5) * 2;
			_g3d.rotateY(ratio * 4);
		}
 
		// draws the tree
		private function trunk():void {
			for (var i:int = 0; i < trunkSegments; i++) {
				var lean:Number = randRange(22);
				_g3d.lineStyle(radius + 3, DARK_BROWN);
				_g3d.moveTo2D(stage.stageWidth / 2 + lean2[i], stage.stageHeight - (trunkLength / trunkSegments) * i, 0);
				_g3d.lineTo2D(stage.stageWidth / 2 + lean, stage.stageHeight - (trunkLength / trunkSegments) * (i + 1), 0);
				lean2[i + 1] = lean;
			}
			// set inital branch point from top of trunk
			pts[0] = new Point3D(stage.stageWidth * .5 + lean2[trunkSegments], stage.stageHeight - trunkLength, 0);
 
			//create branches
			branch(pts);
		}
 
		private function branch(pts:Vector.<Point3D>):void {
			var stemCount:int = 2;
 
			//  branchLimit controls complexity of tree
			if (counter2 < branchLimit){
				//set branch thickness
				_g3d.lineStyle(radius, DARK_BROWN);
				// some conditionals change branches as
				// they get further away from the trunk
				if(counter2 < 200) {
					yg -= Math.random() * .354;
					xg -= Math.random() * .625;
					if (radius > 2) radius *= .85;
				} else if (counter2 >= 200) {
 
					// moving into leaf territory now
 
					// at top of tree branches get thinner and more numerous
					stemCount = 2 + int(Math.random() * 5);
 
					// leaf color
					var leafColor:uint = getColor(Math.random() * 60, 50 + Math.random() * 90, Math.random() * 20);
					_g3d.lineStyle(0, leafColor, 230 / 255);
 
					yg -= Math.random() * .75;
					xg *= Math.random() * .20;
					zg *= Math.random() * .20;
				}
				for (var j:int = 0; j < stemCount; j++) {
 
					// randomize branch positions
					var xx:Number = randRange(30);
					var yy:Number = randRange(40);
					var zz:Number = randRange(50);
 
					_g3d.moveTo2D(pts[counter2].x, pts[counter2].y, pts[counter2].z);
					_g3d.lineTo2D(pts[counter2].x + xg + xx, pts[counter2].y - yg + yy, pts[counter2].z + zg + zz);
 
					// fill up pts array to be passed back recursively to branch function
					pts[counter + 1] = new Point3D(pts[counter2].x + xg + xx, pts[counter2].y - yg + yy, pts[counter2].z + zg +zz);
 
					// alternate branches left and right and back and forth
					xg *= -1;
					zg *= -1;
 
					// keep track of nodes
					counter++;
				}
 
				// keeps track of branches
				counter2++;
 
				//recursive call
				branch(pts);
			}
		}
 
		private function getColor(r:Number, g:Number, b:Number):uint {
			return r << 16 | g << 8 | b;
		}
 
		private function randRange(val:int):Number {
			return Math.random() * val + Math.random() * -val;
		}
	}
}

and a simple Point3D class to just store a bit of data

package geom {
	/**
	 * Basic 3D point
	 * @author Devon O.
	 */
	public class Point3D {
 
		private var _x:Number;
		private var _y:Number;
		private var _z:Number;
 
		public function Point3D(x:Number = 0, y:Number = 0, z:Number = 0) {
			_x = x;
			_y = y;
			_z = z;
		}
 
		public function get x():Number { return _x; }
 
		public function set x(value:Number):void {
			_x = value;
		}
 
		public function get y():Number { return _y; }
 
		public function set y(value:Number):void {
			_y = value;
		}
 
		public function get z():Number { return _z; }
 
		public function set z(value:Number):void {
			_z = value;
		}
	}
}

A Saturday morning well spent…

In other news, just discovered this blog’s been shortlisted as Best Irish Tech Blog. Some very nice news!

Leave a Reply

Devon O. Wolfgang

Technical Reviewer of “The Essential Guide to Flash CS4 AIR Development”

Contributing Author of “Flash AS3 for Interactive Agencies”

Senior Flash Engineer PopCap Games, International Ltd.

Portfolio

Santabot: A Unity3D Flash Game


All right, so a Christmas game like “Santabot vs. The Flying Saucers from Mars” may be a day late[...]

Magnify – a jQuery Plugin


Let me begin by saying right up front, I have not given up on Flash[...]

It’s a Starling Halloween


Getting some practice for the upcoming Zombie Apocalypse[...]

Getting Started with Proscenium

So I had a chance this weekend to sit down and play around with Adobe’s new 3D framework for Stage3D, Proscenium, and thought I’d share a few of the results (a word of caution, there are no preloaders for any of the examples and may load a bit slowly). The first shows some reflections and [...]

Particle Editor for Starling Framework

An in-browser particle editor for the Starling 2D Framework for Flash Player 11.

So Long and Thanks for all the Flash on the Beach

So, another Flash on the Beach has just has just drawn to a close[...]

Game Development Tips from the Trenches of PopCap

Well, this is a post that’s a bit overdue, but, thanks to a well timed bank holiday, I finally had the opportunity to sit down and type up what I’ve been meaning to for some time now…

Old Skool Demoscene FX as 3D Textures

Many moons ago, I got the idea to create some demoscene plane deformation effects in Flash based on the formulas found here: http://www.iquilezles.org/www/articles/deform/deform.htm. I posted my less than desired results up on wonderfl. Thankfully, fellow wonderfl user, Hasufel, forked my attempt and optimized the hell out of it coming up with this. Well, today, for no [...]

Making The Gaming Scene (A Change in Careers)

And for my second blog post of the day, a much more personal note. After about three years of working with, what I would consider as objectively as possible, the best digital agency in Ireland, vStream Digital Media, I have made the immense career decision to leave the agency world and enter the arena of [...]

Feeling Lucky?

Images to dice, kick ascii style [...]

Adventures in Playbook Land

Adventures in Playbook Land


Now that the ordeal is over, I thought I’d take the time to sit down and share my account of what it was like to develop a Blackberry Playbook application using the Adobe Flex SDK[...]

Flash

Draw it for Me

So many ideas – so little time….

Kinect Application Running in Dublin

So, on Friday I just wrapped up our latest project at vStream Digital Media, a Kinect powered flipbook that lets users flip through the hand written notebooks of Philip Lynott of Thin Lizzy. The app uses OpenNI, runs in Adobe AIR and is currently on display at a pretty bitchin’ Phil Lynott exhibition running in [...]

Beach Ball Kinect Party

So we finally got a Kinect camera hooked up to a pc at work and, while it doesn’t seem to be legal to use it for commercial projects (but, hey, I’m no lawyer), the boss asked me to get it figured out and come up with some ideas just in case it would be feasible [...]

Facebook and Flash – A Book Review

Now, I should begin by saying I absolutely hate building Facebook applications. And I build a lot of them at work. Every time I get the word from above that we’re doing another FB app, I just groan – both inwardly and out. It’s become a running joke of the office. Why do I dislike [...]

Multitouch Fluid Dynamics with AIR for Android and RTMFP

The other day I was having some fun playing around with Eugene Zatepyakin’s (aka @inspirit) FluidSolverHD (Actionscript port of C++ fluid dynamics library, MSAFluid. Or is MSAFluid, the processing/java port of the C++ library? In any case it’s a very cool fluid dynamics thingamabob – the HD version using Alchemy). After a bit of tinkering, [...]