Applicare le proiezioni e le visualizzazioni della videocamera

Nell'ambiente OpenGL ES, le visualizzazioni di proiezione e videocamera consentono di visualizzare gli oggetti disegnati in un modo che assomiglia maggiormente al modo in cui vedi gli oggetti fisici con i tuoi occhi. Questa simulazione della visualizzazione fisica viene eseguita con trasformazioni matematiche delle coordinate degli oggetti disegnati:

  • Proiezione: questa trasformazione regola le coordinate degli oggetti disegnati in base alla larghezza e all'altezza del GLSurfaceView in cui vengono visualizzati. Senza questo calcolo, gli oggetti disegnati da OpenGL ES vengono inclinati dalle proporzioni disuguali della finestra di visualizzazione. In genere, una trasformazione di proiezione deve essere calcolata solo quando le proporzioni della vista OpenGL vengono stabilite o modificate nel metodo onSurfaceChanged() del renderer. Per ulteriori informazioni sulle proiezioni OpenGL ES e sulla mappatura delle coordinate, consulta Mappatura delle coordinate per oggetti disegnati.
  • Vista videocamera: questa trasformazione regola le coordinate degli oggetti disegnati in base alla posizione di una fotocamera virtuale. È importante notare che OpenGL ES non definisce un oggetto della fotocamera reale, ma fornisce metodi di utilità che simulano una telecamera trasformando la visualizzazione degli oggetti disegnati. Una trasformazione della visualizzazione della videocamera potrebbe essere calcolata una sola volta quando stabilisci il tuo GLSurfaceView oppure potrebbe cambiare in modo dinamico in base alle azioni dell'utente o alla funzione della tua applicazione.

Questa lezione descrive come creare una proiezione e una visualizzazione della videocamera e applicarle alle forme disegnate in GLSurfaceView.

Definisci una proiezione

I dati per una trasformazione di proiezione vengono calcolati nel metodo onSurfaceChanged() della classe GLSurfaceView.Renderer. Il codice di esempio seguente prende l'altezza e la larghezza di GLSurfaceView e la utilizza per completare una trasformazione di proiezione Matrix con il metodo 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);
}

Questo codice compila una matrice di proiezione, mProjectionMatrix, che puoi combinare con una trasformazione di visualizzazione della videocamera nel metodo onDrawFrame(), mostrato nella sezione successiva.

Nota: la semplice applicazione di una trasformazione di proiezione agli oggetti di disegno comporta in genere una visualizzazione molto vuota. In generale devi anche applicare una trasformazione vista telecamera per far sì che qualsiasi cosa venga visualizzata sullo schermo.

Definire la visualizzazione della videocamera

Completa il processo di trasformazione degli oggetti disegnati aggiungendo una trasformazione della vista telecamera come parte del processo di disegno nel renderer. Nel codice di esempio riportato di seguito, la trasformazione della visualizzazione della videocamera viene calcolata utilizzando il metodo Matrix.setLookAtM() e poi combinata con la matrice di proiezione calcolata in precedenza. Le matrici di trasformazione combinate vengono quindi passate alla forma disegnata.

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

Applicare le trasformazioni di proiezione e telecamera

Per utilizzare la matrice di trasformazione combinata per proiezione e visualizzazione della videocamera mostrata nelle sezioni delle anteprime, aggiungi innanzitutto una variabile della matrice al vertex Shader definito in precedenza nella classe 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;

    ...
}

Successivamente, modifica il metodo draw() degli oggetti grafici per accettare la matrice di trasformazione combinata e applicarla alla forma:

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

Dopo aver calcolato e applicato correttamente le trasformazioni di proiezione e visualizzazione della videocamera, gli oggetti grafici vengono disegnati nelle proporzioni corrette e dovrebbero avere il seguente aspetto:

Figura 1. Triangolo disegnato con una proiezione e una visualizzazione della fotocamera applicate.

Ora che disponi di un'applicazione che mostra le forme nelle proporzioni corrette, puoi aggiungere movimento alle forme.