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 @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 @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