Android - OpenGL ES 2 - Tutorial 2 - Draw a Triangle

Consider the triangle of the following image:

Continuing on the basic 2D project, create a new class "ObjTriangle" and replace the code with the following:
package opengles2.tutorial2;

import android.opengl.GLES20;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.opengles.GL10;

public class ObjTriangle {
    private FloatBuffer vertexBuffer;
    private ShortBuffer indexBuffer;

    private final int COORDS_PER_VERTEX = 2;
    private final int vertexStride = COORDS_PER_VERTEX * 4;
    private float[] vertices = {
            -0.5f, -0.5f,
            0.5f, -0.5f,
            0.0f, 0.5f,

    private short[] indices = {
            0, 1, 2

    // Color for all vertices (Red).
    private float[] color = {
            1.0f, 0.0f, 0.0f, 1.0f

    private final String vertexShaderCode =
            "uniform mat4 uMVPMatrix;" +
            "attribute vec4 vPosition;" +
            "void main() {" +
            "  gl_Position = uMVPMatrix * vPosition;" +

    private final String fragmentShaderCode =
            "precision mediump float;" +
            "uniform vec4 vColor;" +
            "void main() {" +
            "  gl_FragColor = vColor;" +

    private int mProgram;

    public ObjTriangle() {
        // Set vertex buffer from data.
        ByteBuffer vbb = ByteBuffer.allocateDirect(this.vertices.length * 4);
        this.vertexBuffer = vbb.asFloatBuffer();

        // Set index buffer from data.
        ByteBuffer ibb = ByteBuffer.allocateDirect(this.indices.length * 2);
        this.indexBuffer = ibb.asShortBuffer();
    public void SetProgramShader() {
        // Load shaders.
        int vertexShader = MainRenderer.LoadShader(GLES20.GL_VERTEX_SHADER, this.vertexShaderCode);
        int fragmentShader = MainRenderer.LoadShader(GLES20.GL_FRAGMENT_SHADER, this.fragmentShaderCode);

        // Create empty OpenGL ES Program.
        this.mProgram = GLES20.glCreateProgram();
        // Add the vertex shader to program.
        GLES20.glAttachShader(this.mProgram, vertexShader);
        // Add the fragment shader to program.
        GLES20.glAttachShader(this.mProgram, fragmentShader);
        // Creates OpenGL ES program executables.

    private int positionHandle;
    private int colorHandle;
    private int modelHandle;

    public void DrawTriangle(float[] modelMatrix) {
        // Add program to OpenGL ES environment.

        // Get handle to vertex shader's vPosition member.
        this.positionHandle = GLES20.glGetAttribLocation(this.mProgram, "vPosition");
        // Enable a handle to the triangle vertices.
        // Prepare the triangle coordinate data.
        GLES20.glVertexAttribPointer(this.positionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, this.vertexStride, this.vertexBuffer);

        // Get handle to fragment shader's vColor member.
        this.colorHandle = GLES20.glGetUniformLocation(this.mProgram, "vColor");
        // Set color for drawing the triangle.
        GLES20.glUniform4fv(this.colorHandle, 1, this.color, 0);

        // Get handle to shape's transformation matrix.
        this.modelHandle = GLES20.glGetUniformLocation(this.mProgram, "uMVPMatrix");
        // Pass the projection and view transformation to the shader.
        GLES20.glUniformMatrix4fv(this.modelHandle, 1, false, modelMatrix, 0);

        // Draw the triangle.
        GLES20.glDrawElements(GL10.GL_TRIANGLES, this.indices.length, GL10.GL_UNSIGNED_SHORT, this.indexBuffer);
        // Disable vertex array.

Now let's edit the "MainRenderer" class as follows:
package opengles2.tutorial2;

import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class MainRenderer implements GLSurfaceView.Renderer {
    int width, height;

    private final float[] projMatrix = new float[16];
    private final float[] viewMatrix = new float[16];
    // Projection and view transformation.
    private final float[] basicMatrix = new float[16];
    // Temp models matrix.
    private float[] modelMatrix = new float[16];

    ObjTriangle objtriangle;

    // Constructor.
    public MainRenderer() {
        // Set class.
        this.objtriangle = new ObjTriangle();

    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

        // Set program shader.

    public void onSurfaceChanged(GL10 unused, int width, int height) {
        this.width = width;
        this.height = height;

        GLES20.glViewport(0, 0, this.width, this.height);
        Matrix.orthoM(this.projMatrix, 0, 0.0f, this.width - 1.0f, 0.0f, this.height - 1.0f, 5.0f, 10.0f);
        Matrix.setLookAtM(this.viewMatrix, 0, 0.0f, 0.0f, 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
        // Calculate the projection and view transformation for models.
        Matrix.multiplyMM(this.basicMatrix, 0, this.projMatrix, 0, this.viewMatrix, 0);

    public void onDrawFrame(GL10 unused) {

        // Translate triangle.
        Matrix.translateM(this.modelMatrix, 0, this.width / 2.0f, this.height / 2.0f, 0.0f);
        // Scale triangle.
        Matrix.scaleM(this.modelMatrix, 0, 100.0f, 100.0f, 0.0f);
        // Draw triangle.

    public static int LoadShader(int type, String shaderCode) {
        // Create a shader type.
        int shader = GLES20.glCreateShader(type);
        // Add the source code to the shader and compile it.
        GLES20.glShaderSource(shader, shaderCode);

        return shader;

    private void ResetModelMatrix() {
        this.modelMatrix = this.basicMatrix.clone();

We note the presence of the constructor "MainRenderer()" as we need to define the "ObjTriangle" class when the renderer is defined in "MainView".

With "this.objtriangle = new ObjTriangle();" we call the constructor of "ObjTriangle" class where we set the data of our triangle.
The vertices of the triangle present in "vertices" and "indices" (written counterclockwise) are not in a format useful for OpenGL, in the constructor they are converted and stored in "vertexBuffer" and "indexBuffer".

In the "onSurfaceCreated()" method we initialize the program shader with "this.objtriangle.SetProgramShader();".

In the "onSurfaceChanged()" method, after setting the projection and camera matrix, we set the basic matrix for the models, in practice we multiply the projection matrix by the camera matrix.

In the "onDrawFrame()" method:
- 1. clear the frame;
- 2. reset the model matrix;
- 3. translate the model matrix;
- 4. scale the model matrix;
- 5. draw the triangle by calling the function present in the "ObjTriangle" class and passing the model matrix to make changes to the coordinates of the triangle.

The result is:

Knowing that our orthogonal coordinate system is "1:1" with the screen and the triangle is "1x1", translating by 200 is equivalent to move of 200 and scaling by 10 is equivalent to a resizing of 10. But be careful of the order! If we first scale by 10, when we move by 200 we will move of 2000, that is the new "basic unit" (10) multiplied by 200.

Download Project:
OpenGL ES 2 Tutorial 2

For more information on the instructions, refer to:

Page created july 23, 2020.


2007-2021 ©
All rights reserved