More z-sorting

[SWF(width = 500, height=500, backgroundColor = 0x333333)]
x = stage.stageWidth / 2;
y = stage.stageHeight / 2;


var polyNum:int = 3000;
// standard Vectors for using drawTriangles
var verts:Vector.<Number> = new Vector.<Number>();
var pVerts:Vector.<Number>;
var uvts:Vector.<Number> = new Vector.<Number>();
var indices:Vector.<int> = new Vector.<int>();
// needed for z-sorting
var sortedIndices:Vector.<int>;
var faces:Array = [];

// we'll use this for tranforming points
// and as the transormation matrix for our render
var m:Matrix3D = new Matrix3D();

// plot a poly
var poly:Vector.<Number>;
poly = Vector.<Number>([ 0, 0, 0,
					    10, 0, 0,
					    0,10, 0]);

// temp vect for any transformed polygons
var transPoly:Vector.<Number> = new Vector.<Number>();

var i:int;
var inc:int = 0;
for (i = 0; i<polyNum; i++){
	m.identity();
	var s:Number = (int(Math.random()*50) == 1) ? 4 + Math.random()*2 : 1 + Math.random() * 2;
	m.appendScale(s, s, 1);
	m.appendRotation(Math.random()*360, Vector3D.X_AXIS);
	m.appendRotation(Math.random()*360, Vector3D.Y_AXIS);
	m.appendRotation(Math.random()*360, Vector3D.Z_AXIS);
	m.appendTranslation(200,0,0);
						 
	m.appendRotation(Math.random()*360, Vector3D.X_AXIS);
	m.appendRotation(Math.random()*360, Vector3D.Y_AXIS);
	m.appendRotation(Math.random()*360, Vector3D.Z_AXIS);
	
	m.transformVectors(poly, transPoly);
	
	verts = verts.concat(transPoly);
	faces.push(new Vector3D());
	indices.push(inc++, inc++, inc++);
	uvts.push(Math.random(), Math.random(), 0, Math.random(), Math.random(), 0, Math.random(), Math.random(), 0);
}

sortedIndices = new Vector.<int>(indices.length, true);

// create texture
var tex:BitmapData = new BitmapData(400,400,false, 0x000000);
var grad:Shape = new Shape();
var mat:Matrix = new Matrix();
mat.createGradientBox(400,400,0,0,0);
with (grad.graphics){
	beginGradientFill(GradientType.LINEAR, [0x000000, 0xAA0000, 0xFFFF00], [1, 1, 1], [20, 200, 255], mat);
	drawRect(0,0,400,400);
}
tex.draw(grad);

// create background
mat.createGradientBox(1600,1000,0,-550, -100);
with (grad.graphics){
	beginGradientFill(GradientType.RADIAL, [0x333333, 0xffffff], [1, 1], [0, 255], mat);
	drawRect(0,0,500,500);
}
grad.x = -stage.stageWidth/2
grad.y = -stage.stageHeight/2;
addChild(grad);

// triangles will be drawn to this
var render:Shape = Shape(addChild(new Shape()));

// fix all vector lengths
verts.fixed = true, uvts.fixed = true, indices.fixed = true
pVerts = new Vector.<Number>(verts.length/3 * 2, true); 

// we need these if we want perspective
var persp:PerspectiveProjection = new PerspectiveProjection();
persp.fieldOfView = 45;
// projection matrix
var proj:Matrix3D = persp.toMatrix3D();

var dx:Number = 0, dy:Number = 0;
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	dx += (mouseX - dx) / 4;
	dy += (mouseY - dy) / 4;
	m.identity();
	m.appendRotation(dy, Vector3D.X_AXIS);
	m.appendRotation(dx, Vector3D.Y_AXIS);
	// push everything back so its not to close
	m.appendTranslation(0,0,800);
	// append the projection matrix at the end
	m.append(proj);
	
	Utils3D.projectVectors(m, verts, pVerts, uvts);
	
	var face:Vector3D;
	inc = 0;
	for (var i:int = 0; i<indices.length; i+=3){
		face = faces[inc];
		face.x = indices[i];
		// it may look odd, but casting to an int 
		// when doing operations inside array sytnax
		// adds a big speed boost
		face.y = indices[int(i + 1)];
		face.z = indices[int(i + 2)];
		var i3:int = i * 3;
		// get the average z position (t value) and store it in the Vector3D w property
		// depending on your model, you may not need to do an average of all 3 values
		face.w = (uvts[int(i3 + 2)] + uvts[int(i3 + 5)] + uvts[int(i3 + 8)]) * 0.333333;
		inc++;
	}
	 
	// sort on w, so far this beats all other sorting methods for speed,
	// faster than Vector.sort(), faster than any custom sort method I could find
	faces.sortOn("w", Array.NUMERIC);

	// re-order indices so that faces are drawn in the correct order (back to front);
	inc = 0;
	for each (face in faces){
		sortedIndices[inc++] = face.x;
		sortedIndices[inc++] = face.y;
		sortedIndices[inc++] = face.z;
	}
	
	render.graphics.clear();
	render.graphics.beginBitmapFill(tex, null, false, false);
	render.graphics.drawTriangles(pVerts, sortedIndices, uvts, TriangleCulling.NONE);
}

This is a slightly more advanced version of the z-sorting demo from yesterday. Here 3000 polygons are randomly arranged in a sphere formation…


Have a look at the swf…

6 comments

  1. it looks great, but the sphere on wonderfl is very small (I had to right-click/zoom 2x or 3x). Is there a scale problem?
    ps: I’ve flash player 10.0.r12

    Great blog anyway ๐Ÿ˜‰

  2. not sure what would cause the sphere to be small, but if you just copy this code into your timeline or copy the code from wonderfl into flex you can see it full size…

  3. If you see sphere small try upgrading flash player 10. Some versions are buggy with perspectiveProjection and matrix3D.

Leave a Reply

Your email address will not be published. Required fields are marked *