• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=Applying Projection and Camera Views
2parent.title=Displaying Graphics with OpenGL ES
3parent.link=index.html
4
5trainingnavtop=true
6previous.title=Drawing Shapes
7previous.link=draw.html
8next.title=Applying Projection and Camera Views
9next.link=projection.html
10
11@jd:body
12
13<div id="tb-wrapper">
14<div id="tb">
15
16<h2>This lesson teaches you to</h2>
17<ol>
18  <li><a href="#projection">Define a Projection</a></li>
19  <li><a href="#camera-view">Define a Camera View</a></li>
20  <li><a href="#transform">Apply Projection and Camera Transformations</a></li>
21</ol>
22
23<h2>You should also read</h2>
24<ul>
25  <li><a href="{@docRoot}guide/topics/graphics/opengl.html">OpenGL</a></li>
26</ul>
27
28<div class="download-box">
29 <a href="{@docRoot}shareables/training/OpenGLES.zip"
30class="button">Download the sample</a>
31 <p class="filename">OpenGLES.zip</p>
32</div>
33
34</div>
35</div>
36
37<p>In the OpenGL ES environment, projection and camera views allow you to display drawn objects in a
38way that more closely resembles how you see physical objects with your eyes. This simulation of
39physical viewing is done with mathematical transformations of drawn object coordinates:</p>
40
41<ul>
42  <li><em>Projection</em> - This transformation adjusts the coordinates of drawn objects based on
43the width and height of the {@link android.opengl.GLSurfaceView} where they are displayed. Without
44this calculation, objects drawn by OpenGL ES are skewed by the unequal proportions of the view
45window. A projection transformation typically only has to be calculated when the proportions of the
46OpenGL view are established or changed in the {@link
47android.opengl.GLSurfaceView.Renderer#onSurfaceChanged
48onSurfaceChanged()} method of your renderer. For more information about OpenGL ES projections and
49coordinate mapping, see <a
50href="{@docRoot}guide/topics/graphics/opengl.html#coordinate-mapping">Mapping Coordinates for Drawn
51Objects</a>.</li>
52  <li><em>Camera View</em> - This transformation adjusts the coordinates of drawn objects based on a
53virtual camera position. It’s important to note that OpenGL ES does not define an actual camera
54object, but instead provides utility methods that simulate a camera by transforming the display of
55drawn objects. A camera view transformation might be calculated only once when you establish your
56{@link android.opengl.GLSurfaceView}, or might change dynamically based on user actions or your
57application’s function.</li>
58</ul>
59
60<p>This lesson describes how to create a projection and camera view and apply it to shapes drawn in
61your {@link android.opengl.GLSurfaceView}.</p>
62
63
64<h2 id="projection">Define a Projection</h2>
65
66<p>The data for a projection transformation is calculated in the {@link
67android.opengl.GLSurfaceView.Renderer#onSurfaceChanged onSurfaceChanged()}
68method of your {@link android.opengl.GLSurfaceView.Renderer} class. The following example code
69takes the height and width of the {@link android.opengl.GLSurfaceView} and uses it to populate a
70projection transformation {@link android.opengl.Matrix} using the {@link
71android.opengl.Matrix#frustumM Matrix.frustumM()} method:</p>
72
73<pre>
74// mMVPMatrix is an abbreviation for "Model View Projection Matrix"
75private final float[] mMVPMatrix = new float[16];
76private final float[] mProjectionMatrix = new float[16];
77private final float[] mViewMatrix = new float[16];
78
79&#64;Override
80public void onSurfaceChanged(GL10 unused, int width, int height) {
81    GLES20.glViewport(0, 0, width, height);
82
83    float ratio = (float) width / height;
84
85    // this projection matrix is applied to object coordinates
86    // in the onDrawFrame() method
87    Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
88}
89</pre>
90
91<p>This code populates a projection matrix, {@code mProjectionMatrix} which you can then combine
92with a camera view transformation in the {@link android.opengl.GLSurfaceView.Renderer#onDrawFrame
93onDrawFrame()} method, which is shown in the next section.</p>
94
95<p class="note"><strong>Note:</strong> Just applying a projection transformation to your
96drawing objects typically results in a very empty display. In general, you must also apply a camera
97view transformation in order for anything to show up on screen.</p>
98
99
100<h2 id="camera-view">Define a Camera View</h2>
101
102<p>Complete the process of transforming your drawn objects by adding a camera view transformation as
103part of the drawing process in your renderer. In the following example code, the camera view
104transformation is calculated using the {@link android.opengl.Matrix#setLookAtM Matrix.setLookAtM()}
105method and then combined with the previously calculated projection matrix. The combined
106transformation matrices are then passed to the drawn shape.</p>
107
108<pre>
109&#64;Override
110public void onDrawFrame(GL10 unused) {
111    ...
112    // Set the camera position (View matrix)
113    Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
114
115    // Calculate the projection and view transformation
116    Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
117
118    // Draw shape
119    mTriangle.draw(mMVPMatrix);
120}
121</pre>
122
123
124<h2 id="#transform">Apply Projection and Camera Transformations</h2>
125
126<p>In order to use the combined projection and camera view transformation matrix shown in the
127previews sections, first add a matrix variable to the <em>vertex shader</em> previously defined
128in the <code>Triangle</code> class:</p>
129
130<pre>
131public class Triangle {
132
133    private final String vertexShaderCode =
134        // This matrix member variable provides a hook to manipulate
135        // the coordinates of the objects that use this vertex shader
136        <strong>"uniform mat4 uMVPMatrix;" +</strong>
137        "attribute vec4 vPosition;" +
138        "void main() {" +
139        // the matrix must be included as a modifier of gl_Position
140        // Note that the uMVPMatrix factor *must be first* in order
141        // for the matrix multiplication product to be correct.
142        "  gl_Position = <strong>uMVPMatrix</strong> * vPosition;" +
143        "}";
144
145    // Use to access and set the view transformation
146    private int mMVPMatrixHandle;
147
148    ...
149}
150</pre>
151
152<p>Next, modify the {@code draw()} method of your graphic objects to accept the combined
153transformation matrix and apply it to the shape:</p>
154
155<pre>
156public void draw(float[] mvpMatrix) { // pass in the calculated transformation matrix
157    ...
158
159    // get handle to shape's transformation matrix
160    <strong>mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");</strong>
161
162    // Pass the projection and view transformation to the shader
163    <strong>GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);</strong>
164
165    // Draw the triangle
166    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
167
168    // Disable vertex array
169    GLES20.glDisableVertexAttribArray(mPositionHandle);
170}
171</pre>
172
173<p>Once you have correctly calculated and applied the projection and camera view transformations,
174your graphic objects are drawn in correct proportions and should look like this:</p>
175
176
177<img src="{@docRoot}images/opengl/ogl-triangle-projected.png">
178<p class="img-caption">
179<strong>Figure 1.</strong> Triangle drawn with a projection and camera view applied.</p>
180
181
182<p>Now that you have an application that displays your shapes in correct proportions, it's time to
183add motion to your shapes.</p>
184