Trong môi trường OpenGL ES, phép chiếu và khung hiển thị máy ảnh cho phép bạn hiển thị các đối tượng được vẽ trong theo cách giống với cách bạn nhìn thấy các vật thể bằng mắt. Phần mô phỏng này về quá trình xem thực được thực hiện bằng các phép biến đổi toán học của toạ độ đối tượng được vẽ:
- Phiếu – Quy tắc chuyển đổi này điều chỉnh toạ độ của các đối tượng được vẽ dựa trên
chiều rộng và chiều cao của
GLSurfaceView
, nơi chúng được hiển thị. Không có trong phép tính này, các đối tượng do OpenGL ES vẽ bị lệch bởi tỷ lệ hình ảnh không bằng nhau cửa sổ. Phép biến đổi phép chiếu thường chỉ phải được tính toán khi tỷ lệ của Khung hiển thị OpenGL được thiết lập hoặc thay đổi trong phương thứconSurfaceChanged()
của trình kết xuất. Để biết thêm thông tin về phép chiếu OpenGL ES và lập bản đồ toạ độ, xem Ánh xạ toạ độ cho bản vẽ đối tượng. - Chế độ xem máy ảnh – Quy tắc chuyển đổi này điều chỉnh toạ độ của các đối tượng được vẽ dựa trên
vị trí của máy ảnh ảo. Điều quan trọng cần lưu ý là OpenGL ES không xác định máy ảnh thực
mà thay vào đó cung cấp các phương thức tiện ích mô phỏng camera bằng cách biến đổi màn hình
các đối tượng được vẽ. Chỉ có thể tính toán một lượt chuyển đổi chế độ xem camera một lần khi bạn thiết lập
GLSurfaceView
hoặc có thể thay đổi linh hoạt dựa trên thao tác của người dùng hoặc chức năng của ứng dụng.
Bài học này mô tả cách tạo một phép chiếu và khung hiển thị máy ảnh, cũng như áp dụng khung hiển thị đó cho các hình dạng được vẽ
GLSurfaceView
của bạn.
Xác định một phép chiếu
Dữ liệu của phép biến đổi phép chiếu được tính trong onSurfaceChanged()
của lớp GLSurfaceView.Renderer
. Mã ví dụ sau đây
lấy chiều cao và chiều rộng của GLSurfaceView
rồi sử dụng nó để điền sẵn
biến đổi phép chiếu Matrix
bằng phương thức 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); }
Mã này sẽ điền sẵn ma trận chiếu mProjectionMatrix
mà sau đó bạn có thể kết hợp
với sự biến đổi khung hiển thị camera trong phương thức onDrawFrame()
, như minh hoạ trong phần tiếp theo.
Lưu ý: Chỉ áp dụng phép biến đổi phép chiếu cho đối tượng vẽ thường dẫn đến màn hình rất trống. Nói chung, bạn cũng phải sử dụng máy ảnh chuyển đổi khung hiển thị để mọi thứ đều xuất hiện trên màn hình.
Xác định chế độ xem camera
Hoàn tất quá trình biến đổi các đối tượng đã vẽ bằng cách thêm biến đổi chế độ xem camera dưới dạng
của quá trình vẽ trong trình kết xuất. Trong mã ví dụ sau, chế độ xem camera
phép biến đổi được tính bằng phép biến đổi Matrix.setLookAtM()
rồi kết hợp với ma trận chiếu được tính toán trước đó. Các biến thể kết hợp
sau đó, các ma trận biến đổi được truyền đến hình dạng đã vẽ.
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); }
Áp dụng phép chiếu và các phép biến đổi camera
Để sử dụng ma trận biến đổi phép chiếu và chế độ xem máy ảnh kết hợp hiển thị trong
để xem trước các phần, trước tiên hãy thêm một biến ma trận vào trình đổ bóng đỉnh đã xác định trước đó
trong lớp 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; ... }
Tiếp theo, hãy sửa đổi phương thức draw()
của các đối tượng đồ hoạ để chấp nhận kiểu kết hợp
và áp dụng ma trận biến đổi vào hình dạng:
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); }
Khi bạn đã tính toán và áp dụng chính xác phép chiếu và các phép biến đổi khung hiển thị camera, đối tượng đồ hoạ được vẽ theo tỷ lệ chính xác và sẽ có dạng như sau:
![](https://developer.android.google.cn/static/images/opengl/ogl-triangle-projected.png?authuser=19&hl=vi)
Hình 1. Hình tam giác được vẽ có áp dụng phép chiếu và khung hiển thị camera.
Giờ bạn đã có ứng dụng hiển thị các hình dạng theo tỷ lệ chính xác, đã đến lúc thêm chuyển động vào hình dạng của bạn.