page.title=Hello OpenGL ES 1.0 parent.title=Tutorials parent.link=../../browser.html?tag=tutorial @jd:body

In this document

  1. Creating an OpenGL ES 2.0 Application
  2. Drawing Graphic Elements
    1. Defining a Triangle
    2. Draw the Triangle
  3. Using Projection and Views
  4. Adding Motion
  5. Additional Resources

Related Samples

  1. API Demos - graphics
  2. OpenGL ES 2.0 Example

See also

  1. 3D with OpenGL
  2. Hello OpenGL ES 1.0

This tutorial shows you how to create a simple Android application that uses OpenGL ES 2.0 and perform some basic operations using the OpenGL ES 2.0 API, including:

This tutorial demonstrates use of the OpenGL ES 2.0 API. Beginning with Android 2.2 (API Level 8), the framework supports OpenGL ES 2.0.

Both the OpenGL ES 1.0 and the ES 1.1 API are supported by the Android framework since release 1.0 (API Level 1).For more information about compatibility for OpenGL versions and Android devices, see the 3D with OpenGL document.

Creating an OpenGL ES 1.0 Application

OpenGL applications for Android have the same basic structure as other applications, however OpenGL applications use {@link android.opengl.GLSurfaceView} where other, non-OpenGL applications use the {@link android.view.View} or {@link android.view.SurfaceView} class.

To get started using OpenGL in your Android application, you must implement both a {@link android.opengl.GLSurfaceView} and a {@link android.opengl.GLSurfaceView.Renderer}. The {@link android.opengl.GLSurfaceView} is the main view type for the OpenGL applications and the {@link android.opengl.GLSurfaceView.Renderer} controls what is drawn within that view. For more information about these classes, see the 3D with OpenGL document.

To create an application that uses OpenGL ES 2.0:

  1. Start a new Android project with an Activity called HelloOpenGLES20.

    Note: If you have not created a basic Android application yet, follow the Hello World Tutorial instructions to familiarize yourself with the process.

  2. Modify the HelloOpenGLES20 class as follows:
    package com.example.android.apis.graphics;
    
    import android.app.Activity;
    import android.content.Context;
    import android.opengl.GLSurfaceView;
    import android.os.Bundle;
    
    public class HelloOpenGLES20 extends Activity {
      
        private GLSurfaceView mGLView;    
      
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            
            mGLView = new HelloOpenGLES20SurfaceView(this);
            setContentView(mGLView);
        }
        
        @Override
        protected void onPause() {
            super.onPause();
            mGLView.onPause();
        }
        
        @Override
        protected void onResume() {
            super.onResume();
            mGLView.onResume();
        }
    }
      
    class HelloOpenGLES20SurfaceView extends GLSurfaceView {
    
        public HelloOpenGLES20SurfaceView(Context context){
            super(context);
            
            // Create an OpenGL ES 2.0 context.
            setEGLContextClientVersion(2);
    
            setRenderer(new HelloOpenGLES20Renderer());
        }
    }
    

    This Activity class creates a basic container for a {@link android.opengl.GLSurfaceView}.

  3. Create the following class HelloOpenGLES20Renderer, which implements the {@link android.opengl.GLSurfaceView.Renderer} interface:
    package com.example.android.apis.graphics;
    
    import javax.microedition.khronos.egl.EGLConfig;
    import javax.microedition.khronos.opengles.GL10;
    
    import android.opengl.GLES20;
    import android.opengl.GLSurfaceView;
    
    public class HelloOpenGLES20Renderer implements GLSurfaceView.Renderer {
      
        public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        
            // Set the background frame color
            GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
        }
        
        public void onDrawFrame(GL10 unused) {
        
            // Redraw background color
            GLES20.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        }
        
        public void onSurfaceChanged(GL10 unused, int width, int height) {
            GLES20.glViewport(0, 0, width, height);
        }
      
    }
    

These classes create a simple Android application which displays a grey screen using OpenGL ES 2.0 calls. While this application does not do anything very interesting, by creating these two classes, you have layed the foundation needed to start drawing graphic elements with OpenGL ES 2.0.

If your application only supports OpenGL ES 2.0, then you should declare that your application requires OpenGL ES 2.0 by adding the following settings to your AndroidManifest.xml file as shown below.

...
    </application>
    
    <!-- Tell the system that you need ES 2.0. -->
    <uses-feature android:glEsVersion="0x00020000" android:required="true" />

</manifest>

Adding this declaration hides your application from devices that do not support OpenGL ES 2.0 in the Android Market.

If you are familiar with the OpenGL ES APIs, these preceding classes and the AndroidManifest.xml declaration should give you enough information to start using the OpenGL ES API and creating graphics. However, if you need a bit more help getting started with OpenGL, head on to the next sections for a few more tips.

Drawing Graphic Elements

Once you have implemented a {@link android.opengl.GLSurfaceView.Renderer}, the next step is to draw something on it. This section shows you how to define and draw a basic triangle shape with the OpenGL ES 2.0 API.

Note: The following instructions build on the previous section, so if you have not been following along, go back to the previous section and catch up.

Defining a Triangle

OpenGL allows you to define objects using coordinates in three-dimensional space. So, before you can draw a triangle, you must define its coordinates. In OpenGL, the typical way to do this is to define a vertex array for the coordinates.

By default, OpenGL ES assumes a coordinate system where 0,0,0 (X,Y,Z) specifies the center of the {@link android.opengl.GLSurfaceView} frame, 1,1,0 is the top right corner of the frame and -1,-1,0 is bottom left corner of the frame.

To define a vertex array for a triangle:

  1. In your HelloOpenGLES20Renderer class, add new member variable to contain the vertices of a triangle shape:
        private FloatBuffer triangleVB;
    
  2. Create a method, initShapes() which populates this member variable:
        private void initShapes(){
        
            float triangleCoords[] = {
                // X, Y, Z
                -0.5f, -0.25f, 0,
                 0.5f, -0.25f, 0,
                 0.0f,  0.559016994f, 0
            }; 
            
            // initialize vertex Buffer for triangle  
            ByteBuffer vbb = ByteBuffer.allocateDirect(
                    // (# of coordinate values * 4 bytes per float)
                    triangleCoords.length * 4); 
            vbb.order(ByteOrder.nativeOrder());
            triangleVB = vbb.asFloatBuffer();
            triangleVB.put(triangleCoords);
            triangleVB.position(0);
        
        }
    

    This method defines a two-dimensional triangle shape with three equal sides.

  3. Modify your onSurfaceCreated() method to initialize your triangle:
        public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        
            // Set the background frame color
            GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
            
            // initialize the triangle vertex array
            initShapes();
        }
    

    Warning: Shapes and other static objects should be initialized once in your onSurfaceCreated() method for best performance. Avoid initializing the new objects in onDrawFrame(), as this causes the system to re-create the objects for every frame redraw and slows down your application.

Draw the Triangle

Now that you have defined a shape to draw, you can now use the OpenGL APIs to draw the object. In order to do this with OpenGL ES 2.0, you must define a vertex shader and a fragment shader to describe how to draw your shape.

To draw the triangle with OpenGL:

  1. In your HelloOpenGLES20Renderer class, define a vertex shader and a fragment shader.
        private final String vertexShaderCode = 
            "attribute vec4 vPosition;    \n" +
            "void main(){         \n" +
            " gl_Position = vPosition;  \n" +
            "}                \n";
        
        private final String fragmentShaderCode = 
            "precision mediump float; \n" +
            "void main(){       \n" +
            " gl_FragColor = vec4 (0.63671875, 0.76953125, 0.22265625, 1.0); \n" +
            "} \n";
    
  2. In your HelloOpenGLES20Renderer class, create a method for loading the shaders.
        private int loadShader(int type, String shaderCode){
        
            int shader = GLES20.glCreateShader(type);
            
            GLES20.glShaderSource(shader, shaderCode);
            GLES20.glCompileShader(shader);
            
            return shader;
        }
    
  3. Add the following members to your HelloOpenGLES20Renderer class for an OpenGL Program.
        private int mProgram;
        private int maPositionHandle;
    
  4. Modify your onSurfaceCreated() method to load the shaders and attach them to a OpenGL Program.
        public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        
            // Set the background frame color
            GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
            
            // initialize the triangle vertex array
            initShapes();
            
            // Create shaders for shape and attach to program
            int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
            int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
            
            mProgram = GLES20.glCreateProgram();
            GLES20.glAttachShader(mProgram, vertexShader);
            GLES20.glAttachShader(mProgram, fragmentShader);
            GLES20.glLinkProgram(mProgram);
            
            maPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
        }
    

    At this point, you are ready to draw the triangle object in the OpenGL frame.

  5. Modify your onDrawFrame() method to draw the triangle.
        public void onDrawFrame(GL10 unused) {
            
            // Redraw background color
            GLES20.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        
            // Specify a program with shaders
            GLES20.glUseProgram(mProgram);
            
            // Prepare the triangle data
            GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, 12, triangleVB);
            GLES20.glEnableVertexAttribArray(maPositionHandle);
            
            // Draw the triangle
            GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
        }
    

    Note: Since the triangle is stationary at this point, the system is redrawing the object repeatedly in exactly the same place and so is not the most efficient use of the OpenGL graphics pipeline. In a later section, we add motion to the object to justify this use of processing power.

Try running this example application on your emulator or test device and you should see something like this:

There are a few problems with this example. First of all, it's not going to impress your friends. Secondly, the triangle is a bit squashed and changes shape when you change the screen orientation of the test device. The reason the shape is skewed is due to the fact that the object is being rendered in a frame which is not perfectly square. We fix that problem in the next section.

Using Projection and Views

OpenGL Projection and Views provide a way to calculate the coordinates of graphic objects in realistic proportions on graphics displays of any size. One of the basic problems in displaying graphics is that Android device displays are typically not square and—by default—OpenGL happily maps a perfectly square, uniform coordinate system onto your typically non-square screen.

The illustration above shows the uniform coordinate system assumed for an OpenGL frame on the left, and how these coordinates actually map to a typical device screen in landscape orientation on the right. To solve this problem, you can apply OpenGL projection modes and views to transform object coordinates so your graphic objects have the correct proportions on any display.

To use a projection transformation on your triangle:

  1. Add the following members to your HelloOpenGLES20Renderer class.
        private int muMVPMatrixHandle;
        private float[] mMVPMatrix = new float[16];
        private float[] mMMatrix = new float[16];
        private float[] mVMatrix = new float[16];
        private float[] mProjMatrix = new float[16];
    
  2. Modify your vertexShaderCode string to add a variable for a model view projection matrix.
        private final String vertexShaderCode = 
            "uniform mat4 uMVPMatrix;   \n" +
            "attribute vec4 vPosition;  \n" +
            "void main(){               \n" +
            " gl_Position = uMVPMatrix * vPosition; \n" +
            "}  \n";
    
  3. Modify your onSurfaceChanged() method to reference the uMVPMatrix shader variable you added and define a view transformation matrix.
        public void onSurfaceCreated(GL10 unused, EGLConfig config) {
            ...
            maPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
            
            muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
            Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
        }
    
  4. Next, modify your onSurfaceChanged() method to calculate the device screen ration and create a projection matrix.
        public void onSurfaceChanged(GL10 unused, int width, int height) {
            GLES20.glViewport(0, 0, width, height);
            
            float ratio = (float) width / height;
            Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
        }  
    
  5. Finally, modify your onDrawFrame() method to apply the transformation.
        public void onDrawFrame(GL10 unused) {
            ...
            // Apply a ModelView Projection transformation
            Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
            GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
            
            // Draw the triangle
            GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);        
        }
    

Try running this updated application on your emulator or test device and you should see something like this:

Now that you have applied this transformation, the triangle has three equal sides, instead of the squashed display in the earlier version.

Adding Motion

While it may be interesting exercise to create static graphic objects with OpenGL ES, chances are you want at least some of your objects to move. In this section, we add motion to to our triangle by rotating it.

To add rotation to your triangle:

  1. Add an additional tranformation matrix member to your HelloOpenGLES20Renderer class.
          private float[] mMMatrix = new float[16];
        
  2. Modify your onDrawFrame() method to rotate the triangle object:
        public void onDrawFrame(GL10 gl) {
            ...
        
            // Create a rotation for the triangle
            long time = SystemClock.uptimeMillis() % 4000L;
            float angle = 0.090f * ((int) time);
            Matrix.setRotateM(mMMatrix, 0, angle, 0, 0, 1.0f);
            Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
            Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
            
            // Apply a ModelView Projection transformation
            //Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
            GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
            
            // Draw the triangle
            ...
        }
    

Run the application with this code and your triangle should rotate around its center.

Additional Resources

Be sure to check out the OpenGL ES code samples are available in the API Demos sample application and listed in Related Samples sidebar above.