Zastosuj projekcje i widoki z kamery

W środowisku OpenGL ES funkcja projekcji i widoki kamery pozwalają wyświetlać narysowane obiekty na podobieństwo sposobu, w jaki widzicie obiekty oczami. Ta symulacja fizyczne przeglądanie polega na przekształcaniu matematycznych współrzędnych obiektów:

  • Odwzorowanie – to przekształcenie dostosowuje współrzędne rysowanych obiektów na podstawie szerokość i wysokość GLSurfaceView, w których są wyświetlane. Bez w tych obliczeniach obiekty rysowane przez OpenGL ES są zniekształcone przez nierówne proporcje obrazu okno. Transformacja rzutująca zwykle musi być obliczona tylko wtedy, gdy proporcje Widok OpenGL jest ustanawiany lub zmieniany w metodzie onSurfaceChanged() mechanizmu renderowania. Więcej informacji na temat projekcji OpenGL ES mapowanie współrzędnych, patrz Nanoszenie współrzędnych na mapie .
  • Widok kamery – to przekształcenie dostosowuje współrzędne rysowanych obiektów na podstawie pozycji kamery wirtualnej. Należy pamiętać, że OpenGL ES nie definiuje rzeczywistej kamery. , ale zapewnia metody użytkowe symulujące działanie kamery przez przekształcenie obrazu narysowanych obiektach. Transformacja widoku z kamery może zostać obliczona tylko raz po ustawieniu GLSurfaceView lub może się zmieniać dynamicznie w zależności od działań użytkowników lub do funkcji aplikacji.

Z tej lekcji dowiesz się, jak utworzyć projekcję i widok z kamery oraz zastosować je do kształtów rysowanych GLSurfaceView.

Definiowanie prognozy

Dane na potrzeby przekształcenia prognozy są obliczane w onSurfaceChanged() klasy GLSurfaceView.Renderer. Oto przykładowy kod pobiera wysokość i szerokość GLSurfaceView i używa ich do wypełnienia przekształcenie prognozy Matrix przy użyciu metody 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);
}

Ten kod wypełnia macierz wyświetlania, mProjectionMatrix, którą można następnie połączyć. z przekształceniem widoku z kamery w metodzie onDrawFrame(), co pokazano w następnej sekcji.

Uwaga: samo zastosowanie przekształcenia prognozy rysowanie obiektów zazwyczaj skutkuje bardzo pustym wyświetlaniem. Ogólnie rzecz biorąc, trzeba również użyć aparatu wyświetlić przekształcenie, aby pokazać na ekranie cokolwiek.

Zdefiniuj widok z kamery

Dokończ proces przekształcania rysowanych obiektów, dodając przekształcenie widoku kamery jako stanowią część procesu rysowania. W poniższym przykładowym kodzie widok z kamery przekształcenie jest obliczane za pomocą funkcji Matrix.setLookAtM() a następnie połączona z obliczoną wcześniej macierzą projekcji. Połączone macierze transformacji są następnie przekazywane do narysowanego kształtu.

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

Zastosuj przekształcanie obrazu i kamery

Aby zastosować połączone projekcję i macierz przekształcenia obrazu z kamery widoczną w podgląd sekcji, najpierw dodaj zmienną macierzy do wcześniej zdefiniowanego programu do cieniowania wierzchołków w zajęciach 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;

    ...
}

Następnie zmodyfikuj metodę draw() obiektów graficznych, by zaakceptować połączone wartości macierz transformacji i zastosuj ją do kształtu:

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

Po prawidłowym obliczeniu i zastosowaniu przekształceń obrazu i widoku z kamery obiekty graficzne są rysowane we właściwych proporcjach i powinny wyglądać tak:

Rysunek 1. Trójkąt narysowany z projekcją i widokiem z kamery.

Teraz gdy masz już aplikację, która wyświetla kształty w odpowiednich proporcjach, czas aby dodać ruch do kształtów.