Home | History | Annotate | Download | only in opengl
      1 page.title=Applying Projection and Camera Views
      2 parent.title=Displaying Graphics with OpenGL ES
      3 parent.link=index.html
      4 
      5 trainingnavtop=true
      6 previous.title=Drawing Shapes
      7 previous.link=draw.html
      8 next.title=Applying Projection and Camera Views
      9 next.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"
     30 class="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
     38 way that more closely resembles how you see physical objects with your eyes. This simulation of
     39 physical 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
     43 the width and height of the {@link android.opengl.GLSurfaceView} where they are displayed. Without
     44 this calculation, objects drawn by OpenGL ES are skewed by the unequal proportions of the view
     45 window. A projection transformation typically only has to be calculated when the proportions of the
     46 OpenGL view are established or changed in the {@link
     47 android.opengl.GLSurfaceView.Renderer#onSurfaceChanged
     48 onSurfaceChanged()} method of your renderer. For more information about OpenGL ES projections and
     49 coordinate mapping, see <a
     50 href="{@docRoot}guide/topics/graphics/opengl.html#coordinate-mapping">Mapping Coordinates for Drawn
     51 Objects</a>.</li>
     52   <li><em>Camera View</em> - This transformation adjusts the coordinates of drawn objects based on a
     53 virtual camera position. Its important to note that OpenGL ES does not define an actual camera
     54 object, but instead provides utility methods that simulate a camera by transforming the display of
     55 drawn 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
     57 applications 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
     61 your {@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
     67 android.opengl.GLSurfaceView.Renderer#onSurfaceChanged onSurfaceChanged()}
     68 method of your {@link android.opengl.GLSurfaceView.Renderer} class. The following example code
     69 takes the height and width of the {@link android.opengl.GLSurfaceView} and uses it to populate a
     70 projection transformation {@link android.opengl.Matrix} using the {@link
     71 android.opengl.Matrix#frustumM Matrix.frustumM()} method:</p>
     72 
     73 <pre>
     74 // mMVPMatrix is an abbreviation for "Model View Projection Matrix"
     75 private final float[] mMVPMatrix = new float[16];
     76 private final float[] mProjectionMatrix = new float[16];
     77 private final float[] mViewMatrix = new float[16];
     78 
     79 &#64;Override
     80 public 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
     92 with a camera view transformation in the {@link android.opengl.GLSurfaceView.Renderer#onDrawFrame
     93 onDrawFrame()} method, which is shown in the next section.</p>
     94 
     95 <p class="note"><strong>Note:</strong> Just applying a projection transformation to your
     96 drawing objects typically results in a very empty display. In general, you must also apply a camera
     97 view 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
    103 part of the drawing process in your renderer. In the following example code, the camera view
    104 transformation is calculated using the {@link android.opengl.Matrix#setLookAtM Matrix.setLookAtM()}
    105 method and then combined with the previously calculated projection matrix. The combined
    106 transformation matrices are then passed to the drawn shape.</p>
    107 
    108 <pre>
    109 &#64;Override
    110 public 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
    127 previews sections, first add a matrix variable to the <em>vertex shader</em> previously defined
    128 in the <code>Triangle</code> class:</p>
    129 
    130 <pre>
    131 public 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
    153 transformation matrix and apply it to the shape:</p>
    154 
    155 <pre>
    156 public 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,
    174 your 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
    183 add motion to your shapes.</p>
    184