Appliquer des vues de caméra et des projections

Dans l'environnement OpenGL ES, les vues de projection et de caméra vous permettent d'afficher les objets dessinés d'une manière qui ressemble davantage à la façon dont vous voyez les objets physiques avec vos yeux. Cette simulation de la visualisation physique est effectuée avec des transformations mathématiques de coordonnées d'objets dessinées:

  • Projection : cette transformation ajuste les coordonnées des objets dessinés en fonction de la largeur et de la hauteur de la GLSurfaceView où ils sont affichés. Sans ce calcul, les objets dessinés par OpenGL ES sont asymétriques par les proportions inégales de la fenêtre d'affichage. Une transformation de projection ne doit généralement être calculée que lorsque les proportions de la vue OpenGL sont établies ou modifiées dans la méthode onSurfaceChanged() de votre moteur de rendu. Pour en savoir plus sur les projections OpenGL ES et la mise en correspondance des coordonnées, consultez la section Mapper des coordonnées pour les objets dessinés.
  • Camera View (Vue de la caméra) : cette transformation ajuste les coordonnées des objets dessinés en fonction de la position de la caméra virtuelle. Il est important de noter qu'OpenGL ES ne définit pas un objet appareil photo réel, mais fournit des méthodes utilitaires qui simulent un appareil photo en transformant l'affichage des objets dessinés. La transformation de la vue de la caméra peut être calculée une seule fois lors de l'établissement de votre GLSurfaceView. Elle peut également changer de manière dynamique en fonction des actions de l'utilisateur ou de la fonction de votre application.

Cette leçon explique comment créer une projection et une vue de caméra, et les appliquer aux formes dessinées dans votre GLSurfaceView.

Définir une projection

Les données d'une transformation de projection sont calculées dans la méthode onSurfaceChanged() de la classe GLSurfaceView.Renderer. L'exemple de code suivant utilise la hauteur et la largeur de GLSurfaceView et l'utilise pour renseigner une transformation de projection Matrix à l'aide de la méthode 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);
}

Ce code remplit une matrice de projection, mProjectionMatrix, que vous pouvez ensuite combiner avec une transformation de vue de caméra dans la méthode onDrawFrame(), comme indiqué dans la section suivante.

Remarque:Le simple fait d'appliquer une transformation de projection à vos objets de dessin produit généralement un affichage très vide. En général, vous devez également appliquer une transformation de vue de la caméra pour que tout s'affiche à l'écran.

Définir une vue de caméra

Terminez le processus de transformation des objets dessinés en ajoutant une transformation de vue de caméra dans le cadre du processus de dessin de votre moteur de rendu. Dans l'exemple de code suivant, la transformation de la vue de la caméra est calculée à l'aide de la méthode Matrix.setLookAtM(), puis combinée à la matrice de projection précédemment calculée. Les matrices de transformation combinées sont ensuite transmises à la forme dessinée.

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

Appliquer des transformations de projection et de caméra

Pour utiliser la matrice de transformation de la projection et de la vue de caméra présentée dans les sections d'aperçus, commencez par ajouter une variable matricielle au nuanceur de sommets précédemment défini dans la 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;

    ...
}

Ensuite, modifiez la méthode draw() de vos objets graphiques pour accepter la matrice de transformation combinée et l'appliquer à la forme:

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

Une fois que vous avez correctement calculé et appliqué les transformations de la projection et de la vue de la caméra, vos objets graphiques sont dessinés dans des proportions correctes et doivent se présenter comme suit:

Figure 1 : Triangle dessiné avec une projection et une vue de caméra appliquées.

Maintenant que vous disposez d'une application qui affiche les formes dans des proportions correctes, vous pouvez ajouter du mouvement à celles-ci.