应用投影和相机视图

在 OpenGL ES 环境中,投影和相机视图允许您以 更接近您用眼睛看实物的方式。这种模拟 实物观看是通过对绘制对象坐标进行数学转换完成的:

  • 投影 - 这种转换可根据 GLSurfaceView 的宽度和高度。不包含 通过该计算,OpenGL ES 绘制的对象会被不等比例的视图所扭曲 窗口。投影转换通常只有在 OpenGL 视图是在渲染程序的 onSurfaceChanged() 方法中建立或更改的。有关 OpenGL ES 投影和 坐标映射, 请参阅 映射所绘制的坐标 对象
  • 相机视图 - 这种转换可根据 虚拟摄像头的位置。请务必注意,OpenGL ES 不会定义实际的相机 对象,而是提供了实用程序方法,通过将 绘制的对象。相机视图转换可能只计算一次, GLSurfaceView,也可以根据用户操作或您的 应用的功能。

本课介绍如何创建投影和相机视图,并将其应用于 您的GLSurfaceView

定义映射

投影转换的数据在 onSurfaceChanged() 中计算得出 方法中 GLSurfaceView.Renderer 类的构造函数。以下示例代码 接受 GLSurfaceView 的高度和宽度,并使用它来填充 投影转换 Matrix(使用 Matrix.frustumM() 方法):

Kotlin

// vPMatrix is an abbreviation for "Model View Projection Matrix" private val vPMatrix = FloatArray(16) private val projectionMatrix = FloatArray(16) private val viewMatrix = FloatArray(16) override fun onSurfaceChanged(unused: GL10, width: Int, height: Int) {  GLES20.glViewport(0, 0, width, height)  val ratio: Float = width.toFloat() / height.toFloat()  // this projection matrix is applied to object coordinates  // in the onDrawFrame() method  Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1f, 1f, 3f, 7f) }

Java

// vPMatrix is an abbreviation for "Model View Projection Matrix" private final float[] vPMatrix = new float[16]; private final float[] projectionMatrix = new float[16]; private final float[] viewMatrix = 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(projectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7); }

此代码会填充投影矩阵 mProjectionMatrix,然后您可以将该矩阵合并 并在 onDrawFrame() 方法中实现相机视图转换,这在下一节中将有所说明。

注意:只需将投影转换应用于 绘制对象通常会导致显示画面很空。一般来说,您还必须将相机 视图转换,以便在屏幕上显示任何内容。

定义相机视图

通过添加镜头视图转换函数来完成绘制对象的转换过程,如下所示 绘制程序的一部分在下面的示例代码中,相机视图 转换是使用 Matrix.setLookAtM() 计算的 方法,然后将该矩阵与之前计算的投影矩阵合并。组合 然后将转换矩阵传递给所绘制的形状。

Kotlin

override fun onDrawFrame(unused: GL10) {  ...  // Set the camera position (View matrix)  Matrix.setLookAtM(viewMatrix, 0, 0f, 0f, 3f, 0f, 0f, 0f, 0f, 1.0f, 0.0f)  // Calculate the projection and view transformation  Matrix.multiplyMM(vPMatrix, 0, projectionMatrix, 0, viewMatrix, 0)  // Draw shape  triangle.draw(vPMatrix)

Java

@Override public void onDrawFrame(GL10 unused) {  ...  // Set the camera position (View matrix)  Matrix.setLookAtM(viewMatrix, 0, 0, 0, 3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);  // Calculate the projection and view transformation  Matrix.multiplyMM(vPMatrix, 0, projectionMatrix, 0, viewMatrix, 0);  // Draw shape  triangle.draw(vPMatrix); }

应用投影和相机转换

为了使用合并的投影和相机视图转换矩阵,如 预览部分,请先将矩阵变量添加到先前定义的顶点着色器Triangle 类中:

Kotlin

class Triangle {  private val vertexShaderCode =  // 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 var vPMatrixHandle: Int = 0  ... }

Java

public class Triangle {  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;" +  "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 vPMatrixHandle;  ... }

接下来,修改图形对象的 draw() 方法,以接受合并后的图像对象。 并将其应用于形状:

Kotlin

fun draw(mvpMatrix: FloatArray) { // pass in the calculated transformation matrix  ...  // get handle to shape's transformation matrix  vPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix")  // Pass the projection and view transformation to the shader  GLES20.glUniformMatrix4fv(vPMatrixHandle, 1, false, mvpMatrix, 0)  // Draw the triangle  GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount)  // Disable vertex array  GLES20.glDisableVertexAttribArray(positionHandle) }

Java

public void draw(float[] mvpMatrix) { // pass in the calculated transformation matrix  ...  // get handle to shape's transformation matrix  vPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");  // Pass the projection and view transformation to the shader  GLES20.glUniformMatrix4fv(vPMatrixHandle, 1, false, mvpMatrix, 0);  // Draw the triangle  GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);  // Disable vertex array  GLES20.glDisableVertexAttribArray(positionHandle); }

正确计算并应用投影和相机视图转换后, 您的图形对象应按正确比例绘制,并且应如下所示:

图 1. 应用了投影和相机视图后绘制的三角形。

现在,您已经有了按正确比例显示形状的应用,接下来该 为您的形状添加动画效果。