Utility Function: indexedTrisToString
This week’s article offers another useful utility function: indexedTrisToString
. This function is especially useful when dealing with 3D engines such as those based on Context3D.drawTriangles
or Graphics.drawTriangles
. It helps to untangle the complicated indices/vertices format that these API functions require into something much more readable and, therefore, debuggable.
Both the software-based Graphics.drawTriangles
and the hardware-based Context3D.drawTriangles
require you to specify two sets of data: vertex data (X, Y, Z) and sets of three indices into those vertices forming a triangle. For example:
var tris:Vector.<uint> = new <uint>[ 0, 1, 2, 2, 1, 0 ]; var vertices:Vector.<Number> = new <Number>[ 11, 12, 13, 21, 22, 23, 31, 32, 33 ];
The tris
specify two triangles ([0,1,2] and [2,1,0]) in the vertices
. Each index I
actually resolves to the vertex with components [I*3
, I*3+1
, I*3+2
]. To make matters worse, Stage3D
often packs more vertex data in with X, Y, and Z to specify things like normal vectors and texture coordinates. At this point it’s very difficult to interpret the data in its raw form:
trace(tris); trace(vertices); // output: 0,1,2,2,1,0 11,12,13,21,22,23,31,32,33
That’s not very helpful. Enter today’s utility function-indexedTrisToString
:
trace(indexedTrisToString(tris, vertices, "\n")); // output: V0: (X: 11, Y: 12, Z: 13) V1: (X: 21, Y: 22, Z: 23) V2: (X: 31, Y: 32, Z: 33) V0: (X: 31, Y: 32, Z: 33) V1: (X: 21, Y: 22, Z: 23) V2: (X: 11, Y: 12, Z: 13)
Now that’s a lot more useful! So what if we had extra data after the X, Y, and Z components:
var verticesExtraRight:Vector.<Number> = new <Number>[ 11, 12, 13, 14, 21, 22, 23, 15, 31, 32, 33, 16 ]; trace(indexedTrisToString(tris, verticesExtraRight, "\n", 4));
All we had to do was specify that there were four elements per vertex and the function took care of it. How about data before that X, Y, and Z components?
var verticesExtraLeft:Vector.<Number> = new <Number>[ 10, 11, 12, 13, 20, 21, 22, 23, 30, 31, 32, 33 ]; trace(indexedTrisToString(tris, verticesExtraLeft, "\n", 4, 1, 2, 3));
Here we had to specify that there were four elements per vertex and also the indices of the X, Y, and Z components. Now it’s easy to handle data on the left and and right of the X, Y, and Z components:
var verticesExtraLeftRight:Vector.<Number> = new <Number>[ 10, 11, 12, 13, 14, 20, 21, 22, 23, 15, 30, 31, 32, 33, 16 ]; trace(indexedTrisToString(tris, verticesExtraLeftRight, "\n", 5, 1, 2, 3));
The only modification is to tell indexedTrisToString that there are five components per vertex.
Here is the source code of today’s utility function:
/** * Get a string representation of indexed triangles * @param tris Indices of the triangles * @param vertices Vertex data (may contain more than just X, Y, and Z) * @param sep Separator between triangles * @param attributesPerVertex Number of attributes per vertex. For example, (XYZ) is 3 and * (XYZUV) is 5. * @param xIndex Index into the vertex attributes of the X component * @param yIndex Index into the vertex attributes of the Y component * @param zIndex Index into the vertex attributes of the Z component * @return A string representation of the given indexed triangles * @author Jackson Dunstan (http://JacksonDunstan.com) * @license MIT */ public static function indexedTrisToString( tris:Vector.<uint>, vertices:Vector.<Number>, sep:String, attributesPerVertex:uint=3, xIndex:uint=0, yIndex:uint=1, zIndex:uint=2 ): String { var ret:String = ""; for (var i:uint, triIndex:uint, len:uint = tris.length; i < len; i+=3, triIndex++) { if (triIndex) { ret += sep; } var baseVertexIndex:uint = tris[i]; ret += "V0: (X: " + vertices[baseVertexIndex*attributesPerVertex+xIndex] + ", Y: " + vertices[baseVertexIndex*attributesPerVertex+yIndex] + ", Z: " + vertices[baseVertexIndex*attributesPerVertex+zIndex] + ")" + sep; baseVertexIndex = tris[i+1]; ret += "V1: (X: " + vertices[baseVertexIndex*attributesPerVertex+xIndex] + ", Y: " + vertices[baseVertexIndex*attributesPerVertex+yIndex] + ", Z: " + vertices[baseVertexIndex*attributesPerVertex+zIndex] + ")" + sep; baseVertexIndex = tris[i+2]; ret += "V2: (X: " + vertices[baseVertexIndex*attributesPerVertex+xIndex] + ", Y: " + vertices[baseVertexIndex*attributesPerVertex+yIndex] + ", Z: " + vertices[baseVertexIndex*attributesPerVertex+zIndex] + ")" + sep; } return ret; }
I hope you find it useful in your 3D debugging! If you spot a bug in it or have a question, leave a comment below!