# Lesson 170. OpenGL. graphic primitives

In this lesson:

– we draw graphic primitives

The original lessons are available on githab. Download the project, we will use the lesson170_primitives module in it.

In the last lesson, we learned how to transmit vertex data to shaders and obtain a triangle. To make this mechanism clearer, let’s try to develop a theme, and let’s create some examples of passing vertices and constructing different graphical primitives (point, line, and triangle) from these vertices.

### triangle

Right now, our app draws one triangle. If we look at the OpenGLRenderer class, in the prepareData method we will see in it a list of vertices:

float[] vertices = { -0.5f, -0.2f, 0.0f, 0.2f, 0.5f, -0.2f, };

Each pair of values is the coordinates (x, y) of one vertex. Three pairs = three vertices = triangle.

Next, in the onDrawFrame method, we use the glDrawArrays method to draw a triangle.

@Override public void onDrawFrame(GL10 arg0) { glClear(GL_COLOR_BUFFER_BIT); glDrawArrays(GL_TRIANGLES, 0, 3); }

GL_TRIANGLES is the type of primitive to draw, a triangle in our case

0 – vertices must be taken from the array starting from position 0, ie from the first

3 – means that you need to use three vertices for drawing

run the program

Now let’s try to draw 4 triangles. For this we need more vertices. 4 triangles, each with three vertices, so we need 3 * 4 = 12 vertices.

Rewrite the vertices array in the prepareData method

float[] vertices = { // треугольник 1 -0.9f, 0.8f, -0.9f, 0.2f, -0.5f, 0.8f, // треугольник 2 -0.6f, 0.2f, -0.2f, 0.2f, -0.2f, 0.8f, // треугольник 3 0.1f, 0.8f, 0.1f, 0.2f, 0.5f, 0.8f, // треугольник 4 0.1f, 0.2f, 0.5f, 0.2f, 0.5f, 0.8f, };

We now have 12 vertices of which we can construct 4 triangles.

run

But we only see one triangle instead of 4. We forgot to tell the system that we had to draw triangles using 12 vertices. That is, in the glDrawArrays method, we are still passing the value 3, which means that the system will take a value from the array to draw only three vertices.

rewrite onDrawFrame

@Override public void onDrawFrame(GL10 arg0) { glClear(GL_COLOR_BUFFER_BIT); glDrawArrays(GL_TRIANGLES, 0, 12); }

In glDrawArrays, we specify 12 instead of 3. Now the system will know that it needs to use data from the array to form 12 vertices to draw triangles, and we will get 4 triangles.

run

We see two triangles and a rectangle. This rectangle is actually composed of two triangles that are close to each other.

Look at the vertex array and note that triangles 3 and 4 have common vertices (0.1f, 0.2f) and (0.5f, 0.8f). Here, on this side, they united, forming a rectangle.

We ended up with 4 triangles, two of which look like one rectangle.

### types of triangles

To draw a triangle, we pass type GL_TRIANGLES to the glDrawArrays method. There are two other types of triangles: GL_TRIANGLE_STRIP and GL_TRIANGLE_FAN.

What is the difference between them? see the picture

**GL_TRIANGLES** – every three transmitted vertices form a triangle. That is

v0, v1, v2 is the first triangle

v3, v4, v5 is the second triangle

**GL_TRIANGLE_STRIP** – each subsequent triangle uses the last two vertices of the previous one

v0, v1, v2 is the first triangle

v1, v2, v3 is the second triangle

v2, v3, v4 is the third triangle

v3, v4, v5 is the fourth triangle

**GL_TRIANGLE_FAN** – each subsequent triangle uses the last vertex of the previous and the first vertex

v0, v1, v2 is the first triangle

v0, v2, v3 is the second triangle

v0, v3, v4 is the third triangle

Consider these types in the examples

Set 6 vertices in prepareData:

float[] vertices = { 0.1f, 0.8f, 0.1f, 0.2f, 0.5f, 0.8f, 0.1f, 0.2f, 0.5f, 0.2f, 0.5f, 0.8f, };

type GL_TRIANGLES and 6 vertices in glDrawArrays:

glDrawArrays(GL_TRIANGLES, 0, 6);

run

We get a rectangle composed of two triangles.

Now we draw the same rectangle, but a little differently

We set 4 vertices

float[] vertices = { 0.1f, 0.8f, 0.1f, 0.2f, 0.5f, 0.8f, 0.5f, 0.2f, };

type GL_TRIANGLE_STRIP and 4 vertices

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

If you have a development environment swearing at constant GL_TRIANGLE_STRIP, then import it at the beginning of the class:

import static android.opengl.GLES20.GL_TRIANGLE_STRIP;

And for all the following constants, do the same.

run

The result is the same, but this time we used 4 vertices rather than 6. The triangle type GL_TRIANGLE_STRIP helped save a little. In this example, this is usually not particularly critical, but overall, the fewer vertices we have to transmit, the higher the speed of the program.

Consider the latter type. We set 8 vertices

float[] vertices = { 0.0f, 0.0f, -0.4f, 0.4f, 0.4f, 0.4f, 0.8f, 0.0f, 0.4f, -0.4f, -0.4f, -0.4f, -0.8f, 0.0f, -0.4f, 0.4f, };

type GL_TRIANGLE_FAN and 8 vertices

glDrawArrays(GL_TRIANGLE_FAN, 0, 8);

run

Got a hexagon. To do this, we specified the center vertex and vertices, and in GL_TRIANGLE_FAN mode, the system drew a hexagon.

### line

Go to the line. To draw a line we need to specify two vertices.

We set them in an array:

float[] vertices = { -0.9f, -0.9f, 0.9f, 0.9f, };

And rewrite onDrawFrame:

@Override public void onDrawFrame(GL10 arg0) { glClear(GL_COLOR_BUFFER_BIT); glDrawArrays(GL_LINES, 0, 2); }

We use the GL_LINES constant and specify that we need to use two vertices.

run

One line is clear, let’s try to draw three lines.

we indicate the vertices

float[] vertices = { // линия 1 -0.9f, -0.9f, 0.9f, 0.9f, // линия 2 -0.5f, 0.0f, 0.5f, 0.0f, // линия 3 0.0f, 0.7f, 0.0f, -0.7f, };

Remember to specify in glDrawArrays that you need to use 6 vertices, and set the line thickness = 5.

@Override public void onDrawFrame(GL10 arg0) { glClear(GL_COLOR_BUFFER_BIT); glLineWidth(5); glDrawArrays(GL_LINES, 0, 6); }

run

Three lines are drawn

### types of lines

There are three types of line reproduction. Let’s look at them in the examples.

Type **GL_LINES** we have already used it, it just takes pairs of vertices and draws lines between them. That is, if we have vertices (v0, v1, v2, v3, v4, v5), then we get three lines (v0, v1), (v2, v3) and (v4, v5).

we set the vertices

float[] vertices = { -0.4f, 0.6f, 0.4f, 0.6f, 0.6f, 0.4f, 0.6f, -0.4f, 0.4f, -0.6f, -0.4f, -0.6f, };

Specify the type GL_LINES, 6 vertices

glDrawArrays(GL_LINES, 0, 6);

run

Each pair of vertices formed a line.

Type **GL_LINE_STRIP** draws lines not in pairs, but sequentially between all vertices. That is, if we have vertices (v0, v1, v2, v3, v4, v5), then we get five lines (v0, v1), (v1, v2), (v2, v3), (v3, v4) and (v4, v5).

We will use the same vertices and change the type to GL_LINE_STRIP

glDrawArrays(GL_LINE_STRIP, 0, 6);

run

The lines are drawn in sequence between all the vertices

Type **GL_LINE_LOOP** similar to GL_LINE_STRIP, except that it also draws a line between the first and last point.

Change type to GL_LINE_LOOP

glDrawArrays(GL_LINE_LOOP, 0, 6);

run

The result is the same as GL_LINE_STRIP, plus is the line between the first and last vertices.

### Point, point

It remains to consider the point. There are no longer any different types here, just GL_POINTS.

Note it in glDrawArrays:

@Override public void onDrawFrame(GL10 arg0) { glClear(GL_COLOR_BUFFER_BIT); glDrawArrays(GL_POINTS, 0, 6); }

The vertices will remain the same.

The point thickness can be specified in vertex shaders using the gl_PointSize variable.

**vertex_shader.glsl**

attribute vec4 a_Position; void main() { gl_Position = a_Position; gl_PointSize = 5.0; }

run

6 points are drawn

And finally, let’s draw several different primitives at once, for example: 4 triangles, 2 lines, 3 points

4 triangles are 4 * 3 = 12 vertices

2 lines are 2 * 2 = 4 vertices

3 points are 3 vertices

Together we need to set 12+ 4 + 3 = 19 vertices

float[] vertices = { // треугольник 1 -0.9f, 0.8f, -0.9f, 0.2f, -0.5f, 0.8f, // треугольник 2 -0.6f, 0.2f, -0.2f, 0.2f, -0.2f, 0.8f, // треугольник 3 0.1f, 0.8f, 0.1f, 0.2f, 0.5f, 0.8f, // треугольник 4 0.1f, 0.2f, 0.5f, 0.2f, 0.5f, 0.8f, // линия 1 -0.7f, -0.1f, 0.7f, -0.1f, // линия 2 -0.6f, -0.2f, 0.6f, -0.2f, // точка 1 -0.5f, -0.3f, // точка 2 0.0f, -0.3f, // точка 3 0.5f, -0.3f, };

rewrite onDrawFrame

@Override public void onDrawFrame(GL10 arg0) { glClear(GL_COLOR_BUFFER_BIT); glLineWidth(5); glDrawArrays(GL_TRIANGLES, 0, 12); glDrawArrays(GL_LINES, 12, 4); glDrawArrays(GL_POINTS, 16, 3); }

We call the glDrawArrays method three times.

The first call tells the system that you need to draw triangles and use 12 vertices, starting with the first one in the array (index 0).

The second call tells the system to draw lines and use 4 vertices, starting with the thirteenth in the array (index 12). We start from the thirteenth because we used the first 12 vertices in the array to set the triangles, and the vertices of the lines go from the thirteenth.

The third call tells the system that you need to draw points and use 3 vertices, starting with the seventeenth in the array (index 16). We start with the seventeenth because we used the first 12 vertices in the array to set the triangles, the next 4 vertices we used to set the lines, and the vertices of the dots go from the seventeenth.

run

The system drew 4 triangles (2 of them form a rectangle), 2 lines and three points.

Hopefully the relationship between the vertex array and the glDrawArrays method has become clearer. That is, in glDrawArrays we specify which figures to draw and how many vertices to use, and the vertices data is taken from the array of vertices. It may be unclear, for example, how the system determines that it takes exactly 2 vertices for the vertex. We will look into this in detail in the next lesson and the algorithm for transferring data to shaders will become fully understood.