# Category Archives: matrix

## 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();
60.     beginGradientFill(GradientType.LINEAR, [0x000000, 0xAA0000, 0xFFFF00], [1, 1, 1], [20, 200, 255], mat);
61.     drawRect(0,0,400,400);
62. }
64.
65. // create background
69.     drawRect(0,0,500,500);
70. }
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;
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 3D, Graphics, Vector, misc | | 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.
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 3D, Graphics, Vector | | 3 Comments

## 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;
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 3D, Graphics, Video | Tagged , , | 1 Comment

## Quick Pixel Sphere

Actionscript:
1. var pointNum:int = 20000;
3.
4. var canvas:BitmapData = new BitmapData(400,400,false, 0x000000);
6. var verts:Vector.<Number>  = new Vector.<Number>();
7. var pVerts:Vector.<Number> = new Vector.<Number>();
8. var uv:Vector.<Number> = new Vector.<Number>();
9.
10. for (var i:int = 0; i<pointNum; i+=3){
11.     var xp:Number = Math.random() * 400 - 200;
12.     var yp:Number = Math.random() * 400 - 200;
13.     var zp:Number = Math.random() * 400 - 200;
14.     var dist:Number = Math.sqrt(xp * xp + yp * yp + zp * zp);
15.     // normalize and scale x,y,z
16.     verts[i] = xp / dist * radius;
17.     verts[i+1] = yp / dist * radius;
18.     verts[i+2] = zp / dist * radius;
19. }
20.
21. var m:Matrix3D = new Matrix3D();
22. var dx:Number = 0, dy:Number = 0;
24. function onLoop(evt:Event):void {
25.        m.identity();
26.        dx += (mouseX - dx) / 4;
27.        dy += (mouseY - dy) / 4;
28.        m.appendRotation(dx, Vector3D.X_AXIS);
29.        m.appendRotation(dy, Vector3D.Y_AXIS);
30.        m.appendTranslation(200,200,0);
31.        Utils3D.projectVectors(m, verts, pVerts, uv);
32.        canvas.fillRect(canvas.rect, 0x000000);
33.        for (var i:int = 0; i<pVerts.length; i+=2){
34.          canvas.setPixel(pVerts[i], pVerts[i + 1], 0xFFFFFF);
35.        }
36. }

This snippet shows a quick way to randomly place a bunch of xyz coordinates on the surface of a sphere. I saw this trick in an OpenGL book a few years back - dug around my books but couldn't find it... If I find it I'll update this post.

The trick is achieved by normalizing the vector defined by each 3D coordinate...

Have a look at the swf...

Also posted in 3D, BitmapData, Math, setPixel | Tagged , , | 4 Comments