Áp dụng phép chiếu và khung hiển thị camera

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ức onSurfaceChanged() 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:

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.