OpenGL ES 3.0 Primitive Drawing API Overview
OpenGL ES 3.0 offers five primary API functions for rendering geometric primitives. While glDrawElements and its variations are common for indexed rendering, glDrawArrays serves as the fundamental method for rendering non-indexed geometry directly from vertex buffer data.
The glDrawArrays Function
This command constructs sequences of geometric primitives using data currently bound to the vertex arrays. It supports various rendering modes, including points, lines, and triangles, allowing developers to define how vertices are interpreted.
Triangle Primitive Modes
When rendering triangles, the mode parameter dictates how the vertex data is assembled. The three most distinct modes are GL_TRIANGLES, GL_TRIANGLE_STRIP, and GL_TRIANGLE_FAN.
- GL_TRIANGLES: Each group of three vertices defines a single, independent triangle. For a vertex count of n, this mode generates n/3 triangles.
- GL_TRIANGLE_STRIP: Creates a connected chain of triangles. Starting from the third vertex, each new vertex forms a triangle with the previous two. For n vertices, it yields n-2 triangles. Note that the winding order typically alternates to maintain consistent surface normals.
- GL_TRIANGLE_FAN: Defines a series of triangles sharing a common pivot point (the first vertex). Subsequent vertices form triangles with the pivot and the preceding vertex, also resulting in n-2 triangles.
Code Implementation Examples
The following examples demonstrate how to render a quadrilateral using the different assembly modes. The code assumes a standard EGL context has been initialized.
1. Using GL_TRIANGLES
Since GL_TRIANGLES does not share vertices between adjacent faces, we must explicitly define six vertices to form two triangles composing a rectangle.
GLfloat rectVertices[] = {
// x y z
-0.5f, 0.5f, 0.0f, // Top-Left (v0)
-0.5f, -0.5f, 0.0f, // Bottom-Left (v1)
0.5f, -0.5f, 0.0f, // Bottom-Right (v2)
-0.5f, 0.5f, 0.0f, // Top-Left (v0) - Repeat
0.5f, -0.5f, 0.0f, // Bottom-Right (v2) - Repeat
0.5f, 0.5f, 0.0f // Top-Right (v3)
};
// Set the viewport and clear the screen
glViewport(0, 0, kScreenWidth, kScreenHeight);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Enable and specify the vertex attribute array
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, rectVertices);
// Issue the draw call
glDrawArrays(GL_TRIANGLES, 0, 6);
2. Using GL_TRIANGLE_STRIP
This mode optimizes memory usage by reusing vertices. Only four vertices are needed to construct the same rectangle.
GLfloat stripVertices[] = {
// x y z
-0.5f, 0.5f, 0.0f, // v0
-0.5f, -0.5f, 0.0f, // v1
0.5f, 0.5f, 0.0f, // v2
0.5f, -0.5f, 0.0f // v3
};
glViewport(0, 0, kScreenWidth, kScreenHeight);
glClear(GL_COLOR_BUFFER_BIT);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, stripVertices);
// 4 vertices yield 2 triangles
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3. Using GL_TRIANGLE_FAN
To render the rectangle as a fan, we select one corner as the origin (v0) and traverse the perimeter.
GLfloat fanVertices[] = {
// x y z
-0.5f, 0.5f, 0.0f, // Center/Origin (v0)
-0.5f, -0.5f, 0.0f, // v1
0.5f, -0.5f, 0.0f, // v2
0.5f, 0.5f, 0.0f // v3
};
glViewport(0, 0, kScreenWidth, kScreenHeight);
glClear(GL_COLOR_BUFFER_BIT);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, fanVertices);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);