Webcam Particles

Inspired by Andrés fur-experiments and the perlin-particles by Joa this little Webcam idea crossed my mind.
It uses a perlin noise force to position the particles. The particles save their position, have a lifespan and color information.

The code for the particle effect is fairly simple. First there is the Particle class:


public class Particle
{
    public var next: Particle;

    public var posX: Number;
    public var posY: Number;
    public var velocityX: Number;
    public var velocityY: Number;

    public var livespan: int;
    public var age: int;
    public var color: int;
}
                    

Then the actual force and rendering class. First setup the input and output:


private function init():void
{
    var cam:Camera = Camera.getCamera();
    cam.setMode( 640, 480, 30 );
    _video = new Video( cam.width, cam.height );
    _video.attachCamera( cam );
    _input = new BitmapData( _dim.width, _dim.height, true, 0 );

    _output = new BitmapData( _dim.width, _dim.height, true, 0 );
    _outputBlur = new BitmapData( _dim.width, _dim.height, false, 0 );
    addChild( new Bitmap( _output ) );

    var scale: Number = 4;
    _noise = new BitmapData( _dim.width / scale, _dim.height / scale, false, 0 );
    _force = new BitmapData( _dim.width, _dim.height, true, 0 );
    _scaleMatrix = new Matrix();
    _scaleMatrix.scale( scale, scale );
}
                    

Then the setup the particles:


private function setupParticles(): void
{
    var p: Particle;

    var n: int = NUM_PARTICLES;

    p = _particles = new Particle();

    while( --n > -1)
    {
        p = p.next = new Particle();

        p.posX = Math.random( ) * _dim.width;
        p.posY = Math.random() * _dim.height;

        p.velocityX = Math.random();
        p.velocityY = Math.random();
        p.livespan = Math.random() * 20;
        p.age = 0;
    }
}
                    

The last part is a render-loop / enterframe handler:


private function render( e: Event ): void
{
    _input.draw( _video );

    _p0.x += SPEED;
    _p0.y -= SPEED;
    _p1.x -= SPEED;
    _p1.y += SPEED;

    _noise.perlinNoise( 10.0, 10.0, 2, 2, false, true, BitmapDataChannel.GREEN | BitmapDataChannel.BLUE, false, _octaves );
    _force.draw( _noise, _scaleMatrix );

    var particle: Particle = _particles.next;

    do
    {
        force = _force.getPixel( particle.posX, particle.posY );

        ++particle.age;

        if( particle.age > particle.livespan )
        {
            particle.posX = Math.random() * _dim.width;
            particle.posY = Math.random() * _dim.height;
            particle.color = _input.getPixel( particle.posX, particle.posY );
            particle.age = 0;
        }
        else
        {
            if( ( force >> 8 & 0xff ) > 0x80 )
                ++particle.posX;
            else
                --particle.posX;
            if( ( force & 0xff ) > 0x80 )
                ++particle.posY;
            else
                --particle.posY;

            particle.posX += particle.velocityX;
            particle.posY += particle.velocityY;

            a = 0xff * ( particle.age / particle.livespan ) >> 24;
            r = particle.color >> 16;
            g = particle.color >> 8;
            b = particle.color ;

            _outputBlur.setPixel( particle.posX, particle.posY, ( a << 24 | r << 16 | g << 8 | b ) );
        }

        particle = particle.next;

    }
    while( particle );

    _output.copyPixels( _outputBlur, _outputBlur.rect, origin );
    _outputBlur.applyFilter( _outputBlur, _outputBlur.rect, origin, filter );
}