Category Archives: 3D

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

Also posted in Graphics, Vector, matrix, misc | Tagged , , , , | 6 Comments

drawTriangles() & z-sorting

Actionscript:
  1. [SWF(width = 500, height=500, backgroundColor = 0x000000)]
  2. x = stage.stageWidth / 2;
  3. y = stage.stageHeight / 2;
  4.  
  5. // standard Vectors for using drawTriangles and projectVectors
  6. var verts:Vector.<Number> = new Vector.<Number>();
  7. var pVerts:Vector.<Number>;
  8. var uvts:Vector.<Number>;
  9. var indices:Vector.<int>;
  10. // needed for z-sorting
  11. var sortedIndices:Vector.<int>;
  12. var faces:Array = [];
  13.  
  14. // we'll use this for transforming points
  15. // and as the transformation matrix for our render
  16. var m:Matrix3D = new Matrix3D();
  17.  
  18. // plot a poly
  19. var poly:Vector.<Number>;
  20. poly = Vector.<Number>([ 0, 0, 0,
  21.                         10, 0, 0,
  22.                         0,10, 0]);
  23.  
  24. verts = verts.concat(poly);
  25. faces.push(new Vector3D());
  26.  
  27. // add two more polygons by transorming the poly Vector
  28. // and concatenating it to the verts Vector
  29. // Vector3D instances are added to the faces
  30. // Array for z-sorting
  31.  
  32. // temp vect for any transformed polygons
  33. var transPoly:Vector.<Number> = new Vector.<Number>();
  34.  
  35. m.appendRotation(10, Vector3D.Z_AXIS);
  36. m.appendTranslation(0,-2,5);
  37. m.transformVectors(poly, transPoly);
  38.  
  39. verts = verts.concat(transPoly);
  40. faces.push(new Vector3D());
  41.  
  42. m.appendRotation(10, Vector3D.Z_AXIS);
  43. m.appendTranslation(0,-2,5);
  44. m.transformVectors(poly, transPoly);
  45. verts = verts.concat(transPoly);
  46. faces.push(new Vector3D());
  47.  
  48. // hard coded indices
  49. indices = Vector.<int>([0, 1, 2, 3, 4, 5, 6, 7, 8]);
  50. sortedIndices = new Vector.<int>(indices.length, true);
  51.  
  52. // create texture
  53. var tex:BitmapData = new BitmapData(100,100,false, 0x000000);
  54. tex.fillRect(new Rectangle(0,0,50,50), 0xFF0000);
  55. tex.fillRect(new Rectangle(50,0,50,50), 0x0000FF);
  56. tex.fillRect(new Rectangle(0,50,50,50), 0x00FF00);
  57.  
  58. // hard coded uvts
  59. uvts = Vector.<Number>([0,0,0, .5,0,0, 0,.5,0,
  60.                         .53, 0, 0, 1, 0, 0, .53, .5, 0,
  61.                          0,.6,.5, 0,.6,0, 0,1, 0]);
  62.                        
  63. // fix all vector lengths
  64. verts.fixed = true, uvts.fixed = true, indices.fixed = true
  65. pVerts = new Vector.<Number>(verts.length/3 * 2, true);
  66.  
  67. // we need these if we want perspective
  68. var persp:PerspectiveProjection = new PerspectiveProjection();
  69. // projection matrix
  70. var proj:Matrix3D = persp.toMatrix3D();
  71.  
  72. addEventListener(Event.ENTER_FRAME, onLoop);
  73. function onLoop(evt:Event):void {
  74.     m.identity();
  75.     m.appendRotation(mouseY * 2, Vector3D.X_AXIS);
  76.     m.appendRotation(mouseX * 2, Vector3D.Y_AXIS);
  77.     // push everything back so its not too close
  78.     m.appendTranslation(0,0,40);
  79.     // append the projection matrix at the end
  80.     m.append(proj);
  81.    
  82.     Utils3D.projectVectors(m, verts, pVerts, uvts);
  83.    
  84.     var face:Vector3D;
  85.     var inc:int = 0;
  86.     for (var i:int = 0; i<indices.length; i+=3){
  87.         face = faces[inc];
  88.         face.x = indices[i];
  89.         // it may look odd, but casting to an int
  90.         // when doing operations inside array sytnax
  91.         // adds a big speed boost
  92.         face.y = indices[int(i + 1)];
  93.         face.z = indices[int(i + 2)];
  94.         var i3:int = i * 3;
  95.         // get the average z position (t value) and store it in the Vector3D w property
  96.         // depending on your model, you may not need to do an average of all 3 values
  97.                 // (t is the distance from the eye to the texture)
  98.         face.w = (uvts[int(i3 + 2)] + uvts[int(i3 + 5)] + uvts[int(i3 + 8)]) * 0.333333;
  99.         inc++;
  100.     }
  101.    
  102.     // sort on w, so far this beats all other sorting methods for speed,
  103.     // faster than Vector.sort(), faster than any custom sort method I could find
  104.     faces.sortOn("w", Array.NUMERIC);
  105.    
  106.     // re-order indices so that faces are drawn in the correct order (back to front);
  107.     inc = 0;
  108.     for each (face in faces){
  109.         sortedIndices[inc++] = face.x;
  110.         sortedIndices[inc++] = face.y;
  111.         sortedIndices[inc++] = face.z;
  112.     }
  113.    
  114.     graphics.clear();
  115.     graphics.beginBitmapFill(tex, null, false, false);
  116.     graphics.drawTriangles(pVerts, sortedIndices, uvts, TriangleCulling.NONE);
  117. }

So you want to be able to do some z-sorting with drawTriangles()? Well, its extremely unintuitive. Here is what you need to know:

1) Vector.sort() is slow
2) Array.sortOn() is quite fast
3) I couldn't get any custom sorting method to be faster than Array.sortOn
4) You can use the t value from uvts to do z-sorting (like in this demo)
5) If your going for speed, don't forget to use fixed Vectors (I often forget this step)
6) When working with Vectors cast any operations inside brackets to int() (my tests showed this is a huge speed boost up to 3x faster - franky I think it's horrible that you have to do this).

The swf is not very interesting because I wanted to keep it super simple, but here it is anyway...


Questions

I was told and have read that drawTriangles is slower than using drawGraphicsData and a GraphicsTrianglePath instance. I tested this extensively and found that drawGraphicsData was slower. I'm still not sure which is faster but am up for checking out any simple benchmarks that people have.

drawTriangles is supposed to be faster without adding t values to the uvts Vector. In my benchmark tests there was no real difference in speed. The t value is used to render more accurate textures - which would mean you could potentially use less triangles in your models. One would assume that not using a t value would be faster... but I couldn't confirm this. Again if someone has a good benchmark for this, please let me know.

Help

I had a great deal of help from a few people on Twitter, Katopz (Away3D contributor) of sleepydesign.com made me aware of the fact that Array.sortOn is the way to go... You can see some great demos over at Katopz's blog. While I didn't end up using a custom sorting method, Inspirit
pointed me to his article about custom Vector sorting methods which proved to be very enlightening. I was able to get some really great results for doing different types of sorting - just sorting 1D Vectors with FlashSort can be very fast (faster than Array.sortOn - but not helpful for sorting a 1D Vector of indices).

I also learned a good deal by looking at this code post by Psyark... I actually optimized that code to run about 2x faster (will post that on wonderfl.net at some point, it just needs to be cleaned up).

kevinSuttle sent me a link to The video

Also posted in Graphics, Vector, matrix | Tagged , , , , | 3 Comments

globalToLocal() in 3D

Actionscript:
  1. [SWF(frameRate=60, backgroundColor=0x000000, width=500, height=500)]
  2. stage.quality = "medium";
  3. var frame:Sprite = Sprite(addChild(new Sprite()));
  4. with (frame.graphics) beginFill(0xCCCCCC), drawRect(-200, -200, 400, 400), endFill();
  5. frame.x = stage.stageWidth / 2;
  6. frame.y = stage.stageHeight / 2;
  7. frame.z = 100;
  8.  
  9. var canvas:Shape = Shape(frame.addChild(new Shape()));
  10. var msk:Shape = Shape(frame.addChild(new Shape()));
  11. with (msk.graphics) beginFill(0x00FF00), drawRect(-200, -200, 400, 400), endFill();
  12. canvas.mask = msk
  13.  
  14. var txt:TextField = TextField(addChild(new TextField()));
  15. txt.defaultTextFormat = new TextFormat("_sans", 12);
  16. txt.x = txt.y = 10;
  17. txt.textColor = 0xFFFFFF, txt.autoSize="left", txt.text = "Draw on the 3D plane...";
  18.  
  19. stage.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
  20. stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
  21. function onDown(evt:MouseEvent):void{
  22.     canvas.graphics.lineStyle(4, 0x000000);
  23.     var pnt:Point = frame.globalToLocal(new Point(mouseX, mouseY));
  24.     canvas.graphics.moveTo(pnt.x, pnt.y);
  25.     addEventListener(Event.ENTER_FRAME, onDraw);
  26. }
  27. function onUp(evt:MouseEvent):void{
  28.     removeEventListener(Event.ENTER_FRAME, onDraw);
  29. }
  30.  
  31. var t:Number = 0;
  32. addEventListener(Event.ENTER_FRAME, onLoop);
  33. function onLoop(evt:Event):void {
  34.     frame.rotationY = 35 * Math.sin(t);
  35.     frame.rotationX = 35 * Math.cos(t);
  36.     t+=0.02;
  37. }
  38.  
  39. function onDraw(evt:Event):void {
  40.         var pnt:Point = frame.globalToLocal(new Point(mouseX, mouseY));
  41.     canvas.graphics.lineTo(pnt.x, pnt.y);
  42. }

This demo shows that globalToLocal() works with 3D - saving us the trouble of doing some extra math if we want to draw on 3D display objects...

Have a look at the swf....


Was made aware of this trick by watching a video that kevinSuttle sent me via twitter. The video is an interview with Chris Nuuja (one of the flash player engineers).

Also posted in DisplayObject, Graphics, misc, motion | Tagged , , | 3 Comments

3D Key Controls

Actionscript:
  1. [SWF(backgroundColor=0x000000, width=500, height=500)]
  2. var hsw:Number = stage.stageWidth / 2;
  3. var hsh:Number = stage.stageHeight / 2;
  4. var pointNum:int = 300;
  5. var points3D:Vector.<Number> = new Vector.<Number>();
  6. var points2D:Vector.<Number> = new Vector.<Number>();
  7. var uvts:Vector.<Number> = new Vector.<Number>();
  8. var sorted:Array = [];
  9. var pnt:Point = new Point();
  10. var m:Matrix3D = new Matrix3D();
  11. var v:Vector3D = new Vector3D();
  12. for (var i:int = 0; i<pointNum; i++){
  13.     v.x = 300;
  14.     v.y = v.z = 0;
  15.     m.identity();
  16.     m.appendRotation(Math.random()*360, Vector3D.X_AXIS);
  17.     m.appendRotation(Math.random()*360, Vector3D.Y_AXIS);
  18.     m.appendRotation(Math.random()*360, Vector3D.Z_AXIS);
  19.     v = m.transformVector(v);
  20.     points3D.push(v.x, v.y, v.z);
  21.     points2D.push(0,0);
  22.     uvts.push(0,0,0);
  23.     sorted.push(new Vector3D());
  24. }
  25. points3D.fixed = true;
  26. points2D.fixed = true;
  27. uvts.fixed = true;
  28. var p:PerspectiveProjection = new PerspectiveProjection();
  29. var proj:Matrix3D = p.toMatrix3D();
  30. var rx:Number = 0, ry:Number = 0;
  31. addEventListener(Event.ENTER_FRAME, onLoop);
  32. function onLoop(evt:Event):void {
  33.     var i:int, j:int;
  34.     m.identity();
  35.     if (key[Keyboard.RIGHT]){
  36.         rx+=3
  37.     }else
  38.     if (key[Keyboard.LEFT]){
  39.         rx-=3
  40.     }else
  41.     if (key[Keyboard.UP]){
  42.         ry-=3
  43.     }else
  44.     if (key[Keyboard.DOWN]){
  45.         ry+=3
  46.     }
  47.     m.appendRotation(rx, Vector3D.Y_AXIS);
  48.     m.appendRotation(ry, Vector3D.X_AXIS);
  49.     m.appendTranslation(0, 0, 1000);
  50.     m.append(proj);
  51.     Utils3D.projectVectors(m, points3D, points2D, uvts);
  52.     for (i = 0, j = 0; i<points2D.length; i+=2, j++){
  53.         sorted[j].x = points2D[i] + hsw;
  54.         sorted[j].y = points2D[i + 1] + hsh;
  55.         sorted[j].z = uvts[j * 3 + 2];
  56.     }
  57.     sorted.sortOn("z", Array.NUMERIC);
  58.     graphics.clear();
  59.     graphics.lineStyle(2, 0x000000, 0.1);
  60.     for(i = 0; i<sorted.length; i++){
  61.         var zpos:Number = sorted[i].z * 12000;
  62.         var c:int = zpos * 14;
  63.         c = (c> 255) ? 255 : c;
  64.         graphics.beginFill(100<<16 | 100 <<8 |c);
  65.         graphics.drawCircle(sorted[i].x, sorted[i].y,zpos);
  66.         graphics.endFill();
  67.     }
  68. }
  69.  
  70. // permanently applies the matrix to the points3D vector
  71. function applyTransform():void{
  72.     m.identity();
  73.     m.appendRotation(rx, Vector3D.Y_AXIS);
  74.     m.appendRotation(ry, Vector3D.X_AXIS);
  75.     var temp:Vector.<Number> = new Vector.<Number>();
  76.     m.transformVectors(points3D, temp);
  77.     points3D = temp;
  78.     points3D.fixed = true;
  79.     rx = 0, ry = 0;
  80. }
  81.  
  82. // basic key setup
  83. var key:Object = new Object();
  84. stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyPressed);
  85. stage.addEventListener(KeyboardEvent.KEY_UP, onKeyReleased);
  86. function onKeyPressed(evt:KeyboardEvent):void {
  87.     key[evt.keyCode] = true;
  88.     key.keyCode = evt.keyCode;
  89. }
  90. function onKeyReleased(evt:KeyboardEvent):void {
  91.   applyTransform();
  92.   key[evt.keyCode] = false;
  93. }

In response to Thomas Francis's question, this snippet takes the Simple z-sorting snippet and shows how one might go about adding some basic key controls to it. It works by permanently applying x and y rotation transformations to the set of 3D points every time a key is released.

Check out the swf...

If you need to be able to rotate on both the x and y axis at the same time - and just need more flexibility... one way to do it would be to use quaternions - which may be tricky - but there are plenty of examples out there in java, processing and C/C++ just waiting to be ported (been on the todo list for some time actually).

Haven't been posting every day because I've been out of the country and away from my computer... have a backlog of snippets that need to be cleaned up and put in the pipeline...

Also posted in Graphics, Vector, keys | Tagged , , | 3 Comments

Simple z-sorting

Actionscript:
  1. [SWF(backgroundColor=0x444444, width=500, height=500)]
  2. var hsw:Number = stage.stageWidth / 2;
  3. var hsh:Number = stage.stageHeight / 2;
  4.  
  5. var pointNum:int = 200;
  6. var points3D:Vector.<Number> = new Vector.<Number>();
  7. var points2D:Vector.<Number> = new Vector.<Number>();
  8. var uvts:Vector.<Number> = new Vector.<Number>();
  9. var sorted:Array = [];
  10.  
  11. var pnt:Point = new Point();
  12. var m:Matrix3D = new Matrix3D();
  13. var v:Vector3D = new Vector3D();
  14. for (var i:int = 0; i<pointNum; i++){
  15.     v.x = Math.random()*400-200;
  16.     m.identity();
  17.     m.appendRotation(Math.random()*360, Vector3D.X_AXIS);
  18.     m.appendRotation(Math.random()*360, Vector3D.Y_AXIS);
  19.     m.appendRotation(Math.random()*360, Vector3D.Z_AXIS);
  20.     v = m.transformVector(v);
  21.     points3D.push(v.x, v.y, v.z);
  22.     points2D.push(0,0);
  23.     uvts.push(0,0,0);
  24.     sorted.push(new Vector3D());
  25. }
  26. points3D.fixed = true;
  27. points2D.fixed = true;
  28. uvts.fixed = true;
  29.  
  30. var p:PerspectiveProjection = new PerspectiveProjection();
  31. var proj:Matrix3D = p.toMatrix3D();
  32.  
  33. var dx:Number = 0, dy:Number = 0;
  34. addEventListener(Event.ENTER_FRAME, onLoop);
  35. function onLoop(evt:Event):void {
  36.     var i:int, j:int;
  37.     dx += (mouseX - dx) / 4;
  38.     dy += (mouseY - dy) / 4;
  39.     m.identity();
  40.     m.appendRotation(dx, Vector3D.Y_AXIS);
  41.     m.appendRotation(dy, Vector3D.X_AXIS);
  42.     m.appendTranslation(0, 0, 1000);
  43.     m.append(proj);
  44.    
  45.     Utils3D.projectVectors(m, points3D, points2D, uvts);
  46.    
  47.     for (i = 0, j = 0; i<points2D.length; i+=2, j++){
  48.         sorted[j].x = points2D[i] + hsw;
  49.         sorted[j].y = points2D[i + 1] + hsh;
  50.         sorted[j].z = uvts[j * 3 + 2];
  51.     }
  52.     sorted.sortOn("z", Array.NUMERIC);
  53.    
  54.     graphics.clear();
  55.     for(i = 0; i<sorted.length; i++){
  56.         var zpos:Number = sorted[i].z * 12000;
  57.         var c:int = zpos * 14;
  58.         graphics.beginFill(c <<16 | c <<8 | c);
  59.         graphics.drawCircle(sorted[i].x, sorted[i].y,zpos);
  60.         graphics.endFill();
  61.     }
  62. }

Here is an easy way to do z-sorting on a cluster of circles.


Have a look at the swf over at wonderfl...

Also posted in Graphics, Vector, sortOn | Tagged , , | 5 Comments

Gradient Bezier 3D

Actionscript:
  1. [SWF(backgroundColor=0x333333, width=800, height=600)];
  2. x = stage.stageWidth / 2;
  3. y = stage.stageHeight / 2;
  4. var verts:Vector.<Number>  = new Vector.<Number>();
  5. var tVerts:Vector.<Number> = new Vector.<Number>();
  6. var pVerts:Vector.<Number> = new Vector.<Number>();
  7. var uvts:Vector.<Number> = new Vector.<Number>();
  8.  
  9. var igraph:Vector.<IGraphicsData> = new Vector.<IGraphicsData>();
  10.  
  11. var tVect:Vector3D = new Vector3D();
  12. var m:Matrix3D = new Matrix3D();
  13. for (var i:int = 0; i<200; i++){
  14.     for (var j:int = 0; j<3; j++){
  15.         tVect.x = Math.random() * 0.15;
  16.         m.identity();
  17.         m.appendRotation(Math.random()*360, Vector3D.X_AXIS);
  18.         m.appendRotation(Math.random()*360, Vector3D.Y_AXIS);
  19.         m.appendRotation(Math.random()*360, Vector3D.Z_AXIS);
  20.         tVect = m.transformVector(tVect);
  21.         verts.push(tVect.x, tVect.y, tVect.z);
  22.     }
  23.    
  24.     var stroke:GraphicsStroke = new GraphicsStroke();
  25.    
  26.     var col:int = [0xFFFFFF, 0x000000, 0xFFCC00, 0xFF0000][int(Math.random() * 4)];
  27.    
  28.     stroke.thickness = 2+(Math.random()*Math.random())*8;
  29.     var mg:Matrix = new Matrix();
  30.     mg.createGradientBox(350+Math.random()*20-10, 350+Math.random()*20-10, 0, -270+i/2,-240+i/2);
  31.     stroke.fill = new GraphicsGradientFill(GradientType.RADIAL, [0xFFFFFF,0x444444], [1, 1], [30, 255], mg);
  32.  
  33.     var bez:GraphicsPath = new GraphicsPath();
  34.     bez.commands = Vector.<int>([1, 3]);
  35.     igraph.push(stroke);
  36.     igraph.push(bez);
  37. }
  38.  
  39. var perspective:PerspectiveProjection = new PerspectiveProjection();
  40. perspective.fieldOfView = 45;
  41. var trans:Matrix3D = new Matrix3D();
  42. var proj:Matrix3D = perspective.toMatrix3D();
  43. var dx:Number = 0, dy:Number = 0;
  44.  
  45. addEventListener(Event.ENTER_FRAME, onLoop);
  46. function onLoop(evt:Event):void {
  47.     dx += (mouseX - dx) / 4;
  48.     dy += (mouseY - dy) / 4;
  49.        
  50.     trans.identity();
  51.     trans.appendRotation(dy, Vector3D.X_AXIS);
  52.     trans.appendRotation(dx, Vector3D.Y_AXIS);
  53.     trans.appendTranslation(0,0,0.5);
  54.     trans.transformVectors(verts, tVerts);
  55.     Utils3D.projectVectors(proj, tVerts, pVerts, uvts);
  56.    
  57.     var inc:int = 0;
  58.     for (var i:int = 1; i<igraph.length; i+=2){
  59.         GraphicsPath(igraph[i]).data = pVerts.slice(inc, inc + 6);
  60.         inc += 6;
  61.     }
  62.      
  63.     graphics.clear();
  64.     graphics.drawGraphicsData(igraph);
  65. }

A variation on yesterdays post - this makes use of GraphicsGradientFill to add some depth...

Check out the swf...

Also posted in Graphics, bezier | Tagged , , | Leave a comment

3D Bezier

Actionscript:
  1. [SWF(backgroundColor=0x000000, width=800, height=600)];
  2. x = stage.stageWidth / 2;
  3. y = stage.stageHeight / 2;
  4. var verts:Vector.<Number>  = new Vector.<Number>();
  5. var tVerts:Vector.<Number> = new Vector.<Number>();
  6. var pVerts:Vector.<Number> = new Vector.<Number>();
  7. var uvts:Vector.<Number> = new Vector.<Number>();
  8.  
  9. var igraph:Vector.<IGraphicsData> = new Vector.<IGraphicsData>();
  10.  
  11. var tVect:Vector3D = new Vector3D();
  12. var m:Matrix3D = new Matrix3D();
  13. for (var i:int = 0; i<300; i++){
  14.     for (var j:int = 0; j<3; j++){
  15.         tVect.x = Math.random() * 0.15;
  16.         m.identity();
  17.         m.appendRotation(Math.random()*360, Vector3D.X_AXIS);
  18.         m.appendRotation(Math.random()*360, Vector3D.Y_AXIS);
  19.         m.appendRotation(Math.random()*360, Vector3D.Z_AXIS);
  20.         tVect = m.transformVector(tVect);
  21.         verts.push(tVect.x, tVect.y, tVect.z);
  22.     }
  23.    
  24.      
  25.     var stroke:IGraphicsData = new GraphicsStroke();
  26.    
  27.     var col:int = [0xFFFFFF, 0x000000, 0xFFCC00, 0xFF0000][int(Math.random() * 4)];
  28.     with (stroke) thickness = (Math.random()*Math.random())*10, fill = new GraphicsSolidFill(col);
  29.  
  30.     var bez:GraphicsPath = new GraphicsPath();
  31.     bez.commands = Vector.<int>([1, 3]);
  32.     igraph.push(stroke);
  33.     igraph.push(bez);
  34. }
  35.  
  36. var perspective:PerspectiveProjection = new PerspectiveProjection();
  37. perspective.fieldOfView = 45;
  38. var trans:Matrix3D = new Matrix3D();
  39. var proj:Matrix3D = perspective.toMatrix3D();
  40. var dx:Number = 0, dy:Number = 0;
  41.  
  42. addEventListener(Event.ENTER_FRAME, onLoop);
  43. function onLoop(evt:Event):void {
  44.     dx += (mouseX - dx) / 4;
  45.     dy += (mouseY - dy) / 4;
  46.        
  47.     trans.identity();
  48.     trans.appendRotation(dy, Vector3D.X_AXIS);
  49.     trans.appendRotation(dx, Vector3D.Y_AXIS);
  50.     trans.appendTranslation(0,0,0.5);
  51.     trans.transformVectors(verts, tVerts);
  52.     Utils3D.projectVectors(proj, tVerts, pVerts, uvts);
  53.    
  54.     var inc:int = 0;
  55.     for (var i:int = 1; i<igraph.length; i+=2){
  56.         GraphicsPath(igraph[i]).data = pVerts.slice(inc, inc + 6);
  57.         inc += 6;
  58.     }
  59.      
  60.     graphics.clear();
  61.     graphics.drawGraphicsData(igraph);
  62. }

After a few hours of trying to get a super optimized fp10 z-sorting demo happening, I gave up (for now) and decided to just let loose with something easy. The result is this 3D Bezier example...


Check out the swf...

Also posted in Graphics, bezier | Tagged , , , | 3 Comments

Gumdrop Torus

Actionscript:
  1. var matrix:Matrix3D = new Matrix3D();
  2.  
  3. var verts:Vector.<Number> = new Vector.<Number>();
  4. var pVerts:Vector.<Number> = new Vector.<Number>();
  5. var uvts:Vector.<Number> = new Vector.<Number>();
  6.  
  7. for (var i:Number = -2; i<2; i+=.04){
  8.     for (var j:Number = -2; j<2; j+=.04){
  9.         for (var k:Number = -2; k<2; k+=.04){
  10. // equation from: http://local.wasp.uwa.edu.au/~pbourke/geometry/gumdrop/
  11.             var yz:Number = j * j + k * k;
  12.              var s:Number = 4 * (Math.pow(i,4) + Math.pow(yz,2))
  13.              + 17 * i * i *(yz) - 20 * (yz + i * i) + 17;
  14.             if (s <0 && s> -0.5){
  15.                 verts.push(i * 60);
  16.                 verts.push(j * 60);
  17.                 verts.push(k * 60);
  18.                 pVerts.push(0), pVerts.push(0);
  19.                 uvts.push(0), uvts.push(0), uvts.push(0);
  20.              }
  21.         }
  22.     }
  23. }
  24.  
  25. var tVerts:Vector.<Number> = new Vector.<Number>();
  26. matrix.appendRotation(90, Vector3D.X_AXIS);
  27. matrix.appendRotation(45, Vector3D.Y_AXIS);
  28. matrix.appendScale(1.7, 1.7, 1.7);
  29. matrix.transformVectors(verts, tVerts);
  30.  
  31. var p:Point = new Point();
  32. var brush:BitmapData=new BitmapData(3,3,true,0x41FFFFFF);
  33. var canvas:BitmapData = new BitmapData(500,500,false, 0x000000);
  34. addChild(new Bitmap(canvas));
  35. var dx:Number=0;
  36. var dy:Number=0;
  37. addEventListener(Event.ENTER_FRAME, onLoop);
  38. function onLoop(evt:Event):void {
  39.     dx += (mouseX - dx)/4;
  40.     dy += (mouseY - dy)/4;
  41.     matrix.identity();
  42.     matrix.appendRotation(dy,Vector3D.X_AXIS);
  43.     matrix.appendRotation(dx,Vector3D.Y_AXIS);
  44.     matrix.appendTranslation(250, 250, 0);
  45.     Utils3D.projectVectors(matrix, tVerts, pVerts, uvts);
  46.     canvas.lock();
  47.     canvas.fillRect(canvas.rect, 0x000000);
  48.     var inc:int = 0;
  49.     for (var i:int = 0; i<pVerts.length; i+=2){
  50.      
  51.         p.x = pVerts[i];
  52.         p.y = pVerts[i+1];
  53.         canvas.copyPixels(brush, brush.rect, p, null, null, true);
  54.     }
  55.     canvas.unlock();
  56. }

Felt like revisiting implicit surface plotting today...

Have a look at the swf over at wonderfl.net

Also posted in BitmapData, Math | Tagged , , | Leave a comment

Parallax fp10

Actionscript:
  1. [SWF(backgroundColor=0x000000, width = 800, height = 600)]
  2.  
  3. // this is a trick to keep the 3D texture quality up...
  4. // try setting it right off the bat and you'll notice that the
  5. // Shapes look pixilated
  6. setTimeout(function():void{ stage.quality="low"}, 500);
  7.  
  8. var matrix:Matrix = new Matrix();
  9. matrix.createGradientBox(600, 600, 0, -450, -450);
  10.  
  11. var boxNum:int = 30;
  12. var boxes:Array = [];
  13. for (var i:int = 0; i<boxNum; i++) boxes[i] = makeBox();
  14.  
  15. var dx:Number = 0, dy:Number = 0;
  16. onLoop();
  17. addEventListener(Event.ENTER_FRAME, onLoop);
  18.  
  19. function onLoop(evt:Event=null):void {
  20.     dx += (mouseX - dx) / 4;
  21.     dy += (mouseY - dy) / 4;
  22.     for (var i:int = 0; i<boxNum; i++){
  23.         var box:Shape = boxes[i];
  24.         box.z = 400 - i * 20;
  25.         box.x = dx;
  26.         box.y = dy;
  27.         box.rotation = i + getTimer() / 10;
  28.     }
  29. }
  30.  
  31. function makeBox():Shape{
  32.     var box:Shape = Shape(addChild(new Shape()));
  33.     box.x = stage.stageWidth/2;
  34.     box.y = stage.stageHeight/2;
  35.     box.z = 1;
  36.     with (box.graphics){
  37.          beginGradientFill(GradientType.RADIAL, [0xFFFFFF, 0x333333], [1,1], [0, 255], matrix, SpreadMethod.PAD);
  38.         drawRect(-100, -100, 200, 200);
  39.         drawRect(-70, -70, 140, 140);
  40.     }
  41.     return box;
  42. }

This snippet draws 30 gradient box shapes, gives them different z values and then moves them based on the mouse. This technique is good if you just want a few layers of parallax motion - I got carried away and you'll notice that if you add more boxes it begins to slow down pretty quick.


Have a look at the swf....



I first used this technique for this small interactive drawing...

Something interesting I noticed about fp10 3D DisplayObjects is that if you set the stage.quality to low right off the bat, the display objects look pixelated... but if you wait a few milliseconds, you end up with less pixelation and you still get a speed boost from the low quality - I think it must have something to do with the way the 3D textures are handled by the player...

Tomorrow I think I'll post a version of this that uses IGraphicsData and Utils.projectVectors()... should be a huge speed boost...

Also posted in motion | Tagged , , | 1 Comment

Spring PerspectiveProjection

Actionscript:
  1. var pointNum:int = 3000;
  2. x = stage.stageWidth / 2;
  3. y = stage.stageHeight / 2;
  4.  
  5. var verts:Vector.<Number>  = new Vector.<Number>();
  6. var tVerts:Vector.<Number> = new Vector.<Number>();
  7. var pVerts:Vector.<Number> = new Vector.<Number>();
  8. var uv:Vector.<Number> = new Vector.<Number>();
  9. var cmds:Vector.<int> = new Vector.<int>();
  10.  
  11. var index:int = 0;
  12. var half:Number = pointNum / 20000;
  13. for (var i:int = 0; i<pointNum; i+=3){
  14.     verts[i] = 0.08 * Math.cos(i * Math.PI / 180);
  15.     verts[i+1] = 0.08 * Math.sin(i * Math.PI / 180);
  16.     verts[i+2] =  i / 10000 - half;
  17.     cmds[index++] = 2;
  18. }
  19. cmds[0] = 1;
  20.  
  21. var proj:PerspectiveProjection = new PerspectiveProjection();
  22. proj.fieldOfView = 45;
  23. var projMat:Matrix3D = proj.toMatrix3D();
  24. var m:Matrix3D = new Matrix3D();
  25. var dx:Number = 0, dy:Number = 0;
  26. addEventListener(Event.ENTER_FRAME, onLoop);
  27. function onLoop(evt:Event):void {
  28.        m.identity();
  29.        dx += (mouseX - dx) / 4;
  30.        dy += (mouseY - dy) / 4;
  31.        m.appendRotation(dy,Vector3D.X_AXIS);
  32.        m.appendRotation(dx,Vector3D.Y_AXIS);
  33.        m.appendTranslation(0,0,0.5);
  34.        m.transformVectors(verts, tVerts);
  35.        Utils3D.projectVectors(projMat, tVerts, pVerts, uv);
  36.        graphics.clear();
  37.        graphics.lineStyle(3,0x000000);
  38.        graphics.drawPath(cmds, pVerts);
  39. }

This snippet draws a spring shape in 3D with perspective. This is the first snippet where I've made use of the PerspectiveProjection class. So if your wondering how to add perspective to your Utils3D.projectVectors code... this is one way to do it...


Have a look at the swf...

Also posted in Graphics, Video, matrix | Tagged , , | 1 Comment