
Basic shapes (primitives) - the main elements from which complex objects are drawn when drawing. In
OpenGL ES, these primitives are the objects Point (Point), Line (Line), Triangle (Triangle). I think their names speak for themselves.
In this lesson we will analyze the code, based on which you can later create your own projects.
Primitive №1 - triangles
Triangles are the most difficult of the basic shapes, but they are so convenient and useful that we will begin with them. To draw a triangle, you need to specify
OpenGL three coordinates of the three-dimensional space - the program will do the rest.
')
First of all, create a copy of the project from the lesson "
OpenGL ES: setting up a project in Xcode " or download the source code
from here . Open the project in
Xcode , go to the file "
EAGLView.m " and find the method "
drawView ". The real magic begins!
The first step is to set the parameters of the triangle. Immediately pay attention to the fact that we will work with the coordinates of two types:
Model and
World . The coordinates of the
Model refer to the primitive being drawn, and the coordinates of the
World inform
OpenGL of its location relative to the viewer (which in the
World space is always at the point (0.0, 0.0, 0.0)).
So, we set the coordinates of the triangle in
Model space through three three-dimensional coordinates (X, Y, Z):
const GLfloat triangleVertices[] = {
0.0, 1.0, -6.0,//
-1.0, -1.0, -6.0,//
1.0, -1.0, -6.0,//
};
Note that the coordinates are described sequentially, in the counterclockwise direction (it can be the opposite - the main thing is to set them sequentially and stick to the unified scheme). To begin with, I would recommend working in a counterclockwise pattern, since this is the order required for some of the functions discussed below.
Although our lesson is about
iPhone technology
OpenGL ES , for beginners, I will briefly focus on the three-dimensional coordinate system. Take a look at the picture:

Let us distract from my artistic abilities and see how the
Model (or
World ) space looks like. Imagine that this is a computer monitor, where X and Y are, respectively, the horizontal and vertical axes, and Z is the depth. The center point corresponds to the coordinates (0.0, 0.0, 0.0).
If we now consider the triangle as applied to these axes, then the first point (0.0, 1.0, -6.0) will be its center on the Y axis, shifted up by one point and six points deep into the screen. The second coordinate is one point to the right of the Y axis, below the X axis (since the Y value is -1.0) and six points in depth of the screen (-6.0). Exactly by the same principle, the third coordinate is analyzed.
Z value is made negative to move the object back and make it visible (do not forget that the “camera” is at (0.0, 0.0, 0.0), so otherwise the object will not pass the
OpenGL test to depth and will not be visualized).
Some people will immediately notice: “So it was said that we work with the coordinates of
Model , not
World !” This is true, but when we get to visualize the triangle,
OpenGL will immediately place the object at the point (0.0, 0.0, 0.0). Therefore, we are already shifting it to the depth of the screen, making it visible. Later, considering transformations (displacement, rotation, etc.), such a result can be achieved without resorting to negative values. Until then, we will leave the value -6.0 for the Z coordinate.
Drawing code
Now we are ready to describe the triangle, telling
OpenGL where the data is stored and how to draw the primitive. For this we need a few lines of code. Return to the "
drawView " method and implement it as shown below:
- (void)drawView {
const GLfloat triangleVertices[] = {
0.0, 1.0, -6.0, //
-1.0, -1.0, -6.0, //
1.0, -1.0, -6.0 //
};
[EAGLContext setCurrentContext:context];
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glViewport(0, 0, backingWidth, backingHeight);
// --
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glVertexPointer(3, GL_FLOAT, 0, triangleVertices);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_TRIANGLES, 0, 3);
// --
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
[self checkGLError:NO];
}
As you can see, four lines of code are enough to render the triangle. Let us examine each of them to make sure that everything is very simple.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
This line clears the screen. The control bits tell
OpenGL to use the black color specified in the last lesson in the "
setupView " method and clear the depth buffer. If the buffer is connected without doing this, the scene will not be rendered. If the buffer is not connected, the
GL_DEPTH_BUFFER_BIT message is
not necessary in the transfer of
glClear () .
So, we have cleared everything that was previously drawn in the buffer (Did not forget about double buffering? In one buffer we draw, we display the other).
glVertexPointer(3, GL_FLOAT, 0, triangleVertices);
The function informs
OpenGL about the location of the data and its format. It has four parameters that are as simple as possible:
1. Size: the number of values in each coordinate. In our case, there are three (X, Y, Z). When drawing two-dimensional objects without depth (i.e., Z values), the number 2 will be indicated.
2. Data type:
GL_FLOAT stands for floating point value. If desired, integer numbers are allowed, but in three-dimensional spaces floating points are indispensable.
3. The size of the computation step: tells
OpenGL to ignore a certain number of bytes between the coordinates. Let this parameter not care yet - leave it equal to zero. You will work with it when loading data on vertices from a file, the format of which provides filling information or color data, such as from a Blender 3D application.
4. Data pointer - actually, the data itself.
So, we suggested
OpenGL to clear the buffer, specified the data for the object and reported its format. The time has come for an extremely important message.
glEnableClientState(GL_VERTEX_ARRAY);
OpenGL works with states. This means that the functions are activated and disabled by the appropriate commands. Above, we applied the "
glEnable () " command, working with the "server" mode of
OpenGL . The "
glEnableClientState () " command turns on the "program" mode (i.e. client state). At the moment we have informed OpenGL that the data on the vertices are in a separate array and activated the
OpenGL function to draw the vertex. Theoretically, a vertex can be an array of color (in this case, it’s worth
referring to "
glEnableClientState (GL_COLOR_ARRAY )") or an array of texture coordinates when applying textures (enough sighing!
As we master
OpenGL, we will have to work with different client states, so there will still be time to analyze this topic.
It’s time for the team to visualize the triangle:
glDrawArrays(GL_TRIANGLES, 0, 3);
When calling this function,
OpenGL processes the information obtained from the two previous functions. A triangle with a white fill will appear on the screen (white is the default color when drawing). Triangles are filled objects. To draw an empty triangle, you will need a different technique.
Parse the three arguments of this function:
1. Drawing method: in this case "
GL_TRIANGLES ", whose name itself is quite eloquent. The opportunity to evaluate the potential of the first argument will be presented to us later, when using this function we will draw a square.
2. First vertex: our array consists of only three points. We want
OpenGL to push off from the first point in the array, specified as zero (standard array access). If the array of vertices contained several primitives, it would be appropriate to offset. More on this - in the subsequent lessons, where it will be about creating complex objects. For now let it be zero.
3. Number of vertices: tells
OpenGL how many vertices to draw in the array. For a triangle there are, of course, three, for a square - 4, for a line - 3 (and more), for a point - one (and more when rendering multiple points).
After the code is typed, and the "
drawView " method is brought to the above form, use the "
Build and Go " button to start the project in the simulator. The result will look something like what was supposed to be - a white triangle in the center of the screen.

Before proceeding to the next primitive, try changing the Z value, and you will see that if the value is 0.0, visualization is not performed.
For a few lines of code clarification turned out a lot, but I think it was worth it. I hope that those who already had to stumble over "typical" lessons on
OpenGL , have already understood the difference between
OpenGL and
OpenGL ES .
The source code for the lesson can be downloaded
here .