Want to cut some of that overhead incurred while rendering a scene? Why use full-screen anti-aliasing when you don't have to? This shortcut from Philip Rideout's iPhone 3D Programming will show you how to render anti-alias lines with textures.
Sometimes full-screen anti-aliasing is more than you really need and can cause too much of a performance hit. You may find that you need anti-aliasing only on your line primitives rather than the entire scene. Normally this would be achieved in OpenGL ES like so:
glEnable(GL_LINE_SMOOTH);
Alas, none of the iPhone models supports this at the time of this writing. However, the simulator does support line smoothing; watch out for inconsistencies like this!
A clever trick to work around this limitation is filling an alpha texture with a circle and then tessellating the lines into short triangle strips (Figure 6.9). Texture coordinates are chosen such that the circle is stretched in the right places. That has the added benefit of allowing round end-cap styles and wide lines.
Using a 16×16 circle for the texture works well for thick lines (see the left circle in Figure 6.9 and left panel in Figure 6.10). For thinner lines, I find that a highly blurred 16x16 texture produces good results (see the right circle in Figure 6.9 and right panel in Figure 6.10).
Let’s walk through the process of converting a line list into a textured triangle list. Each source vertex needs to be extruded into four new vertices. It helps to give each extrusion vector a name using cardinal directions, as shown in Figure 6.11, “Line extrusion”.
Before going over the extrusion algorithm,
let’s set up an example scenario. Say we’re rendering an animated stick
figure similar to Figure 6.10. Note that some vertices
are shared by multiple lines, so it makes sense to use an index buffer.
Suppose the application can render the stick figure using either line
primitives or textured triangles. Let’s define a
StickFigure structure that stores the vertex and index
data for either the non-AA variant or the AA variant; see Example 6.17. The non-AA variant doesn’t need
texture coordinates, but we’re including them for simplicity’s
sake.
The function prototype for the extrusion
method needs three arguments: the source StickFigure
(lines), the destination StickFigure (triangles), and
the desired line width. See Example 6.18 and refer
back to Figure 6.11 to visualize the six
extrusion vectors (N, S, NE, NW, SW, SE).
Example 6.18. Line extrusion algorithm
void ExtrudeLines(const StickFigure& lines, StickFigure& triangles, float width)
{
IndexList::iterator sourceIndex = lines.Indices.begin();
VertexList::iterator destVertex = triangles.Vertices.begin();
while (sourceIndex != lines.Indices.end()) {
vec3 a = lines.Vertices[lines.Indices[*sourceIndex++]].Position;
vec3 b = lines.Vertices[lines.Indices[*sourceIndex++]].Position;
vec3 e = (b - a).Normalized() * width;
vec3 N = vec3(-e.y, e.x, 0);
vec3 S = -N;
vec3 NE = N + e;
vec3 NW = N - e;
vec3 SW = -NE;
vec3 SE = -NW;
destVertex++->Position = a + SW;
destVertex++->Position = a + NW;
destVertex++->Position = a + S;
destVertex++->Position = a + N;
destVertex++->Position = b + S;
destVertex++->Position = b + N;
destVertex++->Position = b + SE;
destVertex++->Position = b + NE;
}
}
At this point, we’ve computed the positions of the extruded triangles, but we still haven’t provided texture coordinates for the triangles, nor the contents of the index buffer. Note that the animated figure can change its vertex positions at every frame, but the number of lines stays the same. This means we can generate the index list only once; there’s no need to recompute it at every frame. The same goes for the texture coordinates. Let’s declare a couple functions for these start-of-day tasks:
void GenerateTriangleIndices(size_t lineCount, IndexList& triangles); void GenerateTriangleTexCoords(size_t lineCount, VertexList& triangles);
Flip back to Figure 6.9, and note the number of triangles and vertices.
Every line primitive extrudes into six triangles composed from eight
vertices. Since every triangle requires three indices, the number of
indices in the new index buffer is lineCount*18. This
is different from the number of vertices, which is
only lineCount*8.
Example 6.19. Line extrusion initialization methods
void GenerateTriangleIndices(size_t lineCount, IndexList& triangles)
{
triangles.resize(lineCount * 18);
IndexList::iterator index = triangles.begin();
for (GLushort v = 0; index != triangles.end(); v += 8) {
*index++ = 0 + v; *index++ = 1 + v; *index++ = 2 + v;
*index++ = 2 + v; *index++ = 1 + v; *index++ = 3 + v;
*index++ = 2 + v; *index++ = 3 + v; *index++ = 4 + v;
*index++ = 4 + v; *index++ = 3 + v; *index++ = 5 + v;
*index++ = 4 + v; *index++ = 5 + v; *index++ = 6 + v;
*index++ = 6 + v; *index++ = 5 + v; *index++ = 7 + v;
}
}
void GenerateTriangleTexCoords(size_t lineCount, VertexList& triangles)
{
triangles.resize(lineCount * 8);
VertexList::iterator vertex = triangles.begin();
while (vertex != triangles.end()) {
vertex++->TexCoord = vec2(0, 0);
vertex++->TexCoord = vec2(0, 1);
vertex++->TexCoord = vec2(0.5, 0);
vertex++->TexCoord = vec2(0.5, 1);
vertex++->TexCoord = vec2(0.5, 0);
vertex++->TexCoord = vec2(0.5, 1);
vertex++->TexCoord = vec2(1, 0);
vertex++->TexCoord = vec2(1, 1);
}
}
Et voilà…you now know how to render antialiased lines on a device that doesn’t support antialiased lines! To see this in action, check out the AaLines sample from this book’s example code.
Learn more about this topic from iPhone 3D Programming.
Do you have a great idea for a graphics-intensive iPhone or iPad application, but don't know how to bring it to life? This book offers the perfect solution: a crash course on the OpenGL graphics library with an overview of iPhone 3D development. Whether you're an experienced OpenGL developer looking to build iPhone apps for the first time, or an iPhone developer wanting to learn sophisticated graphics, iPhone 3D Programming addresses both in one concise, easy-to-use guide.

Help







