GL_TRIANGLE_STRIP vs GL_TRIANGLE_FAN
Categories:
GL_TRIANGLE_STRIP vs. GL_TRIANGLE_FAN: Optimizing Your OpenGL Geometry
Explore the differences between GL_TRIANGLE_STRIP and GL_TRIANGLE_FAN in OpenGL, understand their use cases, and learn how to choose the right primitive for efficient rendering.
When rendering 3D graphics with OpenGL, understanding how to efficiently define and draw geometry is crucial for performance. OpenGL provides several primitive types for drawing triangles, the most fundamental building blocks of 3D models. Among these, GL_TRIANGLE_STRIP
and GL_TRIANGLE_FAN
are particularly useful for reducing vertex data redundancy and draw calls. This article will delve into the mechanics of these two primitives, compare their advantages and disadvantages, and guide you on when to use each.
Understanding GL_TRIANGLE_STRIP
GL_TRIANGLE_STRIP
is a primitive type that allows you to draw a series of connected triangles by specifying only a sequence of vertices. Each new vertex added after the first two creates another triangle, sharing two vertices with the previously drawn triangle. This method significantly reduces the amount of vertex data you need to send to the GPU, as many vertices are reused implicitly.
graph TD V1 --> T1 V2 --> T1 V3 --> T1 V2 --> T2 V3 --> T2 V4 --> T2 V3 --> T3 V4 --> T3 V5 --> T3 subgraph Vertices V1(Vertex 1) V2(Vertex 2) V3(Vertex 3) V4(Vertex 4) V5(Vertex 5) end subgraph Triangles T1("Triangle 1 (V1, V2, V3)") T2("Triangle 2 (V2, V4, V3)") T3("Triangle 3 (V3, V4, V5)") end style V1 fill:#f9f,stroke:#333,stroke-width:2px style V2 fill:#f9f,stroke:#333,stroke-width:2px style V3 fill:#f9f,stroke:#333,stroke-width:2px style V4 fill:#f9f,stroke:#333,stroke-width:2px style V5 fill:#f9f,stroke:#333,stroke-width:2px style T1 fill:#ccf,stroke:#333,stroke-width:2px style T2 fill:#ccf,stroke:#333,stroke-width:2px style T3 fill:#ccf,stroke:#333,stroke-width:2px
How GL_TRIANGLE_STRIP forms triangles from a sequence of vertices.
For a GL_TRIANGLE_STRIP
with N
vertices, N-2
triangles are rendered. The order of vertices is crucial: for the first triangle, vertices are V0, V1, V2
. For the second, it's V1, V3, V2
(note the swap to maintain consistent winding order). For the third, it's V2, V3, V4
, and so on. This alternating pattern ensures that all triangles have the same winding order (e.g., counter-clockwise) for proper back-face culling.
glBegin(GL_TRIANGLE_STRIP);
glVertex3f(0.0f, 0.0f, 0.0f); // V0
glVertex3f(0.0f, 1.0f, 0.0f); // V1
glVertex3f(1.0f, 0.0f, 0.0f); // V2 (Forms T1: V0, V1, V2)
glVertex3f(1.0f, 1.0f, 0.0f); // V3 (Forms T2: V1, V3, V2)
glVertex3f(2.0f, 0.0f, 0.0f); // V4 (Forms T3: V2, V3, V4)
glVertex3f(2.0f, 1.0f, 0.0f); // V5 (Forms T4: V3, V5, V4)
glEnd();
Example of drawing a GL_TRIANGLE_STRIP in immediate mode.
Understanding GL_TRIANGLE_FAN
GL_TRIANGLE_FAN
is another efficient primitive type, particularly useful for drawing polygons that share a common central vertex. In a triangle fan, the first vertex specified (V0
) acts as the central pivot. Each subsequent pair of vertices (Vn
, Vn+1
) forms a triangle with this central vertex (V0
). This is ideal for shapes like circles, pie charts, or any convex polygon that can be triangulated from a central point.
graph TD V0 --> T1 V1 --> T1 V2 --> T1 V0 --> T2 V2 --> T2 V3 --> T2 V0 --> T3 V3 --> T3 V4 --> T3 subgraph Vertices V0(Central Vertex) V1(Vertex 1) V2(Vertex 2) V3(Vertex 3) V4(Vertex 4) end subgraph Triangles T1("Triangle 1 (V0, V1, V2)") T2("Triangle 2 (V0, V2, V3)") T3("Triangle 3 (V0, V3, V4)") end style V0 fill:#f9f,stroke:#333,stroke-width:2px style V1 fill:#f9f,stroke:#333,stroke-width:2px style V2 fill:#f9f,stroke:#333,stroke-width:2px style V3 fill:#f9f,stroke:#333,stroke-width:2px style V4 fill:#f9f,stroke:#333,stroke-width:2px style T1 fill:#ccf,stroke:#333,stroke-width:2px style T2 fill:#ccf,stroke:#333,stroke-width:2px style T3 fill:#ccf,stroke:#333,stroke-width:2px
How GL_TRIANGLE_FAN forms triangles around a central vertex.
For a GL_TRIANGLE_FAN
with N
vertices, N-2
triangles are rendered. The first vertex V0
is the common vertex for all triangles. The first triangle is formed by V0, V1, V2
. The second by V0, V2, V3
, the third by V0, V3, V4
, and so on. This structure is very efficient for drawing shapes that emanate from a single point.
glBegin(GL_TRIANGLE_FAN);
glVertex3f(0.0f, 0.0f, 0.0f); // V0 (Central vertex)
glVertex3f(1.0f, 0.0f, 0.0f); // V1
glVertex3f(0.866f, 0.5f, 0.0f); // V2 (Forms T1: V0, V1, V2)
glVertex3f(0.5f, 0.866f, 0.0f); // V3 (Forms T2: V0, V2, V3)
glVertex3f(0.0f, 1.0f, 0.0f); // V4 (Forms T3: V0, V3, V4)
glEnd();
Example of drawing a GL_TRIANGLE_FAN to create a quarter circle.
Choosing Between GL_TRIANGLE_STRIP and GL_TRIANGLE_FAN
The choice between GL_TRIANGLE_STRIP
and GL_TRIANGLE_FAN
depends entirely on the geometry you are trying to render. Both are designed to reduce vertex data and draw calls compared to GL_TRIANGLES
, but they achieve this through different connectivity patterns.
GL_TRIANGLE_STRIP is ideal for rectangular or ribbon-like shapes, while GL_TRIANGLE_FAN excels at circular or radial shapes.
Here's a summary of their typical use cases:
GL_TRIANGLE_STRIP
: Best for rendering surfaces that can be laid out as a continuous ribbon of quadrilaterals or triangles. Common examples include:- Rectangular planes
- Sides of a cube or prism
- Cylinders (unrolled)
- Terrain patches
- Any surface where adjacent triangles share an edge.
GL_TRIANGLE_FAN
: Best for rendering shapes that have a single central point from which all triangles originate. Common examples include:- Circles and ellipses
- Bases of cones or pyramids
- The top/bottom caps of cylinders
- Any convex polygon.
GL_TRIANGLE_STRIP
and GL_TRIANGLE_FAN
are efficient, they can be less flexible than GL_TRIANGLES
for complex, arbitrary meshes. For highly irregular or disconnected geometry, GL_TRIANGLES
with an index buffer (Element Buffer Object) often provides the best balance of flexibility and performance.