
September 27, 2008
Ok, lot of time passed since I posted my PixelMorphing class experiment.
Seemed to me that post passed quite unobserved but then I received a lot of feedback and e-mail asking to share the source code.
Well, the first time I wanted to speed up posting and do further experimentation/optimization so I din’t prepare the source but since the main believe of this blog is that if someone ask for code I release it, here we are. Optimization still not done… I am a lazy one, so if someone want to help improve it is really welcome.
Now the steps to play with it:
- Download the PixelMorphing class
- Use it with this code:
import com.oaxoa.fx.PixelMorphing;
var pm:PixelMorphing=new PixelMorphing(pic1, pic2, 200);
addChild(pm);
pm.start();
//pm.reset();
or certainly you can place some buttons or some combo and wait for some event for it to start or reset. The main code of the previous post is this:
import com.oaxoa.fx.PixelMorphing;
import fl.controls.Button;
import fl.controls.ComboBox;
var pm:PixelMorphing=new PixelMorphing(pic1, pic2, 200);
addChild(pm);
var button1:Button=new Button();
button1.label="Start";
button1.y=203;
button1.x=3;
addChild(button1);
button1.addEventListener(MouseEvent.CLICK, onstart);
var button2:Button=new Button();
button2.label="Reset";
button2.y=203;
button2.x=3;
addChild(button2);
button2.addEventListener(MouseEvent.CLICK, onreset);
button1.width=button2.width=60;
button1.height=button2.height=25;
button2.visible=false;
function onstart(event:MouseEvent):void {
pm.start();
button1.visible=false;
button2.visible=true;
}
function onreset(event:MouseEvent):void {
pm.reset();
button2.visible=false;
button1.visible=true;
}
var ls:ComboBox=new ComboBox();
ls.addItem({label: "Sample 1", value: 1});
ls.addItem({label: "Sample 2", value: 2});
ls.addItem({label: "Sample 3", value: 3});
ls.addItem({label: "Sample 4", value: 4});
ls.addEventListener(Event.CHANGE, onpreset);
ls.x=66;
ls.y=203;
ls.height=25;
addChild(ls);
function onpreset(event:Event):void {
button2.visible=false;
button1.visible=true;
pic1.gotoAndStop(ls.selectedItem.value);
pic2.gotoAndStop(ls.selectedItem.value);
pm.reset();
}
You can find more parameters in the constructor method of the class, but only the first two are needed.
No setters & getters for the main variables but they are public so change them then invoke reset/start method if you wanna play with their values.
Parameters names are quite self-explainatory about what they do but remember one thing:
3rd and 4th parameters are offsetX and offsetY which influence if the starting and the resulting images will bel overlapped in the same position or offsetted. However I needed jsut one bitmapData to be able to move pixels across the two images. So if you have the 2 pictures that are 200×200px (as in the linked previous post) and offset them of 200 on the x, the resulting bitmapdata for the pixelMorphing will be 400×200px. If you offset of 1000px on x axis and 1000px on y axis the resulting bitmapdata will be 1200×1200px. So pay attention with CPU load and memory consumption.
Leave some comment if something not clear or just want to say hello

August 8, 2008
Hi there,
I was just wandering around on some flash blogs when I found this post on bit-101 that reminded me of an old fetish of mine: isometric representations!
So I just wrote this demo… The best result is achived when staring at it for a couple of minutes cause it changes conformation very quickly and displays a lot of different patterns.
No source code here, just a quick post after a while, but I wil be on the subject again (with source code).

View sample #1 - View sample #2
Leave a comment if you like it. Cheers

April 2, 2008
Hi there, some time since I last posted a technical post so here we are.
Brief
I was experimenting with some simple 3d formulas and this is the result…
1200 particles morphing in 3D space.
Added an interactive camera to start having fun.
Usage
Simply move your mouse up/down to move camera forward/backward and left/right for strafing.
Perss SPACE bar to cycle particle conformation between four different shapes.
For better experience move forward and backward while particles are morphing…
Following the morph from behind while moving very fast feel very gratifing for me
Performances
On my old CPU it performs @31fps and neither takes the cpu at 100%
No z-sorting here, just fun. I am not trying to build a real 3d engine… and no class for now, just some procedural code, but I am sure my cool readers will not have problems wrapping it inside a class definition if needed
Caurina Tweener needed.

Experience the demo
And here come the code! Simply past it in the first frame actions of a new fla.
import caurina.transitions.Tweener;
import com.oaxoa.components.FrameRater;
import flash.events.KeyboardEvent;
var particles:Array=[];
var particlesXY:Array=[];
var flen:Number=100;
var lines:Sprite=new Sprite();
var renderLines:Boolean=false;
var shapeN:int=-1;
var camera:Object={px:0, py:0, pz:0};
function drawBg():void {
var bg:Sprite=new Sprite();
bg.graphics.beginFill(0x333333);
bg.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
bg.graphics.endFill();
addChild(bg);
var tf:TextFormat=new TextFormat();
tf.color= 0x999999;
tf.font="_sans";
tf.size=11;
tf.align="right";
var t:TextField=new TextField();
t.width=300;
t.defaultTextFormat=tf;
t.text="Press SPACEBAR to change particles shape";
t.x=stage.stageWidth-t.width-10;
t.selectable=false;
bg.addChild(t);
}
function addParticle(x:Number, y:Number, z:Number):void {
var p:MovieClip=new MovieClip();
p.graphics.beginFill(0xcccccc);
p.graphics.drawCircle(0, 0, 5);
p.graphics.endFill();
p.px=x;
p.py=y;
p.pz=z;
particles.push(p);
}
function cycleShape():void {
if (shapeN<3) {
shapeN++;
} else {
shapeN=0;
}
var i:uint;
var p:MovieClip;
var px:Number;
var py:Number;
var pz:Number;
var arad:Number;
if (shapeN==0) {
var a:Number=0;
for (i=0; i<particles.length; i++) {
a+=9;
a%=360;
p=particles[i];
arad=a/180*Math.PI;
px=Math.cos(arad)*100;
py=Math.sin(arad)*100;
pz=Math.floor(i/40)*60;
Tweener.addTween(p, {time:2, transition:"EaseInOutCubic", px:px, py:py, pz:pz, delay:i/300});
}
} else if (shapeN==1) {
for (i=0; i<particles.length; i++) {
p=particles[i];
arad=i/180*Math.PI;
arad*=2;
px=Math.sin(arad)*100;
py=Math.cos(arad)*100;
pz=i;
Tweener.addTween(p, {time:2, transition:"EaseInOutElastic", px:px, py:py, pz:pz, delay:i/300});
}
} else if (shapeN==2) {
for (i=0; i<particles.length; i++) {
p=particles[i];
px=Math.random()*700-350;
py=Math.random()*700-350;
pz=Math.random()*1700;
Tweener.addTween(p, {time:2, transition:"EaseInOutCubic", px:px, py:py, pz:pz, delay:i/200});
}
} else if (shapeN==3) {
var row:uint=0;
var col:uint=0;
for (i=0; i<particles.length; i++) {
col=(i%50);
row=Math.floor(i/50);
p=particles[i];
px=0
py=-450+row*40;
pz=col*40;
Tweener.addTween(p, {time:2, transition:"EaseInOutBounce", px:px, py:py, pz:pz, delay:i/200});
}
}
}
function render():void {
var c:uint=0;
for each (var p:MovieClip in particles) {
var dx:Number=p.px-camera.px;
var dy:Number=p.py-camera.py;
var dz:Number=p.pz-camera.pz;
var scale:Number=flen/(flen+(dz));
if (scale<0) {
scale=0;
}
p.x=stage.stageWidth/2+dx*scale;
p.y=stage.stageHeight/2+dy*scale;
p.scaleX=p.scaleY=scale;
particlesXY[c]={x:p.x, y:p.y, scale:scale};
c++;
}
// activate lines render, false by default, not really a wireframe
if (renderLines) {
lines.graphics.clear();
lines.graphics.lineStyle(2, 0xCCCCCC);
for(var i:uint=0; i<particlesXY.length; i++) {;
var t:Object=particlesXY[i];
if (i<particlesXY.length-1 && t.scale>0) {
var t2:Object=particlesXY[i+1];
lines.graphics.moveTo(t.x, t.y);
lines.graphics.lineTo(t2.x, t2.y);
}
}
}
}
stage.addEventListener(KeyboardEvent.KEY_UP, onkey);
function onkey(event:KeyboardEvent):void {
if(event.keyCode==32) {
cycleShape();
render();
}
}
addEventListener(Event.ENTER_FRAME, onframe);
function onframe(event:Event):void {
var offx:Number=stage.stageWidth/2-mouseX;
camera.px-=offx/5;
if (camera.px>150) {
camera.px=150;
}
if (camera.px<-150) {
camera.px=-150;
}
var offy:Number=stage.stageHeight/2-mouseY;
if(offy>70) offy=70;
if(offy<-70) offy=-70;
camera.pz+=offy/5;
if (camera.pz>1700) {
camera.pz=1700;
}
if (camera.pz<0) {
camera.pz=0;
}
render();
}
function addSprites():void {
for each (var p:MovieClip in particles) {
addChildAt(p, 1);
}
}
function init():void {
for(var i:uint=0; i<1200; i++) {
var px:Number=0;
var py:Number=0;
var pz:Number=0;
addParticle(px, py ,pz);
}
}
// main methods call
drawBg();
addChild(lines);
init();
addSprites();
cycleShape();
render();
var fr:FrameRater=new FrameRater(0xffffff);
addChild(fr);
Have fun and leave a comment if you like.

February 15, 2008
Hi there,
I am back after some pause with this interesting effect. This class takes every pixel from two pictures, sort them by averaged luminosity e reconstruct the second picture animating pixels from the first one.
The effect is a very nice pixel morphing (particles morphing) and the final result resambles some color ramp recolor tecnique.

Start demo
This is the second algorythm I wrote. The first one was build to do the calculation about moving pixels and then draw the full picture parsing the full array of pixels. The bigger problem in the first one was speed of execution.
The setPixel method of the BitmapData class is far too slow for this kind of effect and even slower was the parsing every frame of the full array containing all the pixel of the first image.
So I come with completely new algorythm that uses three bitmaps/bitmapdatas where the first only displays original image and set to trasparent only pixels that have moved away.
The scond one redraws every frame, but only displays moving pixels which are stored in a much shorter array and the last one shows only pixels which reached the final position.
With this second approach only pixels effectively changing are redrawn and a lot of speed can be gained.
This first post is only for showcase, during next days I will write a technical post about class structure, speed optimisations etc. off course with source code.
Don’t forget to leave a comment if you like it 