# （四）使用投影和相机视角（Applying Projection and Camera Views）

In the OpenGL ES environment, projection and camera views allow you to display drawn objects in a way that more closely resembles how you see physical objects with your eyes. This simulation of physical viewing is done with mathematical transformations of drawn object coordinates:

• Projection - This transformation adjusts the coordinates of drawn objects based on the width and height of the GLSurfaceView where they are displayed. Without this calculation, objects drawn by OpenGL ES are skewed by the unequal proportions of the view window. A projection transformation typically only has to be calculated when the proportions of the OpenGL view are established or changed in the onSurfaceChanged() method of your renderer. For more information about OpenGL ES projections and coordinate mapping, see Mapping Coordinates for Drawn Objects.
投影- 这个变换根据GLSurfaceView的宽高来调节绘制物体的坐标。没有这些转换计算，OpenGL ES 绘制出来的形状会因为GLSurfaceView所在的window比例不同而变形。只需要在OpenGL view建立时，或者在render的onSurfaceChanged()方法中进行投影变换。关于更多的OpenGL ES 投影和坐标映射，可以看映射绘制物体的坐标

• Camera View - This transformation adjusts the coordinates of drawn objects based on a virtual camera position. It’s important to note that OpenGL ES does not define an actual camera object, but instead provides utility methods that simulate a camera by transforming the display of drawn objects. A camera view transformation might be calculated only once when you establish your GLSurfaceView, or might change dynamically based on user actions or your application’s function.
This lesson describes how to create a projection and camera view and apply it to shapes drawn in your GLSurfaceView.
相机视角- 这个转换是根据一个虚拟的相机位置来调节绘制物体的坐标。需要注意的是，OpenGL ES并没有定义一个真实的相机对象，而且提供一个转变绘制形状显示的方法来模拟一个相机。相机视角转换可能只计算一次，也可能因为应用功能的不同而动态变换。
这里主要讲解如何建立投影和相机视角，并把它应用到GLSurfaceView绘制的图形上。

## 定义投射

The data for a projection transformation is calculated in the onSurfaceChanged() method of your GLSurfaceView.Renderer class. The following example code takes the height and width of the GLSurfaceView and uses it to populate a projection transformation Matrix using the Matrix.frustumM() method:

``````// mMVPMatrix is an abbreviation for "Model View Projection Matrix"
private final float[] mMVPMatrix = new float[16];
private final float[] mProjectionMatrix = new float[16];
private final float[] mViewMatrix = new float[16];

@Override
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 coordinates
// in the onDrawFrame() method
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);//wtf is -1,1,3,7?
}
``````

This code populates a projection matrix, mProjectionMatrix which you can then combine with a camera view transformation in the onDrawFrame() method, which is shown in the next section.

• Note: Just applying a projection transformation to your drawing objects typically results in a very empty display. In general, you must also apply a camera view transformation in order for anything to show up on screen.
注意：对绘制图形只使用投影变换会导致没有任何内容显示。一般来说，为了让屏幕上显示正确的内容，你必须应用相机视角变换。

## 定义相机视角

Complete the process of transforming your drawn objects by adding a camera view transformation as part of the drawing process in your renderer. In the following example code, the camera view transformation is calculated using the Matrix.setLookAtM() method and then combined with the previously calculated projection matrix. The combined transformation matrices are then passed to the drawn shape.

``````@Override
public void onDrawFrame(GL10 unused) {
...
// Set the camera position (View matrix)
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);

// Calculate the projection and view transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);

// Draw shape
mTriangle.draw(mMVPMatrix);
}
``````

## 应用投影和相机视频变换

In order to use the combined projection and camera view transformation matrix shown in the previews sections, first add a matrix variable to the vertex shader previously defined in the Triangle class:

``````public class Triangle {

// This matrix member variable provides a hook to manipulate
// the coordinates of the objects that use this vertex shader
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
// the matrix must be included as a modifier of gl_Position
// Note that the uMVPMatrix factor *must be first* in order
// for the matrix multiplication product to be correct.
"  gl_Position = uMVPMatrix * vPosition;" +
"}";

// Use to access and set the view transformation
private int mMVPMatrixHandle;

...
}
``````

Next, modify the draw() method of your graphic objects to accept the combined transformation matrix and apply it to the shape:

``````public void draw(float[] mvpMatrix) { // pass in the calculated transformation matrix
...

// get handle to shape's transformation matrix
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");

// Pass the projection and view transformation to the shader
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);

// Draw the triangle
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);

// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
``````

Once you have correctly calculated and applied the projection and camera view transformations, your graphic objects are drawn in correct proportions and should look like this:

Figure 1. Triangle drawn with a projection and camera view applied.

Now that you have an application that displays your shapes in correct proportions, it's time to add motion to your shapes.