From 4cd8360943a167505c929a309cccd7cb56eb4138 Mon Sep 17 00:00:00 2001 From: Joe Fernandez Date: Wed, 22 Jun 2011 14:25:04 -0700 Subject: docs: OpenGL Tutorials Change-Id: I2d06990277d48facc46f5ea9ea4ec784ece93264 --- .../html/resources/tutorials/opengl/opengl-es10.jd | 409 ++++++++++++++++ .../html/resources/tutorials/opengl/opengl-es20.jd | 514 +++++++++++++++++++++ 2 files changed, 923 insertions(+) create mode 100644 docs/html/resources/tutorials/opengl/opengl-es10.jd create mode 100644 docs/html/resources/tutorials/opengl/opengl-es20.jd (limited to 'docs/html/resources/tutorials') diff --git a/docs/html/resources/tutorials/opengl/opengl-es10.jd b/docs/html/resources/tutorials/opengl/opengl-es10.jd new file mode 100644 index 0000000..d18a547 --- /dev/null +++ b/docs/html/resources/tutorials/opengl/opengl-es10.jd @@ -0,0 +1,409 @@ +page.title=Hello OpenGL ES 1.0 +parent.title=Tutorials +parent.link=../../browser.html?tag=tutorial +@jd:body + + +
+ +
+ +

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

+ + + +

This tutorial demonstrates use of the OpenGL ES 1.0 API. 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). The OpenGL ES 1.1 API +is an extention of the 1.0 API, and it's capabilities are beyond the scope of this tutorial.

+ +

Beginning with Android 2.2 (API Level 8), the framework supports OpenGL ES 2.0. 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 1.0:

+ +
    +
  1. Start a new Android project with an Activity called HelloOpenGLES10. + +

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

    +
  2. + +
  3. Modify the HelloOpenGLES10 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 HelloOpenGLES10 extends Activity {
    +  
    +    private GLSurfaceView mGLView;    
    +  
    +    @Override
    +    public void onCreate(Bundle savedInstanceState) {
    +        super.onCreate(savedInstanceState);
    +        
    +        mGLView = new HelloOpenGLSurfaceView(this);
    +        setContentView(mGLView);
    +    }
    +    
    +    @Override
    +    protected void onPause() {
    +        super.onPause();
    +        mGLView.onPause();
    +    }
    +    
    +    @Override
    +    protected void onResume() {
    +        super.onResume();
    +        mGLView.onResume();
    +    }
    +    
    +}
    +  
    +class HelloOpenGLES10SurfaceView extends GLSurfaceView {
    +
    +    public HelloOpenGLES10SurfaceView(Context context){
    +        super(context);
    +        setRenderer(new HelloOpenGLES10Renderer());
    +    }
    +
    +}
    +
    +

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

    +
  4. + +
  5. Create the following class HelloOpenGLES10Renderer, 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.GLSurfaceView;
    +
    +public class HelloOpenGLES10Renderer implements GLSurfaceView.Renderer {
    +
    +    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    +        // Set the background frame color
    +        gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
    +    }
    +    
    +    public void onDrawFrame(GL10 gl) {
    +        // Redraw background color
    +        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    +    }
    +    
    +    public void onSurfaceChanged(GL10 gl, int width, int height) {
    +        gl.glViewport(0, 0, width, height);
    +    }
    +  
    +}
    +
    +
  6. +
+ +

These classes create a simple Android application which displays a grey screen using OpenGL +ES 1.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 +1.0.

+ +

If you are familiar with the OpenGL ES APIs, these two classes should give you enough information +to start using the OpenGL ES 1.0 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 +Android OpenGL ES 1.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 HelloOpenGLES10Renderer class, add new member variable to contain the +vertices of a triangle shape: +
    +    private FloatBuffer triangleVB;
    +
    +
  2. + +
  3. 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.

    +
  4. +
  5. Modify your onSurfaceCreated() method to initialize your triangle: +
    +    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    +    
    +        // Set the background frame color
    +        gl.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. +

    +
  6. + +
+ +

Draw the Triangle

+ +

Now that you have defined a shape to draw, you can use the OpenGL APIs to draw the +object.

+ +

To draw the triangle with OpenGL:

+ +
    +
  1. Before you can draw your triangle, you must tell OpenGL that you are using vertex arrays. + Modify your onSurfaceCreated() method to enable vertex arrays. +
    +    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    +    
    +        // Set the background frame color
    +        gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
    +        
    +        // initialize the triangle vertex array
    +        initShapes();
    +        
    +        // Enable use of vertex arrays
    +        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    +    }
    +
    +

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

    +
  2. + +
  3. Modify your onDrawFrame() method to draw the triangle. +
    +    public void onDrawFrame(GL10 gl) {
    +        // Redraw background color
    +        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    +    
    +        // Draw the triangle
    +        gl.glColor4f(0.63671875f, 0.76953125f, 0.22265625f, 0.0f);
    +        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, triangleVB);
    +        gl.glDrawArrays(GL10.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.

    +
  4. +
+ +

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. Modify your onSurfaceChanged() method to enable {@link + javax.microedition.khronos.opengles.GL10#GL_PROJECTION GL10.GL_PROJECTION} mode, calculate the + screen ratio and apply the ratio as a transformation of the object coordinates. +
    +  public void onSurfaceChanged(GL10 gl, int width, int height) {
    +      gl.glViewport(0, 0, width, height);
    +      
    +      // make adjustments for screen ratio
    +      float ratio = (float) width / height;
    +      gl.glMatrixMode(GL10.GL_PROJECTION);
    +      gl.glLoadIdentity();
    +      gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7);
    +  }  
    +
    +
  2. + +
  3. Next, modify your onDrawFrame() method to apply the {@link +javax.microedition.khronos.opengles.GL10#GL_MODELVIEW GL_MODELVIEW} mode and set +a view point for the display using {@link +android.opengl.GLU#gluLookAt(javax.microedition.khronos.opengles.GL10, float, float, float, float, +float, float, float, float, float) GLU#gluLookAt()}. +
    +    public void onDrawFrame(GL10 gl) {
    +        // Redraw background color
    +        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    +        
    +        // Set GL_MODELVIEW transformation mode
    +        gl.glMatrixMode(GL10.GL_MODELVIEW);
    +        gl.glLoadIdentity();
    +        
    +        // When using GL_MODELVIEW, you must set the view point
    +        GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);        
    +        
    +        // Draw the triangle
    +        ...
    +    }
    +
    +
  4. +
+ +

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:

+ + +

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. +

diff --git a/docs/html/resources/tutorials/opengl/opengl-es20.jd b/docs/html/resources/tutorials/opengl/opengl-es20.jd new file mode 100644 index 0000000..5cdc343 --- /dev/null +++ b/docs/html/resources/tutorials/opengl/opengl-es20.jd @@ -0,0 +1,514 @@ +page.title=Hello OpenGL ES 1.0 +parent.title=Tutorials +parent.link=../../browser.html?tag=tutorial +@jd:body + + +
+ +
+ +

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. + +
  3. 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}.

    +
  4. + +
  5. 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);
    +    }
    +  
    +}
    +
    +
  6. +
+ +

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. + +
  3. 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.

    +
  4. +
  5. 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. +

    +
  6. + +
+ +

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. +
  3. 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;
    +    }
    +
    +
  4. + +
  5. Add the following members to your HelloOpenGLES20Renderer class for an OpenGL +Program. +
    +    private int mProgram;
    +    private int maPositionHandle;
    +
    +
  6. + +
  7. 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.

    +
  8. + +
  9. 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.

    +
  10. +
+ +

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. +
  3. 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";
    +
    +
  4. +
  5. 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);
    +    }
    +
    +
  6. +
  7. 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);
    +    }  
    +
    +
  8. +
  9. 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);        
    +    }
    +
    +
  10. +
+ +

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
    +        ...
    +    }
    +
    +
  3. +
+ +

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. +

-- cgit v1.1