Monthly Archives: September 2009

More z-sorting

Actionscript:
  1. [SWF(width = 500, height=500, backgroundColor = 0x333333)]
  2. x = stage.stageWidth / 2;
  3. y = stage.stageHeight / 2;
  4.  
  5.  
  6. var polyNum:int = 3000;
  7. // standard Vectors for using drawTriangles
  8. var verts:Vector.<Number> = new Vector.<Number>();
  9. var pVerts:Vector.<Number>;
  10. var uvts:Vector.<Number> = new Vector.<Number>();
  11. var indices:Vector.<int> = new Vector.<int>();
  12. // needed for z-sorting
  13. var sortedIndices:Vector.<int>;
  14. var faces:Array = [];
  15.  
  16. // we'll use this for tranforming points
  17. // and as the transormation matrix for our render
  18. var m:Matrix3D = new Matrix3D();
  19.  
  20. // plot a poly
  21. var poly:Vector.<Number>;
  22. poly = Vector.<Number>([ 0, 0, 0,
  23.                         10, 0, 0,
  24.                         0,10, 0]);
  25.  
  26. // temp vect for any transformed polygons
  27. var transPoly:Vector.<Number> = new Vector.<Number>();
  28.  
  29. var i:int;
  30. var inc:int = 0;
  31. for (i = 0; i<polyNum; i++){
  32.     m.identity();
  33.     var s:Number = (int(Math.random()*50) == 1) ? 4 + Math.random()*2 : 1 + Math.random() * 2;
  34.     m.appendScale(s, s, 1);
  35.     m.appendRotation(Math.random()*360, Vector3D.X_AXIS);
  36.     m.appendRotation(Math.random()*360, Vector3D.Y_AXIS);
  37.     m.appendRotation(Math.random()*360, Vector3D.Z_AXIS);
  38.     m.appendTranslation(200,0,0);
  39.                          
  40.     m.appendRotation(Math.random()*360, Vector3D.X_AXIS);
  41.     m.appendRotation(Math.random()*360, Vector3D.Y_AXIS);
  42.     m.appendRotation(Math.random()*360, Vector3D.Z_AXIS);
  43.    
  44.     m.transformVectors(poly, transPoly);
  45.    
  46.     verts = verts.concat(transPoly);
  47.     faces.push(new Vector3D());
  48.     indices.push(inc++, inc++, inc++);
  49.     uvts.push(Math.random(), Math.random(), 0, Math.random(), Math.random(), 0, Math.random(), Math.random(), 0);
  50. }
  51.  
  52. sortedIndices = new Vector.<int>(indices.length, true);
  53.  
  54. // create texture
  55. var tex:BitmapData = new BitmapData(400,400,false, 0x000000);
  56. var grad:Shape = new Shape();
  57. var mat:Matrix = new Matrix();
  58. mat.createGradientBox(400,400,0,0,0);
  59. with (grad.graphics){
  60.     beginGradientFill(GradientType.LINEAR, [0x000000, 0xAA0000, 0xFFFF00], [1, 1, 1], [20, 200, 255], mat);
  61.     drawRect(0,0,400,400);
  62. }
  63. tex.draw(grad);
  64.  
  65. // create background
  66. mat.createGradientBox(1600,1000,0,-550, -100);
  67. with (grad.graphics){
  68.     beginGradientFill(GradientType.RADIAL, [0x333333, 0xffffff], [1, 1], [0, 255], mat);
  69.     drawRect(0,0,500,500);
  70. }
  71. grad.x = -stage.stageWidth/2
  72. grad.y = -stage.stageHeight/2;
  73. addChild(grad);
  74.  
  75. // triangles will be drawn to this
  76. var render:Shape = Shape(addChild(new Shape()));
  77.  
  78. // fix all vector lengths
  79. verts.fixed = true, uvts.fixed = true, indices.fixed = true
  80. pVerts = new Vector.<Number>(verts.length/3 * 2, true);
  81.  
  82. // we need these if we want perspective
  83. var persp:PerspectiveProjection = new PerspectiveProjection();
  84. persp.fieldOfView = 45;
  85. // projection matrix
  86. var proj:Matrix3D = persp.toMatrix3D();
  87.  
  88. var dx:Number = 0, dy:Number = 0;
  89. addEventListener(Event.ENTER_FRAME, onLoop);
  90. function onLoop(evt:Event):void {
  91.     dx += (mouseX - dx) / 4;
  92.     dy += (mouseY - dy) / 4;
  93.     m.identity();
  94.     m.appendRotation(dy, Vector3D.X_AXIS);
  95.     m.appendRotation(dx, Vector3D.Y_AXIS);
  96.     // push everything back so its not to close
  97.     m.appendTranslation(0,0,800);
  98.     // append the projection matrix at the end
  99.     m.append(proj);
  100.    
  101.     Utils3D.projectVectors(m, verts, pVerts, uvts);
  102.    
  103.     var face:Vector3D;
  104.     inc = 0;
  105.     for (var i:int = 0; i<indices.length; i+=3){
  106.         face = faces[inc];
  107.         face.x = indices[i];
  108.         // it may look odd, but casting to an int
  109.         // when doing operations inside array sytnax
  110.         // adds a big speed boost
  111.         face.y = indices[int(i + 1)];
  112.         face.z = indices[int(i + 2)];
  113.         var i3:int = i * 3;
  114.         // get the average z position (t value) and store it in the Vector3D w property
  115.         // depending on your model, you may not need to do an average of all 3 values
  116.         face.w = (uvts[int(i3 + 2)] + uvts[int(i3 + 5)] + uvts[int(i3 + 8)]) * 0.333333;
  117.         inc++;
  118.     }
  119.      
  120.     // sort on w, so far this beats all other sorting methods for speed,
  121.     // faster than Vector.sort(), faster than any custom sort method I could find
  122.     faces.sortOn("w", Array.NUMERIC);
  123.  
  124.     // re-order indices so that faces are drawn in the correct order (back to front);
  125.     inc = 0;
  126.     for each (face in faces){
  127.         sortedIndices[inc++] = face.x;
  128.         sortedIndices[inc++] = face.y;
  129.         sortedIndices[inc++] = face.z;
  130.     }
  131.    
  132.     render.graphics.clear();
  133.     render.graphics.beginBitmapFill(tex, null, false, false);
  134.     render.graphics.drawTriangles(pVerts, sortedIndices, uvts, TriangleCulling.NONE);
  135. }

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...

Posted in 3D, Graphics, Vector, matrix, misc | Tagged , , , , | 6 Comments