Webcam Flow field in Flash

Ricki » 25 May 2009 » In ActionScript 3.0, Flash, Flex, Particle »

I was lurking about over at Justin Windle’s blog Soulwire, wish my blog had an alter ego with a cool name..

It was a bit to dark, the background is disturbing the image and so on..

Now I know how Neo felt..


It was a bit to dark, the background is disturbing the image and so on..

Which makes this Keanu Reeves..


He had been building some flow fields using Perlin noise, which my colleague think is Merlins evil brother for some reason.

I was writing a vector library for a particle engine Im going to publish here some day and thought that implementing theSoulwire flow field would be nice. Justin has been so kind as to put out the source, which is awesome  when your code is that good and visually stunning. As I played around with the code I got an idea, I think it is inspired by something I saw on the Processing site the idea was to use the input from my webcam as the noise map, instead of the MPerlin noise. I made a quick mockup, that actually looks quite promising. It needs some sort of effect, maybe an IR webcam, a 5×5 meter black wall to project it on, before it is ready, also the manipulation of the webcam image before it get’s read by the particles could give it a little extra. It is ticking along quite well on my Macbook Air, running the webcam and 5000 vectors.

For now I’ll just put the source code up here:

(It is build using Eclipse (Flex Builder Plugin), so it extends UIComponent, not something I would recommend, but if someone can tell me how to add Sprites to the stage of an AIR app, I will surley change it)

package
{
	import com.rickigregersen.flow_bump.Arrow;

	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.filters.BlurFilter;
	import flash.filters.ColorMatrixFilter;
	import flash.geom.ColorTransform;
	import flash.media.Camera;
	import flash.media.Video;

	import mx.core.UIComponent;

	public class Main extends UIComponent
	{
		//theese are the values I had fun playing with, but you might want something a bit more crazy:)

		private static const TRAIL : Number = 0.95;
		private static const BOOST : int = 110;
		private static const VECTORS : int = 1000;
		private static const BLUR : int = 4;
		private static const SCALE : Number = 6.0;
		private static const BACKGROUND : uint = 0x000000;
		;

		private static var fading : ColorTransform = new ColorTransform( 1, 1, 1, TRAIL );
		private static var blurFilter : BlurFilter = new BlurFilter( BLUR, BLUR, 3 )
		private static var grayMatrix : Array = [                       0.3, 0.59, 0.11, 0, 0, 0.3, 0.59, 0.11, 0, 0, 0.3, 0.59, 0.11, 0, 0, 0, 0, 0, 1, 0 ];
		private var grayFilter : ColorMatrixFilter = new ColorMatrixFilter( grayMatrix );
		private var brightMatrix : Array = [                      1, 0, 0, 0, BOOST, 0, 1, 0, 0, BOOST, 0, 0, 1, 0, BOOST, 0, 0, 0, 1, 0 ]
		private var brightFilter : ColorMatrixFilter = new ColorMatrixFilter( brightMatrix );

		private var camBMD : BitmapData;
		private var camBMP : Bitmap;
		private var renderBMD : BitmapData;
		private var renderBMP : Bitmap;
		private var vid : Video;
		private var cam : Camera;
		private var w : int, h : int;
		private var flowImage : Sprite;

		public function Main( _w : int, _h : int )
		{
			//width and height, also a sprite for holding the little particles;
			w = _w;
			h = _h;
			flowImage = new Sprite();
			//get the video;
			cam = Camera.getCamera();
			vid = new Video( w, h );
			vid.attachCamera( cam );

			//make a bitmap for drawing the video into
			camBMD = new BitmapData( w, h, false, BACKGROUND );
			camBMP = new Bitmap( camBMD );

			//a bitmap to stuff it all into and give some sort of effect
			renderBMD = new BitmapData( w, h, false, BACKGROUND );
			renderBMP = new Bitmap( renderBMD );

			//add the cam bmp and the rendered bmp
			addChild( camBMP );
			camBMP.y = h;

			addChild( renderBMP );
			//build the little vectors
			buildVectors();
		}

		private function buildVectors() : void
		{
			//place, rotate and scale them randomly
			var a : Arrow;

			for ( var i : int = 0; i < VECTORS; i++ )
			{
				a = new Arrow();
				a.x = Math.random() * w;
				a.y = Math.random() * h;
				a.rotation = Math.random() * 360;
				a.scaleX = a.scaleY = Math.random() + 0.1;
				flowImage.addChild( a );
			}
			addEventListener( Event.ENTER_FRAME, update, false, 0, true );
		}

		private function update( event : Event ) : void
		{
			//draw the cam to the stage, appy the grayscale Matrix, sometimes blur and brightfilters too
			camBMD.draw( vid );
			camBMP.filters = [                         grayFilter /*, blurFilter, brightFilter */  ];

			var a : Arrow;
			var brightness : Number;
			var radians : Number;
			var angle : Number;
			var speed : Number;
			var pixel : int;

			for ( var i : int = 0; i < VECTORS; i++ )
			{
				a = flowImage.getChildAt( i ) as Arrow;
				//get the brightness values of the pixel positioned directly under the vector
				pixel = camBMD.getPixel( a.x, a.y );
				brightness = pixel / 0xFFFFFF;
				//adjust spped and angle acording to the brightness
				speed = 0.1 + brightness * a.speed;
				angle = 360 * brightness * a.wander;
				radians = angle * Math.PI / 180;
				//make sure the vector is moving in the same direction as it's velocity
				a.x += Math.cos( radians ) * a.speed;
				a.y += Math.sin( radians ) * a.speed;
				//scale and rotate the vector according to brightness and
				a.rotation = angle;
				a.scaleX = a.scaleY = 0.1 + brightness * SCALE;
				//wrap around
				if ( a.x > w )
					a.x = 0;
				else if ( a.x < 0 )
					a.x = w;
				if ( a.y > h )
					a.y = 0;
				else if ( a.y < 0 )
					a.y = h;

			}

			//apply the colortransform, it determines the transparency of the bitmaps being stacked
			renderBMD.colorTransform( renderBMD.rect, fading );
			//draw the Sprite that hold all the vectors.
			renderBMD.draw( flowImage );

		}
	}
}

Here is the Arrow Class:

package com.rickigregersen.flow_bump
{
	import flash.display.Shape;

	public class Arrow extends Shape
	{
		public var speed : Number = Math.random() * 3;
		public var wander : Number = Math.random() * 0.5;

		public function Arrow()
		{
			draw();
		}

		private function draw() : void
		{
			/* 			graphics.clear();
			   graphics.lineStyle( 0, 0xFF0000, 0.4 );
			   graphics.moveTo( 0, 0 );
			   graphics.lineTo( 3, 0 );
			   graphics.moveTo( 2, -1 );
			   graphics.lineTo( 3, 0 );
			 graphics.lineTo( 2, 1 ); */

			/* 			graphics.beginFill( 0xFF0000, 0.9 );
			   graphics.drawEllipse( 0, 0, 6, 2 );
			 graphics.endFill(); */

			/*
			   graphics.beginFill( 0x00FF00, 0.9 );
			   graphics.drawCircle( 0, 0, 5 );
			   graphics.endFill();
			 */
			graphics.clear();
			graphics.beginFill( 0xff6600, 1.0 );
			graphics.moveTo( -1, -0.5 );
			graphics.lineTo( 1, 0 );
			graphics.lineTo( -1, 0.5 );
			graphics.lineTo( -1, -0.5 );
			graphics.endFill();
		}
	}
}

Trackback URL

One Comment on "Webcam Flow field in Flash"

Trackbacks

  1. [...] regards to my previous Perlin Flowfield post, it was a bit strange because I could simply not remember the ...

Hi Stranger, leave a comment:

ALLOWED XHTML TAGS:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Subscribe to Comments