Menerapkan tampilan kamera dan proyeksi

Di lingkungan OpenGL ES, proyeksi dan tampilan kamera memungkinkan Anda menampilkan objek yang digambar di yang lebih menyerupai bagaimana Anda melihat objek fisik dengan mata Anda. Simulasi dari tampilan fisik dilakukan dengan transformasi matematis dari koordinat objek yang digambar:

  • Proyeksi - Transformasi ini menyesuaikan koordinat objek yang digambar berdasarkan lebar dan tinggi GLSurfaceView tempat keduanya ditampilkan. Tanpa dalam penghitungan ini, objek yang digambar oleh OpenGL ES condong oleh proporsi tampilan yang tidak sama jendela. Transformasi proyeksi biasanya hanya harus dihitung ketika proporsi Tampilan OpenGL dibuat atau diubah dalam metode onSurfaceChanged() perender Anda. Untuk informasi selengkapnya tentang proyeksi OpenGL ES dan pemetaan koordinat, lihat Memetakan koordinat untuk yang digambar objek.
  • Tampilan Kamera - Transformasi ini menyesuaikan koordinat objek yang digambar berdasarkan posisi kamera virtual Anda. Penting untuk diperhatikan bahwa OpenGL ES tidak menentukan kamera yang sebenarnya , namun sebagai gantinya menyediakan metode utilitas yang menyimulasikan kamera dengan mengubah tampilan objek yang digambar. Transformasi tampilan kamera mungkin hanya dihitung sekali saat Anda menetapkan GLSurfaceView, atau mungkin berubah secara dinamis berdasarkan tindakan pengguna atau aplikasi.

Tutorial ini menjelaskan cara membuat proyeksi dan tampilan kamera serta menerapkannya ke bentuk yang digambar GLSurfaceView Anda.

Menentukan proyeksi

Data untuk transformasi proyeksi dihitung di onSurfaceChanged() dari class GLSurfaceView.Renderer Anda. Kode contoh berikut menggunakan tinggi dan lebar GLSurfaceView serta menggunakannya untuk mengisi transformasi proyeksi Matrix menggunakan metode 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);
}

Kode ini mengisi matriks proyeksi, mProjectionMatrix yang kemudian dapat Anda gabungkan dengan transformasi tampilan kamera di metode onDrawFrame(), yang akan ditampilkan di bagian berikutnya.

Catatan: Hanya menerapkan transformasi proyeksi ke menggambar objek biasanya menghasilkan tampilan yang sangat kosong. Secara umum, Anda juga harus menerapkan transformasi tampilan agar apa pun muncul di layar.

Menentukan tampilan kamera

Selesaikan proses transformasi objek yang digambar dengan menambahkan transformasi tampilan kamera sebagai dari proses menggambar di perender Anda. Pada kode contoh berikut, tampilan kamera transformasi dihitung menggunakan Matrix.setLookAtM() kemudian digabungkan dengan matriks proyeksi yang telah dihitung sebelumnya. Kombinasi matriks transformasi kemudian diteruskan ke bentuk yang digambar.

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);
}

Menerapkan transformasi proyeksi dan kamera

Untuk menggunakan proyeksi gabungan dan matriks transformasi tampilan kamera yang ditunjukkan dalam melihat pratinjau bagian, pertama-tama tambahkan variabel matriks ke shader verteks yang ditentukan sebelumnya di class 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;

    ...
}

Selanjutnya, ubah metode draw() objek grafis Anda untuk menerima kombinasi matriks transformasi dan menerapkannya ke bentuk:

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);
}

Setelah Anda menghitung dan menerapkan transformasi proyeksi dan tampilan kamera dengan benar, objek grafis Anda digambar dalam proporsi yang benar dan akan terlihat seperti ini:

Gambar 1. Segitiga digambar dengan tampilan kamera dan proyeksi yang diterapkan.

Sekarang, setelah Anda memiliki aplikasi yang menampilkan bentuk Anda dalam proporsi yang benar, saatnya untuk menambahkan {i>motion <i} pada bentuk-bentuk Anda.