Merge "docs: OpenGL ES 1.0 and 2.0 Tutorials"
This commit is contained in:
committed by
Android (Google) Code Review
commit
e3be9b9452
@@ -244,7 +244,7 @@
|
||||
</a></li>
|
||||
<li><a href="<?cs var:toroot ?>guide/topics/graphics/opengl.html">
|
||||
<span class="en">3D with OpenGL</span>
|
||||
</a></li>
|
||||
</a><span class="new">updated</span></li>
|
||||
<li><a href="<?cs var:toroot ?>guide/topics/graphics/animation.html">
|
||||
<span class="en">Property Animation</span>
|
||||
</a></li>
|
||||
|
||||
@@ -8,22 +8,37 @@ parent.link=index.html
|
||||
<h2>In this document</h2>
|
||||
|
||||
<ol>
|
||||
<li><a href="#basics">The Basics</a></li>
|
||||
<li><a href="#compatibility">OpenGL Versions and Device Compatibility</a>
|
||||
<li><a href="#basics">The Basics</a>
|
||||
<ol>
|
||||
<li><a href="#textures">Texture Compression Support</a></li>
|
||||
<li><a href="#declare-compression">Declaring Use of Compressed Textures</a></li>
|
||||
<li><a href="#packages">OpenGL packages</a></li>
|
||||
</ol>
|
||||
<li><a href="#manifest">Declaring OpenGL Requirements</a></li>
|
||||
</li>
|
||||
<li><a href="#coordinate-mapping">Coordinate Mapping for Drawn Objects</a>
|
||||
<ol>
|
||||
<li><a href="#proj-es1">Projection and camera in ES 1.0</a></li>
|
||||
<li><a href="#proj-es1">Projection and camera in ES 2.0</a></li>
|
||||
</ol>
|
||||
</li>
|
||||
<li><a href="#compatibility">OpenGL Versions and Device Compatibility</a>
|
||||
<ol>
|
||||
<li><a href="#textures">Texture compression support</a></li>
|
||||
<li><a href="#gl-extension-query">Determining OpenGL Extensions</a></li>
|
||||
</ol>
|
||||
</li>
|
||||
<li><a href="#choosing-version">Choosing an OpenGL API Version</a></li>
|
||||
</ol>
|
||||
<h2>Key classes</h2>
|
||||
<ol>
|
||||
<li>{@link android.opengl.GLSurfaceView}</li>
|
||||
<li>{@link android.opengl.GLSurfaceView.Renderer}</li>
|
||||
<li>{@link javax.microedition.khronos.opengles}</li>
|
||||
<li>{@link android.opengl}</li>
|
||||
</ol>
|
||||
<h2>Related Samples</h2>
|
||||
<h2>Related tutorials</h2>
|
||||
<ol>
|
||||
<li><a href="{@docRoot}resources/tutorials/opengl/opengl-es10.html">OpenGL ES 1.0</a></li>
|
||||
<li><a href="{@docRoot}resources/tutorials/opengl/opengl-es20.html">OpenGL ES 2.0</a></li>
|
||||
</ol>
|
||||
<h2>Related samples</h2>
|
||||
<ol>
|
||||
<li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/graphics/
|
||||
GLSurfaceViewActivity.html">GLSurfaceViewActivity</a></li>
|
||||
@@ -46,11 +61,11 @@ GLSurfaceView</a></li>
|
||||
</div>
|
||||
|
||||
<p>Android includes support for high performance 2D and 3D graphics with the Open Graphics Library
|
||||
(OpenGL) API—specifically, the OpenGL ES API. OpenGL is a cross-platform graphics API that
|
||||
specifies a standard software interface for 3D graphics processing hardware. OpenGL ES is a flavor
|
||||
of the OpenGL specification intended for embedded devices. The OpenGL ES 1.0 and 1.1 API
|
||||
specifications have been supported since Android 1.0. Beginning with Android 2.2 (API
|
||||
Level 8), the framework supports the OpenGL ES 2.0 API specification.</p>
|
||||
(OpenGL), specifically, the OpenGL ES API. OpenGL is a cross-platform graphics API that specifies a
|
||||
standard software interface for 3D graphics processing hardware. OpenGL ES is a flavor of the OpenGL
|
||||
specification intended for embedded devices. The OpenGL ES 1.0 and 1.1 API specifications have been
|
||||
supported since Android 1.0. Beginning with Android 2.2 (API Level 8), the framework supports the
|
||||
OpenGL ES 2.0 API specification.</p>
|
||||
|
||||
<p class="note"><b>Note:</b> The specific API provided by the Android framework is similar to the
|
||||
J2ME JSR239 OpenGL ES API, but is not identical. If you are familiar with J2ME JSR239
|
||||
@@ -71,18 +86,19 @@ understanding how to implement these classes in an activity should be your first
|
||||
</p>
|
||||
|
||||
<dl>
|
||||
<dt>{@link android.opengl.GLSurfaceView}</dt>
|
||||
<dd>This class is a container on which you can draw and manipulate objects using OpenGL API calls.
|
||||
This class is similar in function to a {@link android.view.SurfaceView}, except that it is
|
||||
specifically for use with OpenGL. You can use this class by simply creating an instance of
|
||||
{@link android.opengl.GLSurfaceView} and adding your
|
||||
<dt><strong>{@link android.opengl.GLSurfaceView}</strong></dt>
|
||||
<dd>This class is a {@link android.view.View} where you can draw and manipulate objects using
|
||||
OpenGL API calls and is similar in function to a {@link android.view.SurfaceView}. You can use
|
||||
this class by creating an instance of {@link android.opengl.GLSurfaceView} and adding your
|
||||
{@link android.opengl.GLSurfaceView.Renderer Renderer} to it. However, if you want to capture
|
||||
touch screen events, you should extend the {@link android.opengl.GLSurfaceView} class to
|
||||
implement the touch listeners, as shown in the <a
|
||||
implement the touch listeners, as shown in OpenGL Tutorials for
|
||||
<a href="{@docRoot}resources/tutorials/opengl/opengl-es10.html#touch">ES 1.0</a>,
|
||||
<a href="{@docRoot}resources/tutorials/opengl/opengl-es20.html#touch">ES 2.0</a> and the <a
|
||||
href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/graphics/TouchRotateActivity
|
||||
.html">TouchRotateActivity</a> sample.</dd>
|
||||
|
||||
<dt>{@link android.opengl.GLSurfaceView.Renderer}</dt>
|
||||
<dt><strong>{@link android.opengl.GLSurfaceView.Renderer}</strong></dt>
|
||||
<dd>This interface defines the methods required for drawing graphics in an OpenGL {@link
|
||||
android.opengl.GLSurfaceView}. You must provide an implementation of this interface as a
|
||||
separate class and attach it to your {@link android.opengl.GLSurfaceView} instance using
|
||||
@@ -119,6 +135,7 @@ href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/graphics
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<h3 id="packages">OpenGL packages</h3>
|
||||
<p>Once you have established a container view for OpenGL using {@link
|
||||
android.opengl.GLSurfaceView} and {@link android.opengl.GLSurfaceView.Renderer}, you can begin
|
||||
calling OpenGL APIs using the following classes:</p>
|
||||
@@ -126,8 +143,17 @@ calling OpenGL APIs using the following classes:</p>
|
||||
<ul>
|
||||
<li>OpenGL ES 1.0/1.1 API Packages
|
||||
<ul>
|
||||
<li>{@link android.opengl} - This package provides a static interface to the OpenGL ES
|
||||
1.0/1.1 classes and better performance than the javax.microedition.khronos package interfaces.
|
||||
<ul>
|
||||
<li>{@link android.opengl.GLES10}</li>
|
||||
<li>{@link android.opengl.GLES10Ext}</li>
|
||||
<li>{@link android.opengl.GLES11}</li>
|
||||
<li>{@link android.opengl.GLES10Ext}</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>{@link javax.microedition.khronos.opengles} - This package provides the standard
|
||||
implementation of OpenGL ES 1.0 and 1.1.
|
||||
implementation of OpenGL ES 1.0/1.1.
|
||||
<ul>
|
||||
<li>{@link javax.microedition.khronos.opengles.GL10}</li>
|
||||
<li>{@link javax.microedition.khronos.opengles.GL10Ext}</li>
|
||||
@@ -136,42 +162,243 @@ implementation of OpenGL ES 1.0 and 1.1.
|
||||
<li>{@link javax.microedition.khronos.opengles.GL11ExtensionPack}</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>{@link android.opengl} - This package provides a static interface to the OpenGL classes
|
||||
above. These interfaces were added with Android 1.6 (API Level 4).
|
||||
<ul>
|
||||
<li>{@link android.opengl.GLES10}</li>
|
||||
<li>{@link android.opengl.GLES10Ext}</li>
|
||||
<li>{@link android.opengl.GLES11}</li>
|
||||
<li>{@link android.opengl.GLES10Ext}</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>OpenGL ES 2.0 API Class
|
||||
<ul>
|
||||
<li>{@link android.opengl.GLES20 android.opengl.GLES20}</li>
|
||||
<li>{@link android.opengl.GLES20 android.opengl.GLES20} - This package provides the
|
||||
interface to OpenGL ES 2.0 and is available starting with Android 2.2 (API Level 8).</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>If you'd like to start building an app with OpenGL right away, have a look at the tutorials for
|
||||
<a href="{@docRoot}resources/tutorials/opengl/opengl-es10.html">OpenGL ES 1.0</a> or
|
||||
<a href="{@docRoot}resources/tutorials/opengl/opengl-es20.html">OpenGL ES 2.0</a>!
|
||||
</p>
|
||||
|
||||
<h2 id="manifest">Declaring OpenGL Requirements</h2>
|
||||
<p>If your application uses OpenGL features that are not available on all devices, you must include
|
||||
these requirements in your <a
|
||||
href="{@docRoot}guide/topics/manifest/manifest-intro.html">AndroidManifest.xml</a></code> file.
|
||||
Here are the most common OpenGL manifest declarations:</p>
|
||||
|
||||
<ul>
|
||||
<li><strong>OpenGL ES version requirements</strong> - If your application only supports OpenGL ES
|
||||
2.0, you must declare that requirement by adding the following settings to your manifest as
|
||||
shown below.
|
||||
|
||||
<pre>
|
||||
<!-- Tell the system this app requires OpenGL ES 2.0. -->
|
||||
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
|
||||
</pre>
|
||||
|
||||
<p>Adding this declaration causes the Android Market to restrict your application from being
|
||||
installed on devices that do not support OpenGL ES 2.0.</p>
|
||||
</li>
|
||||
<li><strong>Texture compression requirements</strong> - If your application uses texture
|
||||
compression formats that are not supported by all devices, you must declare them in your manifest
|
||||
file using <a href="{@docRoot}guide/topics/manifest/supports-gl-texture-element.html">
|
||||
{@code <supports-gl-texture>}</a>. For more information about available texture compression
|
||||
formats, see <a href="#textures">Texture compression support</a>.
|
||||
|
||||
<p>Declaring texture compression requirements in your manifest hides your application from users
|
||||
with devices that do not support at least one of your declared compression types. For more
|
||||
information on how Android Market filtering works for texture compressions, see the <a
|
||||
href="{@docRoot}guide/topics/manifest/supports-gl-texture-element.html#market-texture-filtering">
|
||||
Android Market and texture compression filtering</a> section of the {@code
|
||||
<supports-gl-texture>} documentation.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2 id="coordinate-mapping">Coordinate Mapping for Drawn Objects</h2>
|
||||
|
||||
<p>One of the basic problems in displaying graphics on Android devices is that their screens can
|
||||
vary in size and shape. OpenGL assumes a square, uniform coordinate system and, by default, happily
|
||||
draws those coordinates onto your typically non-square screen as if it is perfectly square.</p>
|
||||
|
||||
<img src="{@docRoot}images/opengl/coordinates.png">
|
||||
<p class="img-caption">
|
||||
<strong>Figure 1.</strong> Default OpenGL coordinate system (left) mapped to a typical Android
|
||||
device screen (right).
|
||||
</p>
|
||||
|
||||
<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 camera views to
|
||||
transform coordinates so your graphic objects have the correct proportions on any display.</p>
|
||||
|
||||
<p>In order to apply projection and camera views, you create a projection matrix and a camera view
|
||||
matrix and apply them to the OpenGL rendering pipeline. The projection matrix recalculates the
|
||||
coordinates of your graphics so that they map correctly to Android device screens. The camera view
|
||||
matrix creates a transformation that renders objects from a specific eye position.</p>
|
||||
|
||||
<h3 id="proj-es1">Projection and camera view in OpenGL ES 1.0</h3>
|
||||
<p>In the ES 1.0 API, you apply projection and camera view by creating each matrix and then
|
||||
adding them to the OpenGL environment.</p>
|
||||
|
||||
<ol>
|
||||
<li><strong>Projection matrix</strong> - Create a projection matrix using the geometry of the
|
||||
device screen in order to recalculate object coordinates so they are drawn with correct proportions.
|
||||
The following example code demonstrates how to modify the {@code onSurfaceChanged()} method of a
|
||||
{@link android.opengl.GLSurfaceView.Renderer} implementation to create a projection matrix based on
|
||||
the screen's aspect ratio and apply it to the OpenGL rendering environment.
|
||||
|
||||
<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); // set matrix to projection mode
|
||||
gl.glLoadIdentity(); // reset the matrix to its default state
|
||||
gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7); // apply the projection matrix
|
||||
}
|
||||
</pre>
|
||||
</li>
|
||||
|
||||
<li><strong>Camera transformation matrix</strong> - Once you have adjusted the coordinate system
|
||||
using a projection matrix, you must also apply a camera view. The following example code shows how
|
||||
to modify the {@code onDrawFrame()} method of a {@link android.opengl.GLSurfaceView.Renderer}
|
||||
implementation to apply a model view and use the {@link
|
||||
android.opengl.GLU#gluLookAt(javax.microedition.khronos.opengles.GL10, float, float, float, float,
|
||||
float, float, float, float, float) GLU.gluLookAt()} utility to create a viewing tranformation which
|
||||
simulates a camera position.
|
||||
|
||||
<pre>
|
||||
public void onDrawFrame(GL10 gl) {
|
||||
...
|
||||
// Set GL_MODELVIEW transformation mode
|
||||
gl.glMatrixMode(GL10.GL_MODELVIEW);
|
||||
gl.glLoadIdentity(); // reset the matrix to its default state
|
||||
|
||||
// When using GL_MODELVIEW, you must set the camera view
|
||||
GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<p>For a complete example of how to apply projection and camera views with OpenGL ES 1.0, see the <a
|
||||
href="{@docRoot}resources/tutorials/opengl/opengl-es10.html#projection-and-views">OpenGL ES 1.0
|
||||
tutorial</a>.</p>
|
||||
|
||||
|
||||
<h3 id="proj-es2">Projection and camera view in OpenGL ES 2.0</h3>
|
||||
<p>In the ES 2.0 API, you apply projection and camera view by first adding a matrix member to
|
||||
the vertex shaders of your graphics objects. With this matrix member added, you can then
|
||||
generate and apply projection and camera viewing matrices to your objects.</p>
|
||||
|
||||
<ol>
|
||||
<li><strong>Add matrix to vertex shaders</strong> - Create a variable for the view projection matrix
|
||||
and include it as a multiplier of the shader's position. In the following example vertex shader
|
||||
code, the included {@code uMVPMatrix} member allows you to apply projection and camera viewing
|
||||
matrices to the coordinates of objects that use this shader.
|
||||
|
||||
<pre>
|
||||
private final String vertexShaderCode =
|
||||
|
||||
// This matrix member variable provides a hook to manipulate
|
||||
// the coordinates of objects that use this vertex shader
|
||||
"uniform mat4 uMVPMatrix; \n" +
|
||||
|
||||
"attribute vec4 vPosition; \n" +
|
||||
"void main(){ \n" +
|
||||
|
||||
// the matrix must be included as part of gl_Position
|
||||
" gl_Position = uMVPMatrix * vPosition; \n" +
|
||||
|
||||
"} \n";
|
||||
</pre>
|
||||
<p class="note"><strong>Note:</strong> The example above defines a single transformation matrix
|
||||
member in the vertex shader into which you apply a combined projection matrix and camera view
|
||||
matrix. Depending on your application requirements, you may want to define separate projection
|
||||
matrix and camera viewing matrix members in your vertex shaders so you can change them
|
||||
independently.</p>
|
||||
</li>
|
||||
<li><strong>Access the shader matrix</strong> - After creating a hook in your vertex shaders to
|
||||
apply projection and camera view, you can then access that variable to apply projection and
|
||||
camera viewing matrices. The following code shows how to modify the {@code onSurfaceCreated()}
|
||||
method of a {@link android.opengl.GLSurfaceView.Renderer} implementation to access the matrix
|
||||
variable defined in the vertex shader above.
|
||||
|
||||
<pre>
|
||||
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
|
||||
...
|
||||
muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
</li>
|
||||
<li><strong>Create projection and camera viewing matrices</strong> - Generate the projection and
|
||||
viewing matrices to be applied the graphic objects. The following example code shows how to modify
|
||||
the {@code onSurfaceCreated()} and {@code onSurfaceChanged()} methods of a {@link
|
||||
android.opengl.GLSurfaceView.Renderer} implementation to create camera view matrix and a projection
|
||||
matrix based on the screen aspect ratio of the device.
|
||||
|
||||
<pre>
|
||||
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
|
||||
...
|
||||
// Create a camera view matrix
|
||||
Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
public void onSurfaceChanged(GL10 unused, int width, int height) {
|
||||
GLES20.glViewport(0, 0, width, height);
|
||||
|
||||
float ratio = (float) width / height;
|
||||
|
||||
// create a projection matrix from device screen geometry
|
||||
Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
|
||||
}
|
||||
</pre>
|
||||
</li>
|
||||
|
||||
<li><strong>Apply projection and camera viewing matrices</strong> - To apply the projection and
|
||||
camera view transformations, multiply the matrices together and then set them into the vertex
|
||||
shader. The following example code shows how modify the {@code onDrawFrame()} method of a {@link
|
||||
android.opengl.GLSurfaceView.Renderer} implementation to combine the projection matrix and camera
|
||||
view created in the code above and then apply it to the graphic objects to be rendered by OpenGL.
|
||||
|
||||
<pre>
|
||||
public void onDrawFrame(GL10 unused) {
|
||||
...
|
||||
// Combine the projection and camera view matrices
|
||||
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
|
||||
|
||||
// Apply the combined projection and camera view transformations
|
||||
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
|
||||
|
||||
// Draw objects
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
</li>
|
||||
</ol>
|
||||
<p>For a complete example of how to apply projection and camera view with OpenGL ES 2.0, see the <a
|
||||
href="{@docRoot}resources/tutorials/opengl/opengl-es20.html#projection-and-views">OpenGL ES 2.0
|
||||
tutorial</a>.</p>
|
||||
|
||||
|
||||
<h2 id="compatibility">OpenGL Versions and Device Compatibility</h2>
|
||||
|
||||
<p>
|
||||
The OpenGL ES 1.0 and 1.1 API specifications have been supported since Android 1.0.
|
||||
<p>The OpenGL ES 1.0 and 1.1 API specifications have been supported since Android 1.0.
|
||||
Beginning with Android 2.2 (API Level 8), the framework supports the OpenGL ES 2.0 API
|
||||
specification. OpenGL ES 2.0 is supported by most Android devices and is recommended for new
|
||||
applications being developed with OpenGL. For information about the relative number of
|
||||
Android-powered devices that support a given version of OpenGL ES, see the <a
|
||||
href="{@docRoot}resources/dashboard/opengl.html">OpenGL ES Versions Dashboard</a>.</p>
|
||||
|
||||
|
||||
<h3 id="textures">Texture compression support</h3>
|
||||
<p>Texture compression can significantly increase the performance of your OpenGL application by
|
||||
reducing memory requirements and making more efficient use of memory bandwidth. The Android
|
||||
framework provides support for the ETC1 compression format as a standard feature, including a {@link
|
||||
android.opengl.ETC1Util} utility class and the {@code etc1tool} compression tool (located in your
|
||||
Android SDK at {@code <sdk>/tools/}).</p>
|
||||
|
||||
<p>For an example of an Android application that uses texture compression, see the <a
|
||||
android.opengl.ETC1Util} utility class and the {@code etc1tool} compression tool (located in the
|
||||
Android SDK at {@code <sdk>/tools/}). For an example of an Android application that uses
|
||||
texture compression, see the <a
|
||||
href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/graphics/
|
||||
CompressedTextureActivity.html">CompressedTextureActivity</a> code sample.
|
||||
</p>
|
||||
@@ -184,34 +411,110 @@ alpha channel. If your application requires textures with an alpha channel, you
|
||||
investigate other texture compression formats available on your target devices.</p>
|
||||
|
||||
<p>Beyond the ETC1 format, Android devices have varied support for texture compression based on
|
||||
their GPU chipsets. You should investigate texture compression support on the the devices you are
|
||||
are targeting to determine what compression types your application should support.</p>
|
||||
their GPU chipsets and OpenGL implementations. You should investigate texture compression support on
|
||||
the the devices you are are targeting to determine what compression types your application should
|
||||
support. In order to determine what texture formats are supported on a given device, you must <a
|
||||
href="#gl-extension-query">query the device</a> and review the <em>OpenGL extension names</em>,
|
||||
which identify what texture compression formats (and other OpenGL features) are supported by the
|
||||
device. Some commonly supported texture compression formats are as follows:</p>
|
||||
|
||||
<p>To determine if texture compression formats other than ETC1 are supported on a particular
|
||||
device:</p>
|
||||
<ul>
|
||||
<li><strong>ATITC (ATC)</strong> - ATI texture compression (ATITC or ATC) is available on a
|
||||
wide variety of devices and supports fixed rate compression for RGB textures with and without
|
||||
an alpha channel. This format may be represented by several OpenGL extension names, for example:
|
||||
<ul>
|
||||
<li>{@code GL_AMD_compressed_ATC_texture}</li>
|
||||
<li>{@code GL_ATI_texture_compression_atitc}</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>PVRTC</strong> - PowerVR texture compression (PVRTC) is available on a wide
|
||||
variety of devices and supports 2-bit and 4-bit per pixel textures with or without an alpha channel.
|
||||
This format is represented by the following OpenGL extension name:
|
||||
<ul>
|
||||
<li>{@code GL_IMG_texture_compression_pvrtc}</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>S3TC (DXT<em>n</em>/DXTC)</strong> - S3 texture compression (S3TC) has several
|
||||
format variations (DXT1 to DXT5) and is less widely available. The format supports RGB textures with
|
||||
4-bit alpha or 8-bit alpha channels. This format may be represented by several OpenGL extension
|
||||
names, for example:
|
||||
<ul>
|
||||
<li>{@code GL_OES_texture_compression_S3TC}</li>
|
||||
<li>{@code GL_EXT_texture_compression_s3tc}</li>
|
||||
<li>{@code GL_EXT_texture_compression_dxt1}</li>
|
||||
<li>{@code GL_EXT_texture_compression_dxt3}</li>
|
||||
<li>{@code GL_EXT_texture_compression_dxt5}</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>3DC</strong> - 3DC texture compression (3DC) is a less widely available format that
|
||||
supports RGB textures with an an alpha channel. This format is represented by the following OpenGL
|
||||
extension name:</li>
|
||||
<ul>
|
||||
<li>{@code GL_AMD_compressed_3DC_texture}</li>
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
<p class="warning"><strong>Warning:</strong> These texture compression formats are <em>not
|
||||
supported</em> on all devices. Support for these formats can vary by manufacturer and device. For
|
||||
information on how to determine what texture compression formats are on a particular device, see
|
||||
the next section.
|
||||
</p>
|
||||
|
||||
<p class="note"><strong>Note:</strong> Once you decide which texture compression formats your
|
||||
application will support, make sure you declare them in your manifest using <a
|
||||
href="{@docRoot}guide/topics/manifest/supports-gl-texture-element.html"><supports-gl-texture>
|
||||
</a>. Using this declaration enables filtering by external services such as Android Market, so that
|
||||
your app is installed only on devices that support the formats your app requires. For details, see
|
||||
<a
|
||||
href="{@docRoot}guide/topics/graphics/opengl.html#manifest">OpenGL manifest declarations</a>.</p>
|
||||
|
||||
<h3 id="gl-extension-query">Determining OpenGL extensions</h3>
|
||||
<p>Implementations of OpenGL vary by Android device in terms of the extensions to the OpenGL ES API
|
||||
that are supported. These extensions include texture compressions, but typically also include other
|
||||
extensions to the OpenGL feature set.</p>
|
||||
|
||||
<p>To determine what texture compression formats, and other OpenGL extensions, are supported on a
|
||||
particular device:</p>
|
||||
<ol>
|
||||
<li>Run the following code on your target devices to determine what texture compression
|
||||
formats are supported:
|
||||
<pre>
|
||||
String extensions = javax.microedition.khronos.opengles.GL10.glGetString(GL10.GL_EXTENSIONS);
|
||||
</pre>
|
||||
<p class="warning"><b>Warning:</b> The results of this call vary by device! You must run this
|
||||
call on several target devices to determine what compression types are commonly supported on
|
||||
your target devices.</p>
|
||||
<p class="warning"><b>Warning:</b> The results of this call <em>vary by device!</em> You
|
||||
must run this call on several target devices to determine what compression types are commonly
|
||||
supported.</p>
|
||||
</li>
|
||||
<li>Review the output of this method to determine what extensions are supported on the
|
||||
<li>Review the output of this method to determine what OpenGL extensions are supported on the
|
||||
device.</li>
|
||||
</ol>
|
||||
|
||||
|
||||
<h3 id="declare-compression">Declaring compressed textures</h3>
|
||||
<p>Once you have decided which texture compression types your application will support, you
|
||||
must declare them in your manifest file using <a
|
||||
href="{@docRoot}guide/topics/manifest/supports-gl-texture-element.html">
|
||||
<supports-gl-texture></a>. Declaring this information in your manifest file hides your
|
||||
application from users with devices that do not support at least one of your declared
|
||||
compression types. For more information on how Android Market filtering works for texture
|
||||
compressions, see the <a
|
||||
href="{@docRoot}guide/topics/manifest/supports-gl-texture-element.html#market-texture-filtering">
|
||||
Android Market and texture compression filtering</a> section of the {@code
|
||||
<supports-gl-texture>} documentation.
|
||||
<h2 id="choosing-version">Choosing an OpenGL API Version</h2>
|
||||
|
||||
<p>OpenGL ES API version 1.0 (and the 1.1 extensions) and version 2.0 both provide high
|
||||
performance graphics interfaces for creating 3D games, visualizations and user interfaces. Graphics
|
||||
programming for the OpenGL ES 1.0/1.1 API versus ES 2.0 differs significantly, and so developers
|
||||
should carefully consider the following factors before starting development with either API:</p>
|
||||
|
||||
<ul>
|
||||
<li><strong>Performance</strong> - In general, OpenGL ES 2.0 provides faster graphics performance
|
||||
than the ES 1.0/1.1 APIs. However, the performance difference can vary depending on the Android
|
||||
device your OpenGL application is running on, due to differences in the implementation of the OpenGL
|
||||
graphics pipeline.</li>
|
||||
<li><strong>Device Compatibility</strong> - Developers should consider the types of devices,
|
||||
Android versions and the OpenGL ES versions available to their customers. For more information
|
||||
on OpenGL compatibility across devices, see the <a href="#compatibility">OpenGL Versions and Device
|
||||
Compatibility</a> section.</li>
|
||||
<li><strong>Coding Convenience</strong> - The OpenGL ES 1.0/1.1 API provides a fixed function
|
||||
pipeline and convenience functions which are not available in the ES 2.0 API. Developers who are new
|
||||
to OpenGL may find coding for OpenGL ES 1.0/1.1 faster and more convenient.</li>
|
||||
<li><strong>Graphics Control</strong> - The OpenGL ES 2.0 API provides a higher degree
|
||||
of control by providing a fully programmable pipeline through the use of shaders. With more
|
||||
direct control of the graphics processing pipeline, developers can create effects that would be
|
||||
very difficult to generate using the 1.0/1.1 API.</li>
|
||||
</ul>
|
||||
|
||||
<p>While performance, compatibility, convenience, control and other factors may influence your
|
||||
decision, you should pick an OpenGL API version based on what you think provides the best experience
|
||||
for your users.</p>
|
||||
|
||||
BIN
docs/html/images/opengl/coordinates.png
Normal file
BIN
docs/html/images/opengl/coordinates.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
docs/html/images/opengl/helloopengl-es10-1.png
Normal file
BIN
docs/html/images/opengl/helloopengl-es10-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.3 KiB |
BIN
docs/html/images/opengl/helloopengl-es10-2.png
Normal file
BIN
docs/html/images/opengl/helloopengl-es10-2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.1 KiB |
BIN
docs/html/images/opengl/helloopengl-es20-1.png
Normal file
BIN
docs/html/images/opengl/helloopengl-es20-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.8 KiB |
BIN
docs/html/images/opengl/helloopengl-es20-2.png
Normal file
BIN
docs/html/images/opengl/helloopengl-es20-2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
@@ -781,6 +781,26 @@ 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: '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: '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',
|
||||
|
||||
532
docs/html/resources/tutorials/opengl/opengl-es10.jd
Normal file
532
docs/html/resources/tutorials/opengl/opengl-es10.jd
Normal file
@@ -0,0 +1,532 @@
|
||||
page.title=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">Create an Activity with GLSurfaceView</a></li>
|
||||
<li>
|
||||
<a href="#drawing">Draw a Shape on GLSurfaceView</a>
|
||||
<ol>
|
||||
<li><a href="#define-triangle">Define a Triangle</a></li>
|
||||
<li><a href="#draw-triangle">Draw the Triangle</a></li>
|
||||
</ol>
|
||||
</li>
|
||||
<li><a href="#projection-and-views">Apply Projection and Camera Views</a></li>
|
||||
<li><a href="#motion">Add Motion</a></li>
|
||||
<li><a href="#touch">Respond to Touch Events</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">OpenGL ES 1.0 Sample</a></li>
|
||||
<li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/graphics/
|
||||
TouchRotateActivity.html">TouchRotateActivity</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">OpenGL
|
||||
ES 2.0</a></li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>This tutorial shows you how to create a simple Android application that uses the OpenGL ES 1.0
|
||||
API to perform some basic graphics operations. You'll learn how to:</p>
|
||||
|
||||
<ul>
|
||||
<li>Create an activity using {@link android.opengl.GLSurfaceView} and {@link
|
||||
android.opengl.GLSurfaceView.Renderer}</li>
|
||||
<li>Create and draw a graphic object</li>
|
||||
<li>Define a projection to correct for screen geometry</li>
|
||||
<li>Define a camera view</li>
|
||||
<li>Rotate a graphic object</li>
|
||||
<li>Make graphics touch-interactive</li>
|
||||
</ul>
|
||||
|
||||
<p>The Android framework supports both the OpenGL ES 1.0/1.1 and OpenGL ES 2.0 APIs. You should
|
||||
carefully consider which version of the OpenGL ES API (1.0/1.1 or 2.0) is most appropriate for your
|
||||
needs. For more information, see
|
||||
<a href="{@docRoot}guide/topics/graphics/opengl.html#choosing-version">Choosing an OpenGL API
|
||||
Version</a>. If you would prefer to use OpenGL ES 2.0, see the <a
|
||||
href="{@docRoot}resources/tutorials/opengl/opengl-es20.jd">OpenGL ES 2.0 tutorial</a>.</p>
|
||||
|
||||
<p>Before you start, you should understand how to create a basic Android application. If you do not
|
||||
know how to create an app, follow the <a href="{@docRoot}resources/tutorials/hello-world.html">Hello
|
||||
World Tutorial</a> to familiarize yourself with the process.</p>
|
||||
|
||||
<h2 id="creating">Create an Activity with GLSurfaceView</h2>
|
||||
|
||||
<p>To get started using OpenGL, 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 applications that use OpenGL 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 activity using {@code GLSurfaceView}:</p>
|
||||
|
||||
<ol>
|
||||
<li>Start a new Android project that targets Android 1.6 (API Level 4) or higher.
|
||||
</li>
|
||||
<li>Name the project <strong>HelloOpenGLES10</strong> and make sure it includes an activity called
|
||||
{@code HelloOpenGLES10}.
|
||||
</li>
|
||||
<li>Modify the {@code HelloOpenGLES10} 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;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Create a GLSurfaceView instance and set it
|
||||
// as the ContentView for this Activity.
|
||||
mGLView = new HelloOpenGLES10SurfaceView(this);
|
||||
setContentView(mGLView);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
// The following call pauses the rendering thread.
|
||||
// If your OpenGL application is memory intensive,
|
||||
// you should consider de-allocating objects that
|
||||
// consume significant memory here.
|
||||
mGLView.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
// The following call resumes a paused rendering thread.
|
||||
// If you de-allocated graphic objects for onPause()
|
||||
// this is a good place to re-allocate them.
|
||||
mGLView.onResume();
|
||||
}
|
||||
}
|
||||
|
||||
class HelloOpenGLES10SurfaceView extends GLSurfaceView {
|
||||
|
||||
public HelloOpenGLES10SurfaceView(Context context){
|
||||
super(context);
|
||||
|
||||
// Set the Renderer for drawing on the GLSurfaceView
|
||||
setRenderer(new HelloOpenGLES10Renderer());
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
<p class="note"><strong>Note:</strong> You will get a compile error for the {@code
|
||||
HelloOpenGLES10Renderer} class reference. That's expected; you will fix this error in the next step.
|
||||
</p>
|
||||
|
||||
<p>As shown above, this activity uses a single {@link android.opengl.GLSurfaceView} for its
|
||||
view. Notice that this activity implements crucial lifecycle callbacks for pausing and resuming its
|
||||
work.</p>
|
||||
|
||||
<p>The {@code HelloOpenGLES10SurfaceView} class in this example code above is just a thin wrapper
|
||||
for an instance of {@link android.opengl.GLSurfaceView} and is not strictly necessary for this
|
||||
example. However, if you want your application to monitor and respond to touch screen
|
||||
events—and we are guessing you do—you must extend {@link android.opengl.GLSurfaceView}
|
||||
to add touch event listeners, which you will learn how to do in the <a href="#touch">Reponding to
|
||||
Touch Events</a> section.</p>
|
||||
|
||||
<p>In order to draw graphics in the {@link android.opengl.GLSurfaceView}, you must define an
|
||||
implementation of {@link android.opengl.GLSurfaceView.Renderer}. In the next step, you create
|
||||
a renderer class to complete this OpenGL application.</p>
|
||||
</li>
|
||||
|
||||
<li>Create a new file for the following class {@code HelloOpenGLES10Renderer}, 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>
|
||||
<p>This minimal implementation of {@link android.opengl.GLSurfaceView.Renderer} provides the
|
||||
code structure needed to use OpenGL drawing methods:
|
||||
<ul>
|
||||
<li>{@link
|
||||
android.opengl.GLSurfaceView.Renderer#onSurfaceCreated(javax.microedition.khronos.opengles.GL10,
|
||||
javax.microedition.khronos.egl.EGLConfig) onSurfaceCreated()} is called once to set up the
|
||||
{@link android.opengl.GLSurfaceView}
|
||||
environment.</li>
|
||||
<li>{@link
|
||||
android.opengl.GLSurfaceView.Renderer#onDrawFrame(javax.microedition.khronos.opengles.GL10)
|
||||
onDrawFrame()} is called for each redraw of the {@link
|
||||
android.opengl.GLSurfaceView}.</li>
|
||||
<li>{@link
|
||||
android.opengl.GLSurfaceView.Renderer#onSurfaceChanged(javax.microedition.khronos.opengles.GL10,
|
||||
int, int) onSurfaceChanged()} is called if the geometry of the {@link
|
||||
android.opengl.GLSurfaceView} changes, for example when the device's screen orientation
|
||||
changes.</li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>For more information about these methods, see the <a
|
||||
href="{@docRoot}guide/topics/graphics/opengl.html">3D with OpenGL</a> document.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<p>The code example above creates a simple Android application that displays a grey screen using
|
||||
OpenGL ES 1.0 calls. While this application does not do anything very interesting, by creating these
|
||||
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 classes should give you enough information
|
||||
to use the OpenGL ES 1.0 API and create graphics. However, if you need a bit more help getting
|
||||
started with OpenGL, head on to the next sections for a few more hints.</p>
|
||||
|
||||
<h2 id="drawing">Draw a Shape on GLSurfaceView</h2>
|
||||
|
||||
<p>Once you have implemented a {@link android.opengl.GLSurfaceView.Renderer}, the next step is to
|
||||
draw something with it. This section shows you how to define and draw a triangle.</p>
|
||||
|
||||
<h3 id="define-triangle">Define 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} 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()} 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());// use the device hardware's native byte order
|
||||
triangleVB = vbb.asFloatBuffer(); // create a floating point buffer from the ByteBuffer
|
||||
triangleVB.put(triangleCoords); // add the coordinates to the FloatBuffer
|
||||
triangleVB.position(0); // set the buffer to read the first coordinate
|
||||
|
||||
}
|
||||
</pre>
|
||||
<p>This method defines a two-dimensional triangle with three equal sides.</p>
|
||||
</li>
|
||||
<li>Modify your {@code onSurfaceCreated()} 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="caution"><strong>Caution:</strong> Shapes and other static objects should be initialized
|
||||
once in your {@code onSurfaceCreated()} method for best performance. Avoid initializing the
|
||||
new objects in {@code onDrawFrame()}, as this causes the system to re-create the objects
|
||||
for every frame redraw and slows down your application.
|
||||
</p>
|
||||
</li>
|
||||
|
||||
</ol>
|
||||
|
||||
<p>You have now defined a triangle shape, but if you run the application, nothing appears. What?!
|
||||
You also have to tell OpenGL to draw the triangle, which you'll do in the next section.
|
||||
</p>
|
||||
|
||||
|
||||
<h3 id="draw-triangle">Draw the Triangle</h3>
|
||||
|
||||
<p>Before you can draw your triangle, you must tell OpenGL that you are using vertex arrays. After
|
||||
that setup step, you can call the drawing APIs to display the triangle.</p>
|
||||
|
||||
<p>To draw the triangle:</p>
|
||||
|
||||
<ol>
|
||||
<li>Add the {@code glEnableClientState()} method to the end of {@code onSurfaceCreated()} to
|
||||
enable vertex arrays.
|
||||
<pre>
|
||||
// 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 view.</p>
|
||||
</li>
|
||||
|
||||
<li>Add the following code to the end of your {@code onDrawFrame()} method to draw the triangle.
|
||||
<pre>
|
||||
// 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>
|
||||
</li>
|
||||
<li id="squashed-triangle">Run the app! Your application should look something like this:
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<img src="{@docRoot}images/opengl/helloopengl-es10-1.png">
|
||||
<p class="img-caption">
|
||||
<strong>Figure 1.</strong> Triangle drawn without a projection or camera view.
|
||||
</p>
|
||||
|
||||
<p>There are a few problems with this example. First of all, it is not going to impress your
|
||||
friends. Secondly, the triangle is a bit squashed and changes shape when you change the screen
|
||||
orientation of the 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. You'll fix that problem using a projection
|
||||
and camera view in the next section.</p>
|
||||
|
||||
<p>Lastly, because the triangle is stationary, the system is redrawing the object repeatedly in
|
||||
exactly the same place, which is not the most efficient use of the OpenGL graphics pipeline. In the
|
||||
<a href="#motion">Add Motion</a> section, you'll make this shape rotate and justify
|
||||
this use of processing power.</p>
|
||||
|
||||
<h2 id="projection-and-views">Apply Projection and Camera View</h2>
|
||||
|
||||
<p>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. To solve this problem, you can apply an OpenGL
|
||||
projection mode and camera view (eye point) to transform the coordinates of your graphic objects
|
||||
so they have the correct proportions on any display. For more information about OpenGL coordinate
|
||||
mapping, see <a href="{@docRoot}guide/topics/graphics/opengl.html#coordinate-mapping">Coordinate
|
||||
Mapping for Drawn Objects</a>.</p>
|
||||
|
||||
<p>To apply projection and camera view transformations to your triangle:
|
||||
</p>
|
||||
<ol>
|
||||
<li>Modify your {@code 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.
|
||||
<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); // set matrix to projection mode
|
||||
gl.glLoadIdentity(); // reset the matrix to its default state
|
||||
gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7); // apply the projection matrix
|
||||
}
|
||||
</pre>
|
||||
</li>
|
||||
|
||||
<li>Next, modify your {@code onDrawFrame()} method to apply the {@link
|
||||
javax.microedition.khronos.opengles.GL10#GL_MODELVIEW GL_MODELVIEW} mode and set
|
||||
a view point 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(); // reset the matrix to its default state
|
||||
|
||||
// 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>
|
||||
<li>Run the updated application and you should see something like this:</li>
|
||||
</ol>
|
||||
|
||||
<img src="{@docRoot}images/opengl/helloopengl-es10-2.png">
|
||||
<p class="img-caption">
|
||||
<strong>Figure 2.</strong> Triangle drawn with a projection and camera view applied.
|
||||
</p>
|
||||
|
||||
<p>Now that you have applied this transformation, the triangle has three equal sides, instead of the
|
||||
<a href="#squashed-triangle">squashed triangle</a> in the earlier version.</p>
|
||||
|
||||
<h2 id="motion">Add Motion</h2>
|
||||
|
||||
<p>While it may be an interesting exercise to create static graphic objects with OpenGL ES, chances
|
||||
are you want at least <em>some</em> of your objects to move. In this section, you'll add motion to
|
||||
your triangle by rotating it.</p>
|
||||
|
||||
<p>To add rotation to your triangle:</p>
|
||||
<ol>
|
||||
<li>Modify your {@code onDrawFrame()} 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>
|
||||
<li>Run the application and your triangle should rotate around its center.</li>
|
||||
</ol>
|
||||
|
||||
|
||||
<h2 id="touch">Respond to Touch Events</h2>
|
||||
<p>Making objects move according to a preset program like the rotating triangle is useful for
|
||||
getting some attention, but what if you want to have users interact with your OpenGL graphics? In
|
||||
this section, you'll learn how listen for touch events to let users interact with objects in your
|
||||
{@code HelloOpenGLES10SurfaceView}.</p>
|
||||
|
||||
<p>The key to making your OpenGL application touch interactive is expanding your implementation of
|
||||
{@link android.opengl.GLSurfaceView} to override the {@link
|
||||
android.view.View#onTouchEvent(android.view.MotionEvent) onTouchEvent()} to listen for touch events.
|
||||
Before you do that, however, you'll modify the renderer class to expose the rotation angle of the
|
||||
triangle. Afterwards, you'll modify the {@code HelloOpenGLES10SurfaceView} to process touch events
|
||||
and pass that data to your renderer.</p>
|
||||
|
||||
<p>To make your triangle rotate in response to touch events:</p>
|
||||
|
||||
<ol>
|
||||
<li>Modify your {@code HelloOpenGLES10Renderer} class to include a new, public member so that
|
||||
your {@code HelloOpenGLES10SurfaceView} class is able to pass new rotation values your renderer:
|
||||
<pre>
|
||||
public float mAngle;
|
||||
</pre>
|
||||
</li>
|
||||
<li>In your {@code onDrawFrame()} method, comment out the code that generates an angle and
|
||||
replace the {@code angle} variable with {@code mAngle}.
|
||||
<pre>
|
||||
// Create a rotation for the triangle (Boring! Comment this out:)
|
||||
// long time = SystemClock.uptimeMillis() % 4000L;
|
||||
// float angle = 0.090f * ((int) time);
|
||||
|
||||
// Use the mAngle member as the rotation value
|
||||
gl.glRotatef(mAngle, 0.0f, 0.0f, 1.0f);
|
||||
</pre>
|
||||
</li>
|
||||
<li>In your {@code HelloOpenGLES10SurfaceView} class, add the following member variables.
|
||||
<pre>
|
||||
private final float TOUCH_SCALE_FACTOR = 180.0f / 320;
|
||||
private HelloOpenGLES10Renderer mRenderer;
|
||||
private float mPreviousX;
|
||||
private float mPreviousY;
|
||||
</pre>
|
||||
</li>
|
||||
<li>In the constructor method for {@code HelloOpenGLES10SurfaceView}, set the {@code mRenderer}
|
||||
member so you have a handle to pass in rotation input and set the render mode to {@link
|
||||
android.opengl.GLSurfaceView#RENDERMODE_WHEN_DIRTY}.
|
||||
<pre>
|
||||
public HelloOpenGLES10SurfaceView(Context context){
|
||||
super(context);
|
||||
// set the mRenderer member
|
||||
mRenderer = new HelloOpenGLES10Renderer();
|
||||
setRenderer(mRenderer);
|
||||
|
||||
// Render the view only when there is a change
|
||||
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
|
||||
}
|
||||
</pre>
|
||||
</li>
|
||||
<li>In your {@code HelloOpenGLES10SurfaceView} class, override the {@link
|
||||
android.view.View#onTouchEvent(android.view.MotionEvent) onTouchEvent()} method to listen for touch
|
||||
events and pass them to your renderer.
|
||||
<pre>
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent e) {
|
||||
// MotionEvent reports input details from the touch screen
|
||||
// and other input controls. In this case, you are only
|
||||
// interested in events where the touch position changed.
|
||||
|
||||
float x = e.getX();
|
||||
float y = e.getY();
|
||||
|
||||
switch (e.getAction()) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
|
||||
float dx = x - mPreviousX;
|
||||
float dy = y - mPreviousY;
|
||||
|
||||
// reverse direction of rotation above the mid-line
|
||||
if (y > getHeight() / 2) {
|
||||
dx = dx * -1 ;
|
||||
}
|
||||
|
||||
// reverse direction of rotation to left of the mid-line
|
||||
if (x < getWidth() / 2) {
|
||||
dy = dy * -1 ;
|
||||
}
|
||||
|
||||
mRenderer.mAngle += (dx + dy) * TOUCH_SCALE_FACTOR;
|
||||
requestRender();
|
||||
}
|
||||
|
||||
mPreviousX = x;
|
||||
mPreviousY = y;
|
||||
return true;
|
||||
}
|
||||
</pre>
|
||||
<p class="note"><strong>Note:</strong> Touch events return pixel coordinates which <em>are not the
|
||||
same</em> as OpenGL coordinates. Touch coordinate [0,0] is the bottom-left of the screen and the
|
||||
highest value [max_X, max_Y] is the top-right corner of the screen. To match touch events to OpenGL
|
||||
graphic objects, you must translate touch coordinates into OpenGL coordinates.</p>
|
||||
</li>
|
||||
<li>Run the application and drag your finger or cursor around the screen to rotate the
|
||||
triangle.</li>
|
||||
</ol>
|
||||
<p>For another example of OpenGL touch event functionality, see <a
|
||||
href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/graphics/
|
||||
TouchRotateActivity.html">TouchRotateActivity</a>.</p>
|
||||
652
docs/html/resources/tutorials/opengl/opengl-es20.jd
Normal file
652
docs/html/resources/tutorials/opengl/opengl-es20.jd
Normal file
@@ -0,0 +1,652 @@
|
||||
page.title=OpenGL ES 2.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">Create an Activity with GLSurfaceView</a></li>
|
||||
<li>
|
||||
<a href="#drawing">Draw a Shape on GLSurfaceView</a>
|
||||
<ol>
|
||||
<li><a href="#define-triangle">Define a Triangle</a></li>
|
||||
<li><a href="#draw-triangle">Draw the Triangle</a></li>
|
||||
</ol>
|
||||
</li>
|
||||
<li><a href="#projection-and-views">Apply Projection and Camera Views</a></li>
|
||||
<li><a href="#motion">Add Motion</a></li>
|
||||
<li><a href="#touch">Respond to Touch Events</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 Sample</a></li>
|
||||
<li><a href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/graphics/
|
||||
TouchRotateActivity.html">TouchRotateActivity</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">OpenGL
|
||||
ES 1.0</a></li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>This tutorial shows you how to create a simple Android application that uses the OpenGL ES 2.0
|
||||
API to perform some basic graphics operations. You'll learn how to:</p>
|
||||
|
||||
<ul>
|
||||
<li>Create an activity using {@link android.opengl.GLSurfaceView} and {@link
|
||||
android.opengl.GLSurfaceView.Renderer}</li>
|
||||
<li>Create and draw a graphic object</li>
|
||||
<li>Define a projection to correct for screen geometry</li>
|
||||
<li>Define a camera view</li>
|
||||
<li>Rotate a graphic object</li>
|
||||
<li>Make graphics touch interactive</li>
|
||||
</ul>
|
||||
|
||||
<p>The Android framework supports both the OpenGL ES 1.0/1.1 and OpenGL ES 2.0 APIs. You should
|
||||
carefully consider which version of the OpenGL ES API (1.0/1.1 or 2.0) is most appropriate for your
|
||||
needs. For more information, see
|
||||
<a href="{@docRoot}guide/topics/graphics/opengl.html#choosing-version">Choosing an OpenGL API
|
||||
Version</a>. If you would prefer to use OpenGL ES 1.0, see the <a
|
||||
href="{@docRoot}resources/tutorials/opengl/opengl-es10.jd">OpenGL ES 1.0 tutorial</a>.</p>
|
||||
|
||||
<p>Before you start, you should understand how to create a basic Android application. If you do not
|
||||
know how to create an app, follow the <a href="{@docRoot}resources/tutorials/hello-world.html">Hello
|
||||
World Tutorial</a> to familiarize yourself with the process.</p>
|
||||
|
||||
<p class="caution"><strong>Caution:</strong> OpenGL ES 2.0 <em>is currently not supported</em> by
|
||||
the Android Emulator. You must have a physical test device running Android 2.2 (API Level 8) or
|
||||
higher in order to run and test the example code in this tutorial.</p>
|
||||
|
||||
<h2 id="creating">Create an Activity with GLSurfaceView</h2>
|
||||
|
||||
<p>To get started using OpenGL, 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 applications that use OpenGL 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 activity using {@code GLSurfaceView}:</p>
|
||||
|
||||
<ol>
|
||||
<li>Start a new Android project that targets Android 2.2 (API Level 8) or higher.
|
||||
</li>
|
||||
<li>Name the project <strong>HelloOpenGLES20</strong> and make sure it includes an activity called
|
||||
{@code HelloOpenGLES20}.
|
||||
</li>
|
||||
<li>Modify the {@code HelloOpenGLES20} 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;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Create a GLSurfaceView instance and set it
|
||||
// as the ContentView for this Activity
|
||||
mGLView = new HelloOpenGLES20SurfaceView(this);
|
||||
setContentView(mGLView);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
// The following call pauses the rendering thread.
|
||||
// If your OpenGL application is memory intensive,
|
||||
// you should consider de-allocating objects that
|
||||
// consume significant memory here.
|
||||
mGLView.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
// The following call resumes a paused rendering thread.
|
||||
// If you de-allocated graphic objects for onPause()
|
||||
// this is a good place to re-allocate them.
|
||||
mGLView.onResume();
|
||||
}
|
||||
}
|
||||
|
||||
class HelloOpenGLES20SurfaceView extends GLSurfaceView {
|
||||
|
||||
public HelloOpenGLES20SurfaceView(Context context){
|
||||
super(context);
|
||||
|
||||
// Create an OpenGL ES 2.0 context.
|
||||
setEGLContextClientVersion(2);
|
||||
// Set the Renderer for drawing on the GLSurfaceView
|
||||
setRenderer(new HelloOpenGLES20Renderer());
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
<p class="note"><strong>Note:</strong> You will get a compile error for the {@code
|
||||
HelloOpenGLES20Renderer} class reference. That's expected; you will fix this error in the next step.
|
||||
</p>
|
||||
|
||||
<p>As shown above, this activity uses a single {@link android.opengl.GLSurfaceView} for its
|
||||
view. Notice that this activity implements crucial lifecycle callbacks for pausing and resuming its
|
||||
work.</p>
|
||||
|
||||
<p>The {@code HelloOpenGLES20SurfaceView} class in this example code above is just a thin wrapper
|
||||
for an instance of {@link android.opengl.GLSurfaceView} and is not strictly necessary for this
|
||||
example. However, if you want your application to monitor and respond to touch screen
|
||||
events—and we are guessing you do—you must extend {@link android.opengl.GLSurfaceView}
|
||||
to add touch event listeners, which you will learn how to do in the <a href="#touch">Reponding to
|
||||
Touch Events</a> section.</p>
|
||||
|
||||
<p>In order to draw graphics in the {@link android.opengl.GLSurfaceView}, you must define an
|
||||
implementation of {@link android.opengl.GLSurfaceView.Renderer}. In the next step, you create
|
||||
a renderer class to complete this OpenGL application.</p>
|
||||
</li>
|
||||
|
||||
<li>Create a new file for the following class {@code HelloOpenGLES20Renderer}, 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(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
public void onSurfaceChanged(GL10 unused, int width, int height) {
|
||||
GLES20.glViewport(0, 0, width, height);
|
||||
}
|
||||
|
||||
}
|
||||
</pre>
|
||||
<p>This minimal implementation of {@link android.opengl.GLSurfaceView.Renderer} provides the
|
||||
code structure needed to use OpenGL drawing methods:
|
||||
<ul>
|
||||
<li>{@link
|
||||
android.opengl.GLSurfaceView.Renderer#onSurfaceCreated(javax.microedition.khronos.opengles.GL10,
|
||||
javax.microedition.khronos.egl.EGLConfig) onSurfaceCreated()} is called once to set up the
|
||||
{@link android.opengl.GLSurfaceView}
|
||||
environment.</li>
|
||||
<li>{@link
|
||||
android.opengl.GLSurfaceView.Renderer#onDrawFrame(javax.microedition.khronos.opengles.GL10)
|
||||
onDrawFrame()} is called for each redraw of the {@link
|
||||
android.opengl.GLSurfaceView}.</li>
|
||||
<li>{@link
|
||||
android.opengl.GLSurfaceView.Renderer#onSurfaceChanged(javax.microedition.khronos.opengles.GL10,
|
||||
int, int) onSurfaceChanged()} is called if the geometry of the {@link
|
||||
android.opengl.GLSurfaceView} changes, for example when the device's screen orientation
|
||||
changes.</li>
|
||||
</ul>
|
||||
</p>
|
||||
<p>For more information about these methods, see the <a
|
||||
href="{@docRoot}guide/topics/graphics/opengl.html">3D with OpenGL</a> document.
|
||||
</p>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<p>The code example above creates a simple Android application that displays a grey screen using
|
||||
OpenGL ES 2.0 calls. While this application does not do anything very interesting, by creating these
|
||||
classes, you have layed the foundation needed to start drawing graphic elements with OpenGL ES
|
||||
2.0.</p>
|
||||
|
||||
<p>If you are familiar with the OpenGL ES APIs, these classes should give you enough information
|
||||
to use the OpenGL ES 2.0 API and create graphics. However, if you need a bit more help getting
|
||||
started with OpenGL, head on to the next sections for a few more hints.</p>
|
||||
|
||||
<p class="note"><strong>Note:</strong> If your application requires OpenGL 2.0, make sure you
|
||||
declare this in your manifest:</p>
|
||||
<pre>
|
||||
<!-- Tell the system this app requires OpenGL ES 2.0. -->
|
||||
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
|
||||
</pre>
|
||||
<p>For more information, see <a
|
||||
href="{@docRoot}guide/topics/graphics/opengl.html#manifest">OpenGL manifest declarations</a> in the
|
||||
<em>3D with OpenGL</em> document.</p>
|
||||
|
||||
|
||||
<h2 id="drawing">Draw a Shape on GLSurfaceView</h2>
|
||||
|
||||
<p>Once you have implemented a {@link android.opengl.GLSurfaceView.Renderer}, the next step is to
|
||||
draw something with it. This section shows you how to define and draw a triangle.</p>
|
||||
|
||||
<h3 id="define-triangle">Define 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} 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()} 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());// use the device hardware's native byte order
|
||||
triangleVB = vbb.asFloatBuffer(); // create a floating point buffer from the ByteBuffer
|
||||
triangleVB.put(triangleCoords); // add the coordinates to the FloatBuffer
|
||||
triangleVB.position(0); // set the buffer to read the first coordinate
|
||||
|
||||
}
|
||||
</pre>
|
||||
<p>This method defines a two-dimensional triangle shape with three equal sides.</p>
|
||||
</li>
|
||||
<li>Modify your {@code onSurfaceCreated()} 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="caution"><strong>Caution:</strong> Shapes and other static objects should be initialized
|
||||
once in your {@code onSurfaceCreated()} method for best performance. Avoid initializing the
|
||||
new objects in {@code onDrawFrame()}, as this causes the system to re-create the objects
|
||||
for every frame redraw and slows down your application.
|
||||
</p>
|
||||
</li>
|
||||
|
||||
</ol>
|
||||
|
||||
<p>You have now defined a triangle shape, but if you run the application, nothing appears. What?!
|
||||
You also have to tell OpenGL to draw the triangle, which you'll do in the next section.
|
||||
</p>
|
||||
|
||||
|
||||
<h3 id="draw-triangle">Draw the Triangle</h3>
|
||||
|
||||
<p>The OpenGL ES 2.0 requires a bit more code than OpenGL ES 1.0/1.1 in order to draw objects. In
|
||||
this section, you'll create vertex and fragment shaders, a shader loader, apply the shaders, enable
|
||||
the use of vertex arrays for your triangle and, finally, draw it on screen.</p>
|
||||
|
||||
<p>To draw the triangle:</p>
|
||||
|
||||
<ol>
|
||||
<li>In your {@code HelloOpenGLES20Renderer} class, define a vertex shader and a fragment
|
||||
shader. Shader code is defined as a string which is compiled and run by the OpenGL ES 2.0 rendering
|
||||
engine.
|
||||
<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>
|
||||
<p>The vertex shader controls how OpenGL positions and draws the vertices of shapes in space.
|
||||
The fragment shader controls what OpenGL draws <em>between</em> the vertices of shapes.</p>
|
||||
</li>
|
||||
<li>In your {@code HelloOpenGLES20Renderer} class, create a method for loading the shaders.
|
||||
<pre>
|
||||
private int loadShader(int type, String shaderCode){
|
||||
|
||||
// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
|
||||
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
|
||||
int shader = GLES20.glCreateShader(type);
|
||||
|
||||
// add the source code to the shader and compile it
|
||||
GLES20.glShaderSource(shader, shaderCode);
|
||||
GLES20.glCompileShader(shader);
|
||||
|
||||
return shader;
|
||||
}
|
||||
</pre>
|
||||
</li>
|
||||
|
||||
<li>Add the following members to your {@code HelloOpenGLES20Renderer} class for an OpenGL
|
||||
Program and the positioning control for your triangle.
|
||||
<pre>
|
||||
private int mProgram;
|
||||
private int maPositionHandle;
|
||||
</pre>
|
||||
<p>In OpenGL ES 2.0, you attach vertex and fragment shaders to a <em>Program</em> and then
|
||||
apply the program to the OpenGL graphics pipeline.</p>
|
||||
</li>
|
||||
|
||||
<li>Add the following code to the end of your {@code onSurfaceCreated()} method to load the
|
||||
shaders and attach them to an OpenGL Program.
|
||||
<pre>
|
||||
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
|
||||
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
|
||||
|
||||
mProgram = GLES20.glCreateProgram(); // create empty OpenGL Program
|
||||
GLES20.glAttachShader(mProgram, vertexShader); // add the vertex shader to program
|
||||
GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
|
||||
GLES20.glLinkProgram(mProgram); // creates OpenGL program executables
|
||||
|
||||
// get handle to the vertex shader's vPosition member
|
||||
maPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
|
||||
</pre>
|
||||
<p>At this point, you are ready to draw the triangle object in the OpenGL view.</p>
|
||||
</li>
|
||||
|
||||
<li>Add the following code to the end of your {@code onDrawFrame()} method apply the OpenGL
|
||||
program you created, load the triangle object and draw the triangle.
|
||||
<pre>
|
||||
// Add program to OpenGL environment
|
||||
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>
|
||||
</li>
|
||||
<li id="squashed-triangle">Run the app! Your application should look something like this:
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<img src="{@docRoot}images/opengl/helloopengl-es20-1.png">
|
||||
<p class="img-caption">
|
||||
<strong>Figure 1.</strong> Triangle drawn without a projection or camera view.
|
||||
</p>
|
||||
|
||||
<p>There are a few problems with this example. First of all, it is not going to impress your
|
||||
friends. Secondly, the triangle is a bit squashed and changes shape when you change the screen
|
||||
orientation of the 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. You'll fix that problem using a projection
|
||||
and camera view in the next section.</p>
|
||||
|
||||
<p>Lastly, because the triangle is stationary, the system is redrawing the object repeatedly in
|
||||
exactly the same place, which is not the most efficient use of the OpenGL graphics pipeline. In the
|
||||
<a href="#motion">Add Motion</a> section, you'll make this shape rotate and justify
|
||||
this use of processing power.</p>
|
||||
|
||||
<h2 id="projection-and-views">Apply Projection and Camera View</h2>
|
||||
|
||||
<p>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. To solve this problem, you can apply an OpenGL
|
||||
projection mode and camera view (eye point) to transform the coordinates of your graphic objects
|
||||
so they have the correct proportions on any display. For more information about OpenGL coordinate
|
||||
mapping, see <a href="{@docRoot}guide/topics/graphics/opengl.html#coordinate-mapping">Coordinate
|
||||
Mapping for Drawn Objects</a>.</p>
|
||||
|
||||
<p>To apply projection and camera view transformations to your triangle:
|
||||
</p>
|
||||
<ol>
|
||||
<li>Add the following members to your {@code HelloOpenGLES20Renderer} 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} string to add a variable for a model view
|
||||
projection matrix.
|
||||
<pre>
|
||||
private final String vertexShaderCode =
|
||||
// This matrix member variable provides a hook to manipulate
|
||||
// the coordinates of the objects that use this vertex shader
|
||||
"uniform mat4 uMVPMatrix; \n" +
|
||||
|
||||
"attribute vec4 vPosition; \n" +
|
||||
"void main(){ \n" +
|
||||
|
||||
// the matrix must be included as a modifier of gl_Position
|
||||
" gl_Position = uMVPMatrix * vPosition; \n" +
|
||||
|
||||
"} \n";
|
||||
</pre>
|
||||
</li>
|
||||
<li>Modify the {@code onSurfaceChanged()} method to calculate the device screen ratio 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;
|
||||
|
||||
// this projection matrix is applied to object coodinates
|
||||
// in the onDrawFrame() method
|
||||
Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
|
||||
}
|
||||
</pre>
|
||||
</li>
|
||||
<li>Add the following code to the end of your {@code onSurfaceChanged()} method to
|
||||
reference the {@code uMVPMatrix} shader matrix variable you added in step 2.
|
||||
<pre>
|
||||
muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
|
||||
</pre>
|
||||
</li>
|
||||
<li>Add the following code to the end of your {@code onSurfaceChanged()} method to define
|
||||
a camera view matrix.
|
||||
<pre>
|
||||
Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
|
||||
</pre>
|
||||
</li>
|
||||
<li>Finally, modify your {@code onDrawFrame()} method to combine the projection and
|
||||
camera view matrices and then apply the combined transformation to the OpenGL rendering pipeline.
|
||||
<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
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
</li>
|
||||
<li>Run the updated application and you should see something like this:</li>
|
||||
</ol>
|
||||
|
||||
<img src="{@docRoot}images/opengl/helloopengl-es20-2.png">
|
||||
<p class="img-caption">
|
||||
<strong>Figure 2.</strong> Triangle drawn with a projection and camera view applied.
|
||||
</p>
|
||||
|
||||
<p>Now that you have applied this transformation, the triangle has three equal sides, instead of the
|
||||
<a href="#squashed-triangle">squashed triangle</a> in the earlier version.</p>
|
||||
|
||||
<h2 id="motion">Add Motion</h2>
|
||||
|
||||
<p>While it may be an interesting exercise to create static graphic objects with OpenGL ES, chances
|
||||
are you want at least <em>some</em> of your objects to move. In this section, you'll add motion to
|
||||
your 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}
|
||||
class.
|
||||
<pre>
|
||||
private float[] mMMatrix = new float[16];
|
||||
</pre>
|
||||
</li>
|
||||
<li>Modify your {@code onDrawFrame()} 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
|
||||
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
|
||||
|
||||
// Draw the triangle
|
||||
...
|
||||
}
|
||||
</pre>
|
||||
</li>
|
||||
<li>Run the application and your triangle should rotate around its center.</li>
|
||||
</ol>
|
||||
|
||||
|
||||
<h2 id="touch">Respond to Touch Events</h2>
|
||||
<p>Making objects move according to a preset program like the rotating triangle is useful for
|
||||
getting some attention, but what if you want to have users interact with your OpenGL graphics? In
|
||||
this section, you'll learn how listen for touch events to let users interact with objects in your
|
||||
{@code HelloOpenGLES20SurfaceView}.</p>
|
||||
|
||||
<p>The key to making your OpenGL application touch interactive is expanding your implementation of
|
||||
{@link android.opengl.GLSurfaceView} to override the {@link
|
||||
android.view.View#onTouchEvent(android.view.MotionEvent) onTouchEvent()} to listen for touch events.
|
||||
Before you do that, however, you'll modify the renderer class to expose the rotation angle of the
|
||||
triangle. Afterwards, you'll modify the {@code HelloOpenGLES20SurfaceView} to process touch events
|
||||
and pass that data to your renderer.</p>
|
||||
|
||||
<p>To make your triangle rotate in response to touch events:</p>
|
||||
|
||||
<ol>
|
||||
<li>Modify your {@code HelloOpenGLES20Renderer} class to include a new, public member so that
|
||||
your {@code HelloOpenGLES10SurfaceView} class is able to pass new rotation values your renderer:
|
||||
<pre>
|
||||
public float mAngle;
|
||||
</pre>
|
||||
</li>
|
||||
<li>In your {@code onDrawFrame()} method, comment out the code that generates an angle and
|
||||
replace the {@code angle} variable with {@code mAngle}.
|
||||
<pre>
|
||||
// Create a rotation for the triangle (Boring! Comment this out:)
|
||||
// long time = SystemClock.uptimeMillis() % 4000L;
|
||||
// float angle = 0.090f * ((int) time);
|
||||
|
||||
// Use the mAngle member as the rotation value
|
||||
Matrix.setRotateM(mMMatrix, 0, mAngle, 0, 0, 1.0f);
|
||||
</pre>
|
||||
</li>
|
||||
<li>In your {@code HelloOpenGLES20SurfaceView} class, add the following member variables.
|
||||
<pre>
|
||||
private final float TOUCH_SCALE_FACTOR = 180.0f / 320;
|
||||
private HelloOpenGLES20Renderer mRenderer;
|
||||
private float mPreviousX;
|
||||
private float mPreviousY;
|
||||
</pre>
|
||||
</li>
|
||||
<li>In the constructor method for {@code HelloOpenGLES20SurfaceView}, set the {@code mRenderer}
|
||||
member so you have a handle to pass in rotation input and set the render mode to {@link
|
||||
android.opengl.GLSurfaceView#RENDERMODE_WHEN_DIRTY}.<pre>
|
||||
public HelloOpenGLES20SurfaceView(Context context){
|
||||
super(context);
|
||||
// Create an OpenGL ES 2.0 context.
|
||||
setEGLContextClientVersion(2);
|
||||
|
||||
// set the mRenderer member
|
||||
mRenderer = new HelloOpenGLES20Renderer();
|
||||
setRenderer(mRenderer);
|
||||
|
||||
// Render the view only when there is a change
|
||||
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
|
||||
}
|
||||
</pre>
|
||||
</li>
|
||||
<li>In your {@code HelloOpenGLES20SurfaceView} class, override the {@link
|
||||
android.view.View#onTouchEvent(android.view.MotionEvent) onTouchEvent()} method to listen for touch
|
||||
events and pass them to your renderer.
|
||||
<pre>
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent e) {
|
||||
// MotionEvent reports input details from the touch screen
|
||||
// and other input controls. In this case, you are only
|
||||
// interested in events where the touch position changed.
|
||||
|
||||
float x = e.getX();
|
||||
float y = e.getY();
|
||||
|
||||
switch (e.getAction()) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
|
||||
float dx = x - mPreviousX;
|
||||
float dy = y - mPreviousY;
|
||||
|
||||
// reverse direction of rotation above the mid-line
|
||||
if (y > getHeight() / 2) {
|
||||
dx = dx * -1 ;
|
||||
}
|
||||
|
||||
// reverse direction of rotation to left of the mid-line
|
||||
if (x < getWidth() / 2) {
|
||||
dy = dy * -1 ;
|
||||
}
|
||||
|
||||
mRenderer.mAngle += (dx + dy) * TOUCH_SCALE_FACTOR;
|
||||
requestRender();
|
||||
}
|
||||
|
||||
mPreviousX = x;
|
||||
mPreviousY = y;
|
||||
return true;
|
||||
}
|
||||
</pre>
|
||||
<p class="note"><strong>Note:</strong> Touch events return pixel coordinates which <em>are not the
|
||||
same</em> as OpenGL coordinates. Touch coordinate [0,0] is the bottom-left of the screen and the
|
||||
highest value [max_X, max_Y] is the top-right corner of the screen. To match touch events to OpenGL
|
||||
graphic objects, you must translate touch coordinates into OpenGL coordinates.</p>
|
||||
</li>
|
||||
<li>Run the application and drag your finger or cursor around the screen to rotate the
|
||||
triangle.</li>
|
||||
</ol>
|
||||
<p>For another example of OpenGL touch event functionality, see <a
|
||||
href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/graphics/
|
||||
TouchRotateActivity.html">TouchRotateActivity</a>.</p>
|
||||
Reference in New Issue
Block a user