Saturday, March 01, 2008

XNA Line Thickness

I've been searching for a method to display a thick line in XNA. There isn't a method in XNA as OpenGL's glLineWidth. So you have to construct you own line from triangles. I've found and tried this method. The line were rounded at each edge, and the whole scene looked pretty impressive. The problem was that my application had to render thousands of lines, and doing rounded edges and indexed triangles wasn't very performant. I wanted something much more simple, without rounded edges, but considering line joints. I developed a really simple and performant method to do this. The idea was to take a line strip (the array of Vector3[]) and build a triangle strip, which is the most performant method for rendering, and store it in a vertex buffer. This method is almost as performant as drawing simple lines!
I think that the code is pretty self explaining:

triangleCount =-2;
private List<VertexPositionColor> GetTriangleStrip(Vector3[] points, float thickness)
{
Vector3 lastPoint = Vector3.Zero;
List<VertexPositionColor> list = new List&ltVertexPositionColor>();
for (int i=0;i<points.Length;i++)
{
if (i == 0) { lastPoint = points[i]; continue; }
//the direction of the current line
Vector3 direction = lastPoint - points[i];
direction.Normalize();
//the perpendiculat to the current line
Vector3 normal = Vector3.Cross(direction, Vector3.UnitZ);
normal.Normalize();
Vector3 p1 = lastPoint + normal * thickness; triangleCount++;
Vector3 p2 = lastPoint - normal * thickness; triangleCount++;
Vector3 p3 = points[i] + normal * thickness; triangleCount++;
Vector3 p4 = points[i] - normal * thickness; triangleCount++;
list.Add(new VertexPositionColor(p1, Color.Black));
list.Add(new VertexPositionColor(p2, Color.Black));
list.Add(new VertexPositionColor(p3, Color.Black));
list.Add(new VertexPositionColor(p4, Color.Black));
lastPoint = points[i];
}
return list;
}
Then you just have to store the list in a vertex buffer and render it as a triangle strip with "triangleCount" primirives.