Browse the notebook

Category: matrix

Utils3D.projectVectors() Lathe

[SWF(width = 500, height = 500, backgroundColor = 0x000000)]
var halfWidth:Number = stage.stageWidth / 2;
var halfHeight:Number = stage.stageHeight / 2;
var loc:Vector.<Number>;

graphics.lineStyle(0, 0xFF0000);
graphics.moveTo(halfWidth, 0);
graphics.lineTo(halfWidth, stage.stageHeight);
graphics.moveTo(0, halfHeight);
graphics.lineTo(stage.stageWidth, halfHeight);

var line:Shape = Shape(addChild(new Shape()));
line.x = halfWidth;

var idle:Function = function(){};
var currentMode:Function = idle;
stage.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
addEventListener(Event.ENTER_FRAME, onLoop);
function onDown(evt:MouseEvent):void{
	if (contains(frame)){
		removeChild(frame);
		currentMode = idle;
		line.graphics.clear();
		return;
	}
	loc = new Vector.<Number>();
	line.graphics.lineStyle(0,0xFFFFFF);
	line.x = halfWidth
	line.y = halfHeight;
	line.graphics.moveTo(line.mouseX, line.mouseY);
	currentMode = captureLocs;
	canvas.fillRect(canvas.rect, 0x000000);
}
function onUp(evt:MouseEvent):void{
	if (currentMode == idle) return;
	setupLathe();
	currentMode = showLathe;
}

function onLoop(evt:Event):void{
	currentMode();
}
function captureLocs():void{
	loc.push(line.mouseX);
	loc.push(line.mouseY);
	loc.push(0);
	line.graphics.lineTo(line.mouseX, line.mouseY);
}
/**
 -- Lathe Stuff:
*/
var canvas:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight,false, 0x000000);
var frame:Bitmap = new Bitmap(canvas);
var dx:Number=0;
var dy:Number=0;
 var matrix:Matrix3D = new Matrix3D();
var pVerts:Vector.<Number>;
var uvts:Vector.<Number>;
function setupLathe():void{
	addChild(frame);
	pVerts =  new Vector.<Number>();
	uvts = new Vector.<Number>();
	var nVerts:Vector.<Number> = new Vector.<Number>();
	var tVerts:Vector.<Number> = new Vector.<Number>();
	matrix.identity();
	var step:Number = 2;
	for (var i:int = 0; i <360; i+=step){
		matrix.appendRotation(step,Vector3D.Y_AXIS);
		matrix.transformVectors(loc, tVerts);
		nVerts = nVerts.concat(tVerts);
	}
	loc = nVerts.concat();
}
function showLathe():void{
	dx += (mouseX - dx)/4;
	dy += (mouseY - dy)/4;
	matrix.identity();
	matrix.appendRotation(dy,Vector3D.X_AXIS);
	matrix.appendRotation(dx,Vector3D.Y_AXIS);
	matrix.appendTranslation(halfWidth, halfHeight, 0);
	Utils3D.projectVectors(matrix, loc, pVerts, uvts);
	canvas.lock();
	canvas.fillRect(canvas.rect, 0x000000);
	var leng:int = pVerts.length;
	for (var i:int = 0; i<leng; i+=2){
		canvas.setPixel( pVerts[i], pVerts[i + 1], 0xFFFFFF);
	}
	canvas.unlock();
}

This snippet allows you to create 3D lathe shapes by drawing a 2D line. This is done using Utils3D.projectVectors() and Matrix.transformVectors().

Have a look at the swf here…

Read snippet: Utils3D.projectVectors() Lathe

Distance Render

var verts:Vector.<Number> = new Vector.<Number>();
var pVerts:Vector.<Number> = new Vector.<Number>();
var uvts:Vector.<Number> = new Vector.<Number>();

var hs:Number = 2.3;
var step:Number = 0.04;

var tVerts:Vector.<Number> = new Vector.<Number>();
var rVerts:Vector.<Number> = new Vector.<Number>();
var matrix:Matrix3D = new Matrix3D();
matrix.identity();
matrix.appendRotation(45,Vector3D.Y_AXIS);
matrix.appendRotation(45,Vector3D.X_AXIS);
var inc:int = 0;
var i:Number, j:Number, k:Number;
i = hs;
while( i > -hs){
	j = hs;
	while(j > -hs){
		k = hs;
		while(k > -hs){
			tVerts[inc] = -i;
			inc++
			tVerts[inc] = -j;
			inc++
			tVerts[inc] = -k;
			inc++
			k -= step;
		}
		j -= step;
	}
	i -= step;
}

matrix.transformVectors(tVerts, rVerts);
 
var vinc:int = 0;
inc = 0
var R:Number = 1.5;
var r:Number = .5;
for (i= -hs; i<hs; i+=step){
	for (j = -hs; j<hs; j+=step){
		for (k = -hs; k<hs; k+=step){
			var vx:Number = rVerts[inc] ;
			inc++
			var vy:Number = rVerts[inc]  ;
			inc++
			var vz:Number=  rVerts[inc] ;
			inc++
			var s:Number = Math.pow(vx  * vx  + vy * vy + vz * vz + R*R - r * r, 2) - 4 * (R * R)*(vx * vx + vy * vy); 
			if (s <0 && s > -.5){ 
				verts[vinc] = (i * 50);
				vinc++
				verts[vinc] = (j * 50);
				vinc++
				verts[vinc] = (k * 50);
				vinc++
				  inc += int((hs - k) / step) * 3;
				  k = hs;
			 }
		}
	}
}

var canvas:BitmapData = new BitmapData(400,400,false, 0x000000);
addChild(new Bitmap(canvas));
render();
function render():void{
	matrix.identity();
    matrix.appendTranslation(200, 200, 0);
	Utils3D.projectVectors(matrix, verts, pVerts, uvts);
	canvas.lock();
	canvas.fillRect(canvas.rect, 0x000000);
	var inc:int = 2;
	var c:int = 0;
	var r:Rectangle = new Rectangle();
	r.width = r.height = 2;
	for (var i:int = 0; i<pVerts.length; i+=2){
		  r.x = pVerts[i];
		  r.y = pVerts[i + 1];
		  c = Math.max(0,100 - verts[inc]);
		  canvas.fillRect(r, c << 16 | c << 8 | c);
		  inc += 3; 
	}
	canvas.unlock();
}

This snippet uses some of the techniques from the last few posts to create a distance render – this renders the implicit equation for a torus.

Read snippet: Distance Render

Utils3D.projectVectors() & 100,000 pixels

var matrix:Matrix3D = new Matrix3D();

const PARTICLE_NUM:int = 100000;
var verts:Vector.<Number> = new Vector.<Number>();
var pVerts:Vector.<Number> = new Vector.<Number>();
var uvts:Vector.<Number> = new Vector.<Number>();

for (var i:int = 0; i<PARTICLE_NUM; i++){
	verts.push(Math.random()*250 - 125);
	verts.push(Math.random()*250 - 125);
	verts.push(Math.random()*250 - 125);
	
	pVerts.push(0), pVerts.push(0);
	uvts.push(0), uvts.push(0), uvts.push(0);
}

var canvas:BitmapData = new BitmapData(400,400,false, 0x000000);
addChild(new Bitmap(canvas));
var dx:Number=0;
var dy:Number=0;

addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {

	dx += (mouseX - dx)/4;
	dy += (mouseY - dy)/4;
	
	matrix.identity();
	matrix.appendRotation(dy,Vector3D.X_AXIS);
	matrix.appendRotation(dx,Vector3D.Y_AXIS);
	matrix.appendTranslation(200, 200, 0);
	
	Utils3D.projectVectors(matrix, verts, pVerts, uvts);
	
	canvas.lock();
	canvas.fillRect(canvas.rect, 0x000000);
        var leng:int = pVerts.length;
	for (var i:int = 0; i<leng; i+=2){
		canvas.setPixel( pVerts[i], pVerts[i + 1], 0xFFFFFF);
	}
	canvas.unlock();
}

The above shows an easy way to use Utils3D.projectVectors() to move some pixels around in 3D. Since the 3D math is done behind the scenes by the flash player it runs quite fast…

Read snippet: Utils3D.projectVectors() & 100,000 pixels

Matrix() 3 Point Skew

[SWF(width=500, height=500, backgroundColor=0xFFFFFF, frameRate=30)]

var box:Sprite = createSprite("Rect", 0, 0, 100, 100, 0xFF0000);

var d0:Sprite = drag(createSprite("Ellipse",  -5, -5, 10, 10));
d0.x = d0.y = 200;

var d1:Sprite = drag(createSprite("Ellipse",  -5, -5, 10, 10));
d1.x = 200
d1.y = 300;

var d2:Sprite = drag(createSprite("Ellipse",  -5, -5, 10, 10));
d2.y = d0.y;
d2.x = 300;

addEventListener(Event.ENTER_FRAME, onLoop);

function onLoop(evt:Event):void {
 
	var m:Matrix = new Matrix();
	m.scale((d2.x - d0.x) / 100,(d1.y - d0.y) / 100);
	m.translate(d0.x, d0.y);
	
	m.c =  (d1.x - d0.x) / 100
	m.b =  (d2.y - d0.y ) / 100
	
	box.transform.matrix = m;
}

function createSprite(shape:String, xp:Number, yp:Number, w:Number, h:Number, col:uint=0x444444):Sprite {
	var s:Sprite = new Sprite();
	s.graphics.beginFill(col);
	s.graphics["draw" + shape](xp, yp, w, h);
	addChild(s);
	return s;
}

function drag(target:*):*{
	target.addEventListener(MouseEvent.MOUSE_DOWN, function(evt:MouseEvent){ evt.currentTarget.startDrag(); });
	return target;
}

stage.addEventListener(MouseEvent.MOUSE_UP, function(){ stopDrag() });

The above creates a red rectangle that can be skewed by dragging 3 points. Why is this so cool you ask?

This is why (move your mouse)

The above was written in flash 7, before the Matrix object existed. So in order to create it I used this technique from Eric Lin.

Read snippet: Matrix() 3 Point Skew