3D sound visualization using pv3D and computespectrum

I wrote a relatively simple example of how you can analyze the soundspectrum and then use the output to animate papervision3D objects. I’m not such a fan of ENTER_FRAME  listeners, so you’ll find the code that handles the animation in the tick function of the timer which updates every 100 ms. To get this code to work you’ll need the Tweenlite classes.

Click here to launch ( may take a while to load the mp3 file )

pv3D_sound

And here’s source code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package
{
	import com.greensock.TweenLite;
 
	import flash.display.BlendMode;
	import flash.display.Sprite;
	import flash.display.StageQuality;
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.media.Sound;
	import flash.media.SoundMixer;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;
	import flash.utils.Timer;
 
	import org.papervision3d.materials.ColorMaterial;
	import org.papervision3d.materials.utils.MaterialsList;
	import org.papervision3d.objects.DisplayObject3D;
	import org.papervision3d.objects.primitives.Cube;
	import org.papervision3d.view.BasicView;
 
	[ SWF( width='1024', height='768', backgroundColor='#000000', frameRate='25' ) ]
 
	public class PV3D_SPECTRUM extends BasicView
	{
		private var bytes : ByteArray;
		private var tmr : Timer;
		private var a : Number = 0;
		private var cubes : Array;
		private var container : DisplayObject3D;
		private var pivot : Sprite;
 
		private var easeOut:Number = 0.4; // Higher = faster ease-out
		private var reachX:Number = 0.7; //  Higher =  smaller reach
		private var reachY:Number = 0.7; //  Higher =  smaller reach
 
		public function PV3D_SPECTRUM()
		{
			stage.quality = StageQuality.MEDIUM;
 
			init();
		}
 
		private function init() : void
		{
			var spacing : uint = 600;
			var dim : uint = 3;
			var c : uint = ( dim * spacing * 0.5 );
			var snd : Sound = new Sound();
 
			// Set camera properties
			camera.x = 2000;
			camera.y = 500;
			camera.z = 500;
 
			camera.zoom = 5;
			camera.focus = 100;
			camera.sort = false;
 
			// Set pivot point
			pivot = new Sprite();
			pivot.x = 400;
			pivot.y = 250;
 
			// Make container for cubes
			container = new DisplayObject3D();
			scene.addChild( container );
 
			snd.load( new URLRequest( "3.mp3" ) );
			snd.play();
 
			bytes = new ByteArray();
			cubes = new Array();
 
			for (var i:uint = 0; i < dim; i++)
			{
				for (var j:uint = 0; j < dim; j++)
				{
					for (var k:uint = 0; k < dim; k++)
					{
						var size : uint = Math.random() * 100 + 150;
						var cube : Cube = new Cube(
								new MaterialsList( { all:new ColorMaterial( 0xFFFFFF * Math.random() ) } ),
								size,
								size,
								size,
								1,
								1,
								1 );
 
						container.addChild( cube );
 
						cube.x = i * spacing - c;
						cube.y = j * spacing - c;
						cube.z = k * spacing - c;
 
						cube.useOwnContainer = true;
						cube.alpha = 0.8;
						cube.blendMode = BlendMode.ADD;
 
						cubes.push( cube );
					}
				}
			}
 
			startRendering();
 
			tmr = new Timer( 100 );
			tmr.addEventListener( TimerEvent.TIMER, tick );
			tmr.start();
		}
 
		private function tick(e:TimerEvent):void
		{
			var temp : Array = new Array();
 
			SoundMixer.computeSpectrum( bytes, true, 0 );
 
			for ( var j:int = 0; j < 256; j+= Math.floor( 256 / cubes.length ) )
			{
				temp.push( ( bytes.readFloat() * 1.5 ) + 1 );
			}
 
			for ( var i:uint = 0; i < cubes.length; i++ )
			{
				TweenLite.to( cubes[i], 0.1, { scaleY:temp[i], scaleZ:temp[i], scaleX:temp[i] } );
				cubes[i].alpha = temp[i] - 0.9;
			}
		}
 
		override protected function onRenderTick( event:Event = null ) : void
		{
			container.yaw( 1 );
			container.pitch( 1 ); 
 
			this.camera.x += ( ( - pivot.mouseX * 5 ) - this.camera.x ) / 35;
			this.camera.y += ( ( - pivot.mouseY * 5 ) - this.camera.y ) / 35;
 
			super.onRenderTick();
		}
	}
}
  • Share/Bookmark

Lego Starfighter ARC-170 in 3D

I made a Lego Star Wars set in 3DsMax. It’s amazing how much time it takes to make a 3D model look good. When I got used to the workflow in Max (and learned some stuff about scripting and macro’s), I found myself working remarkably faster.

You can download a wallpaper pack here.

Resolutions included:

  • 1440 x 900
  • 1680 x 1050
  • 1920 x 1200

I also made a small swf file showing you a preview of the wallpaper + a cool color animation. Go check it out!

Here are some renders of the final result:

Startfighter_ARC-170_01

Startfighter_ARC-170_02

Startfighter_ARC-170_03

  • Share/Bookmark

How to make a snake game in flash with Actionscript 3

I’ve written a basic snake game to show you how this can be done in AS3. You can open up flex builder, paste the code in a new actionscript class and run it right away. (Get the class file here).

You’ll probably notice that the game doesn’t check for collisions with the snake itself or the border. Maybe I’ll do a part 2 where I complete the game a bit more.

Anyway, here’s the code for the basic functionality:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package {
 
	import flash.display.Sprite;
	import flash.events.KeyboardEvent;
	import flash.events.TimerEvent;
	import flash.ui.Keyboard;
	import flash.utils.Timer;
 
	[SWF(width='430', height='430', frameRate='30')]
 
	public class Snake extends Sprite{
 
		private const SPEED : uint = 60;//lower = faster
		private const DIM : int = 15; //keep this number uneven to have the snake starting in the middle
		private const INITIAL_SIZE : int = 3; //keep this lower then DIM/2
 
		private var left : Boolean;
		private var right : Boolean;
		private var up : Boolean;
		private var down : Boolean;
		private var size : Number;
		private var food : Sprite;
		private var tmr : Timer;
		private var curI : Number;
		private var curJ : Number;
		private var snake : Array;
		private var grid : Array;
 
		public function Snake(){
			size = stage.stageWidth / DIM;
			curI = curJ = Math.floor(DIM * 0.5);
 
			initSnake();
			fillGrid();
			placeFood();
 
			tmr = new Timer(SPEED);
			tmr.addEventListener(TimerEvent.TIMER,move);
			tmr.start();
 
			stage.addEventListener(KeyboardEvent.KEY_DOWN,changeDir);
		}
 
		private function fillGrid():void{
			grid = Make2DArray();
 
			for (var i:uint = 0; i < DIM; i++){
				for (var j:uint = 0; j < DIM; j++){
					var sp:Sprite = new Sprite();
					sp.graphics.beginFill(0xF0F0F0);
					sp.graphics.lineStyle(1,0xF5F5F5);
					sp.graphics.drawRect(0, 0, size  - 1, size - 1);
					sp.x = i * size;
					sp.y = j * size;
					addChild(sp);
					grid[i][j] = sp;
				}
			}	
		}
 
		private function Make2DArray():Array{
			var a:Array = new Array(DIM);
			for(var i:uint = 0; i < a.length; i++){
			    a[i] = new Array(DIM);
			}	
			return a;
		}
 
		private function initSnake():void{
			var center:Number = Math.floor(DIM * 0.5) * size;
 
			snake = new Array(INITIAL_SIZE);
 
			for (var i:uint = 0; i < INITIAL_SIZE; i++){
				var sp:Sprite = makeItem();
				sp.x = center;
				sp.y = center + i * size;
				addChild(sp);
				snake[i] = sp;
			}
 
			snake.reverse();
		}
 
		private function makeItem(c:uint = 0):Sprite{
			var s:Sprite = new Sprite();
			s.graphics.beginFill(c);
			s.graphics.lineStyle(2,0x333333);
			s.graphics.drawRect(0, 0, size, size);
			return s;
		}
 
		private function placeFood():void{
			var rndI:uint = Math.floor(Math.random() * DIM);
			var rndJ:uint = Math.floor(Math.random() * DIM);
 
			var rndX:Number = grid[rndI][rndJ].x;
			var rndY:Number = grid[rndI][rndJ].y;
 
			if (food != null) removeChild(food);
 
			food = makeItem(Math.random() * 0xFFFFFF);// random color
			food.x = rndX;
			food.y = rndY;
 
			addChild(food);
 
			//redo if the food is on the snake itself
			for (var i:uint = 0; i < snake.length; i++){
				if (rndY == snake[i].y && rndX == snake[i].x){ 
					placeFood();
				}
			} 
		}
 
		private function move(e:TimerEvent):void{
			if (left){
				curI -= 1;
			}else if (right){
				curI += 1;
			}
			if (up){
				curJ -= 1;
			}else if (down){
				curJ += 1;
			}
 
			if (left || right || up || down){
				var s:Sprite = makeItem();
 
				if (curI > DIM - 1) curI = 0;
				if (curJ > DIM - 1) curJ = 0;
 
				if (curI < 0) curI = DIM - 1;
				if (curJ < 0) curJ = DIM - 1;
 
				s.x = grid[curI][curJ].x;
				s.y = grid[curI][curJ].y;
 
				addChild(s);
				snake.push(s);
 
 
				if (Math.floor(s.x) == Math.floor(food.x) && Math.floor(s.y) == Math.floor(food.y) ){
					placeFood();
				} else {
					removeChild(snake[0]);
					snake.shift();
				}
			}
		}
 
		private function changeDir(e:KeyboardEvent):void{
			if(e.keyCode == Keyboard.LEFT)	{if (!right){left = true;  up = false; down = false; right = false;}}
			if(e.keyCode == Keyboard.UP)	{if (!down)	{left = false; up = true;  down = false; right = false;}}
			if(e.keyCode == Keyboard.RIGHT)	{if (!left)	{left = false; up = false; down = false; right = true;}}
			if(e.keyCode == Keyboard.DOWN)	{if (!up)	{left = false; up = false; down = true;  right = false;}}
		}
	}
}

And here is the result. (Press any arrow key to start moving)

This movie requires Flash Player 9

  • Share/Bookmark

Papervision 3D Mashup

My latest project is a game/quiz that combines youtube videos, flickr images and tweets in flash. It uses pv3D to show the content in an interactive way. The goal is to guess the (randomly selected) words that were searched on youtube, flickr and twitter. Be sure to check it out.

launch project

UPDATE:
Since 03/12, Flickr is using a new subdomain (farm5.static.flickr.com) to store it’s images. Because flash player’s security policy needs a crossdomain XML file for each subdomain, I had to change this to be able to load all of the images. Everything should be loading correctly now.

wordsgame_02
Screenshot of the project with gridlayout activated

wordsgame_03
Random layout and menu

wordsgame_01
Screenshot of an early fase of the 3D navigation

  • Share/Bookmark

Tweening vertices in pv3D

Did you know it is possible to manipulate every single vertex in a 3D object? You can access them through the geometry property. I did a quick test by tweening the vertices of a cube. Click on the cube to see the result.

1
var v:Vertex3D = cube.geometry.vertices[i];

This movie requires Flash Player 9

  • Share/Bookmark

AS3 Drawing API + TweenMax

Click on the image to open the SWF in a new window.
Then, click and drag to start drawing.
AS3drawing
  • Share/Bookmark