Merge "Revert "docs: OpenGL Tutorials""

This commit is contained in:
Joe Fernandez
2011-07-07 15:33:15 -07:00
committed by Android (Google) Code Review
8 changed files with 0 additions and 943 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -781,26 +781,6 @@ var ANDROID_RESOURCES = [
en: 'A multi-part tutorial discussing intermediate-level concepts such as data access.'
}
},
{
tags: ['tutorial', 'gl', 'new'],
path: 'tutorials/opengl/opengl-es10.html',
title: {
en: 'Hello OpenGL ES 1.0'
},
description: {
en: 'The basics of implementing an application using the OpenGL ES 1.0 APIs.'
}
},
{
tags: ['tutorial', 'gl', 'new'],
path: 'tutorials/opengl/opengl-es20.html',
title: {
en: 'Hello OpenGL ES 2.0'
},
description: {
en: 'The basics of implementing an application using the OpenGL ES 2.0 APIs.'
}
},
{
tags: ['tutorial', 'testing'],
path: 'tutorials/testing/helloandroid_test.html',

View File

@@ -1,409 +0,0 @@
page.title=Hello OpenGL ES 1.0
parent.title=Tutorials
parent.link=../../browser.html?tag=tutorial
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
<ol>
<li><a href="#creating">Creating an OpenGL ES 1.0 Application</a></li>
<li>
<a href="#drawing">Drawing Graphic Elements</a>
<ol>
<li><a href="#define-triangle">Defining a Triangle</a></li>
<li><a href="#draw-triangle">Draw the Triangle</a></li>
</ol>
</li>
<li><a href="#projection-and-views">Using Projection and Views</a></li>
<li><a href="#motion">Adding Motion</a></li>
<li><a href="#resources">Additional Resources</a></li>
</ol>
<h2 id="code-samples-list">Related Samples</h2>
<ol>
<li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/graphics/
index.html">API Demos - graphics</a></li>
<li><a
href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/graphics/
GLSurfaceViewActivity.html">GLSurfaceViewActivity</a></li>
</ol>
<h2>See also</h2>
<ol>
<li><a href="{@docRoot}guide/topics/graphics/opengl.html">3D with OpenGL</a></li>
<li><a href="{@docRoot}resources/tutorials/opengl/opengl-es20.html">Hello OpenGL
ES 2.0</a></li>
</ol>
</div>
</div>
<p>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:</p>
<ul>
<li>Creating an application using {@link android.opengl.GLSurfaceView} and {@link
android.opengl.GLSurfaceView.Renderer}</li>
<li>Defining a graphic object and drawing it</li>
<li>Defining and applying an projection and view</li>
<li>Applying rotation to the drawn object</li>
</ul>
<p>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.</p>
<p>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 <a
href="{@docRoot}guide/topics/graphics/opengl.html#compatibility">3D with OpenGL</a> document.</p>
<h2 id="creating">Creating an OpenGL ES 1.0 Application</h2>
<p>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.<p>
<p>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 <a href="{@docRoot}guide/topics/graphics/opengl.html">3D
with OpenGL</a> document.</p>
<p>To create an application that uses OpenGL ES 1.0:</p>
<ol>
<li>Start a new Android project with an Activity called <code>HelloOpenGLES10</code>.
<p class="note"><b>Note:</b> If you have not created a basic Android application yet, follow the
<a href="{@docRoot}resources/tutorials/hello-world.html">Hello World Tutorial</a> instructions
to familiarize yourself with the process.</p>
</li>
<li>Modify the <code>HelloOpenGLES10</code> class as follows:
<pre>
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;
&#64;Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGLView = new HelloOpenGLSurfaceView(this);
setContentView(mGLView);
}
&#64;Override
protected void onPause() {
super.onPause();
mGLView.onPause();
}
&#64;Override
protected void onResume() {
super.onResume();
mGLView.onResume();
}
}
class HelloOpenGLES10SurfaceView extends GLSurfaceView {
public HelloOpenGLES10SurfaceView(Context context){
super(context);
setRenderer(new HelloOpenGLES10Renderer());
}
}
</pre>
<p>This Activity class creates a basic container for a {@link android.opengl.GLSurfaceView}.</p>
</li>
<li>Create the following class <code>HelloOpenGLES10Renderer</code>, which implements the
{@link android.opengl.GLSurfaceView.Renderer} interface:
<pre>
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);
}
}
</pre>
</li>
</ol>
<p>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.</p>
<p>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.</p>
<h2 id="drawing">Drawing Graphic Elements</h2>
<p>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.</p>
<p class="note"><b>Note:</b> The following instructions build on the previous section, so if you
have not been following along, go back to the <a href="#get-started">previous section</a> and catch
up.</p>
<h3 id="define-triangle">Defining a Triangle</h3>
<p>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.</p>
<p>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.</p>
<p>To define a vertex array for a triangle:</p>
<ol>
<li>In your <code>HelloOpenGLES10Renderer</code> class, add new member variable to contain the
vertices of a triangle shape:
<pre>
private FloatBuffer triangleVB;
</pre>
</li>
<li>Create a method, <code>initShapes()</code> which populates this member variable:
<pre>
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);
}
</pre>
<p>This method defines a two-dimensional triangle shape with three equal sides.</p>
</li>
<li>Modify your <code>onSurfaceCreated()</code> method to initialize your triangle:
<pre>
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();
}
</pre>
<p class="warning"><strong>Warning:</strong> Shapes and other static objects should be initialized
once in your <code>onSurfaceCreated()</code> method for best performance. Avoid initializing the
new objects in <code>onDrawFrame()</code>, as this causes the system to re-create the objects
for every frame redraw and slows down your application.
</p>
</li>
</ol>
<h3 id="draw-triangle">Draw the Triangle</h3>
<p>Now that you have defined a shape to draw, you can use the OpenGL APIs to draw the
object.</p>
<p>To draw the triangle with OpenGL:</p>
<ol>
<li>Before you can draw your triangle, you must tell OpenGL that you are using vertex arrays.
Modify your <code>onSurfaceCreated()</code> method to enable vertex arrays.
<pre>
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);
}
</pre>
<p>At this point, you are ready to draw the triangle object in the OpenGL frame.</p>
</li>
<li>Modify your <code>onDrawFrame()</code> method to draw the triangle.
<pre>
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);
}
</pre>
<p><b>Note:</b> 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 <a href="#motion">later section</a>, we add motion to the object to
justify this use of processing power.</p>
</li>
</ol>
<p id="squashed-triangle">Try running this example application on your emulator or test device and
you should see something like this:</p>
<img src="{@docRoot}images/opengl/helloopengl-es10-1.png">
<p>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
<a href="#projection-and-views">next section</a>.</p>
<h2 id="projection-and-views">Using Projection and Views</h2>
<p>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&#8212;by default&#8212;OpenGL
happily maps a perfectly square, uniform coordinate system onto your typically non-square
screen.</p>
<img src="{@docRoot}images/opengl/coordinates.png">
<p>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.</p>
<p>To use a projection transformation on your triangle:</p>
<ol>
<li>Modify your <code>onSurfaceChanged()</code> 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.
<pre>
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);
}
</pre>
</li>
<li>Next, modify your <code>onDrawFrame()</code> 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()}.
<pre>
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
...
}
</pre>
</li>
</ol>
<p>Try running this updated application on your emulator or test device and you should see something
like this:</p>
<img src="{@docRoot}images/opengl/helloopengl-es10-2.png">
<p>Now that you have applied this transformation, the triangle has three equal sides, instead of the
squashed display in the <a href="#squashed-triangle">earlier version</a>.</p>
<h2 id="motion">Adding Motion</h2>
<p>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.</p>
<p>To add rotation to your triangle:</p>
<ul>
<li>Modify your <code>onDrawFrame()</code> method to rotate the triangle object:
<pre>
public void onDrawFrame(GL10 gl) {
...
// When using GL_MODELVIEW, you must set the view point
GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// Create a rotation for the triangle
long time = SystemClock.uptimeMillis() % 4000L;
float angle = 0.090f * ((int) time);
gl.glRotatef(angle, 0.0f, 0.0f, 1.0f);
// Draw the triangle
...
}
</pre>
</li>
</ul>
<p>Run the application with this code and your triangle should rotate around its center.</p>
<!--
<h2>TouchScreen Interaction</h2>
Optional extra (using code from API examples)
-->
<h2 id="resources">Additional Resources</h2>
<p>Be sure to check out the OpenGL ES code samples are available in the
<a
href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/graphics/index.html">API
Demos</a> sample application and listed in <a href="#code-samples-list">Related Samples</a>
sidebar above.
</p>

View File

@@ -1,514 +0,0 @@
page.title=Hello OpenGL ES 1.0
parent.title=Tutorials
parent.link=../../browser.html?tag=tutorial
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>In this document</h2>
<ol>
<li><a href="#creating">Creating an OpenGL ES 2.0 Application</a></li>
<li>
<a href="#drawing">Drawing Graphic Elements</a>
<ol>
<li><a href="#define-triangle">Defining a Triangle</a></li>
<li><a href="#draw-triangle">Draw the Triangle</a></li>
</ol>
</li>
<li><a href="#projection-and-views">Using Projection and Views</a></li>
<li><a href="#motion">Adding Motion</a></li>
<li><a href="#resources">Additional Resources</a></li>
</ol>
<h2 id="code-samples-list">Related Samples</h2>
<ol>
<li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/graphics/
index.html">API Demos - graphics</a></li>
<li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/graphics/
GLES20Activity.html">OpenGL ES 2.0 Example</a></li>
</ol>
<h2>See also</h2>
<ol>
<li><a href="{@docRoot}guide/topics/graphics/opengl.html">3D with OpenGL</a></li>
<li><a href="{@docRoot}resources/tutorials/opengl/opengl-es10.html">Hello OpenGL
ES 1.0</a></li>
</ol>
</div>
</div>
<p>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:</p>
<ul>
<li>Creating an application using {@link android.opengl.GLSurfaceView} and {@link
android.opengl.GLSurfaceView.Renderer}</li>
<li>Defining a graphic object and drawing it</li>
<li>Defining and applying an projection and view</li>
<li>Applying rotation to the drawn object</li>
</ul>
<p>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.</p>
<p>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 <a href="{@docRoot}guide/topics/graphics/opengl.html#compatibility">3D with OpenGL</a>
document.</p>
<h2 id="creating">Creating an OpenGL ES 1.0 Application</h2>
<p>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.<p>
<p>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 <a href="{@docRoot}guide/topics/graphics/opengl.html">3D
with OpenGL</a> document.</p>
<p>To create an application that uses OpenGL ES 2.0:</p>
<ol>
<li>Start a new Android project with an Activity called <code>HelloOpenGLES20</code>.
<p class="note"><b>Note:</b> If you have not created a basic Android application yet, follow the
<a href="{@docRoot}resources/tutorials/hello-world.html">Hello World Tutorial</a> instructions
to familiarize yourself with the process.</p>
</li>
<li>Modify the <code>HelloOpenGLES20</code> class as follows:
<pre>
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;
&#64;Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGLView = new HelloOpenGLES20SurfaceView(this);
setContentView(mGLView);
}
&#64;Override
protected void onPause() {
super.onPause();
mGLView.onPause();
}
&#64;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());
}
}
</pre>
<p>This Activity class creates a basic container for a {@link android.opengl.GLSurfaceView}.</p>
</li>
<li>Create the following class <code>HelloOpenGLES20Renderer</code>, which implements the
{@link android.opengl.GLSurfaceView.Renderer} interface:
<pre>
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);
}
}
</pre>
</li>
</ol>
<p>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.</p>
<p>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 <a
href="{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a></code> file as
shown below.</p>
<pre>
...
&lt;/application&gt;
&lt;!-- Tell the system that you need ES 2.0. --&gt;
&lt;uses-feature android:glEsVersion="0x00020000" android:required="true" /&gt;
&lt;/manifest&gt;
</pre>
<p>Adding this declaration hides your application from devices that do not support OpenGL ES 2.0
in the Android Market.</p>
<p>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.</p>
<h2 id="drawing">Drawing Graphic Elements</h2>
<p>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.</p>
<p class="note"><b>Note:</b> The following instructions build on the previous section, so if you
have not been following along, go back to the <a href="#get-started">previous section</a> and catch
up.</p>
<h3 id="define-triangle">Defining a Triangle</h3>
<p>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.</p>
<p>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.</p>
<p>To define a vertex array for a triangle:</p>
<ol>
<li>In your <code>HelloOpenGLES20Renderer</code> class, add new member variable to contain the
vertices of a triangle shape:
<pre>
private FloatBuffer triangleVB;
</pre>
</li>
<li>Create a method, <code>initShapes()</code> which populates this member variable:
<pre>
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);
}
</pre>
<p>This method defines a two-dimensional triangle shape with three equal sides.</p>
</li>
<li>Modify your <code>onSurfaceCreated()</code> method to initialize your triangle:
<pre>
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();
}
</pre>
<p class="warning"><strong>Warning:</strong> Shapes and other static objects should be initialized
once in your <code>onSurfaceCreated()</code> method for best performance. Avoid initializing the
new objects in <code>onDrawFrame()</code>, as this causes the system to re-create the objects
for every frame redraw and slows down your application.
</p>
</li>
</ol>
<h3 id="draw-triangle">Draw the Triangle</h3>
<p>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.</p>
<p>To draw the triangle with OpenGL:</p>
<ol>
<li>In your <code>HelloOpenGLES20Renderer</code> class, define a vertex shader and a fragment
shader.
<pre>
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";
</pre>
</li>
<li>In your <code>HelloOpenGLES20Renderer</code> class, create a method for loading the shaders.
<pre>
private int loadShader(int type, String shaderCode){
int shader = GLES20.glCreateShader(type);
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
</pre>
</li>
<li>Add the following members to your <code>HelloOpenGLES20Renderer</code> class for an OpenGL
Program.
<pre>
private int mProgram;
private int maPositionHandle;
</pre>
</li>
<li>Modify your <code>onSurfaceCreated()</code> method to load the shaders and attach them to a
OpenGL Program.
<pre>
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");
}
</pre>
<p>At this point, you are ready to draw the triangle object in the OpenGL frame.</p>
</li>
<li>Modify your <code>onDrawFrame()</code> method to draw the triangle.
<pre>
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);
}
</pre>
<p><b>Note:</b> 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 <a href="#motion">later section</a>, we add motion to the object to
justify this use of processing power.</p>
</li>
</ol>
<p id="squashed-triangle">Try running this example application on your emulator or test device and
you should see something like this:</p>
<img src="{@docRoot}images/opengl/helloopengl-es20-1.png">
<p>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
<a href="#projection-and-views">next section</a>.</p>
<h2 id="projection-and-views">Using Projection and Views</h2>
<p>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&#8212;by default&#8212;OpenGL
happily maps a perfectly square, uniform coordinate system onto your typically non-square
screen.</p>
<img src="{@docRoot}images/opengl/coordinates.png">
<p>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.</p>
<p>To use a projection transformation on your triangle:</p>
<ol>
<li>Add the following members to your <code>HelloOpenGLES20Renderer</code> class.
<pre>
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];
</pre>
</li>
<li>Modify your <code>vertexShaderCode</code> string to add a variable for a model view
projection matrix.
<pre>
private final String vertexShaderCode =
"uniform mat4 uMVPMatrix; \n" +
"attribute vec4 vPosition; \n" +
"void main(){ \n" +
" gl_Position = uMVPMatrix * vPosition; \n" +
"} \n";
</pre>
</li>
<li>Modify your <code>onSurfaceChanged()</code> method to reference the <code>uMVPMatrix</code>
shader variable you added and define a view transformation matrix.
<pre>
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);
}
</pre>
</li>
<li>Next, modify your <code>onSurfaceChanged()</code> method to calculate the device screen
ration and create a projection matrix.
<pre>
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);
}
</pre>
</li>
<li>Finally, modify your <code>onDrawFrame()</code> method to apply the transformation.
<pre>
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);
}
</pre>
</li>
</ol>
<p>Try running this updated application on your emulator or test device and you should see
something like this:</p>
<img src="{@docRoot}images/opengl/helloopengl-es20-2.png">
<p>Now that you have applied this transformation, the triangle has three equal sides, instead of the
squashed display in the <a href="#squashed-triangle">earlier version</a>.</p>
<h2 id="motion">Adding Motion</h2>
<p>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.</p>
<p>To add rotation to your triangle:</p>
<ol>
<li>Add an additional tranformation matrix member to your <code>HelloOpenGLES20Renderer</code>
class.
<pre>
private float[] mMMatrix = new float[16];
</pre>
</li> <li>Modify your <code>onDrawFrame()</code> method to rotate the triangle object:
<pre>
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
...
}
</pre>
</li>
</ol>
<p>Run the application with this code and your triangle should rotate around its center.</p>
<!--
<h2>TouchScreen Interaction</h2>
Optional extra (using code from API examples)
-->
<h2 id="resources">Additional Resources</h2>
<p>Be sure to check out the OpenGL ES code samples are available in the
<a
href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/graphics/index.html">API
Demos</a> sample application and listed in <a href="#code-samples-list">Related Samples</a>
sidebar above.
</p>