Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.

Cómo aplicar vistas de cámara y proyección

En el entorno de OpenGL ES, las vistas de proyección y cámara permiten mostrar objetos dibujados de una manera que se asemeja más al modo en que ves objetos físicos con los ojos. Esta simulación de la visualización física se lleva a cabo con transformaciones matemáticas de coordenadas de objetos dibujados:

  • Proyección: esta transformación ajusta las coordenadas de los objetos dibujados en función del ancho y la altura de la GLSurfaceView en la que se muestran. Sin este cálculo, los objetos dibujados por OpenGL ES se distorsionan por las proporciones desiguales de la ventana de vista. Por lo general, solo se debe calcular una transformación de proyección cuando se establecen o cambian las proporciones de la vista de OpenGL en el método onSurfaceChanged() de tu procesador. Para obtener más información sobre las proyecciones de OpenGL ES y el mapeo de coordenadas, consulta Cómo mapear coordenadas para objetos dibujados.
  • Vista de cámara: Esta transformación ajusta las coordenadas de los objetos dibujados según la posición de una cámara virtual. Es importante tener en cuenta que OpenGL ES no define un objeto de cámara real, sino que proporciona métodos de utilidades que simulan una cámara transformando la visualización de los objetos dibujados. Se puede calcular una transformación de vista de cámara solo una vez cuando estableces la GLSurfaceView, o puede cambiar de forma dinámica según las acciones del usuario o la función de tu aplicación.

En esta lección, se describe cómo crear una vista de cámara y proyección, y aplicarla a las formas dibujadas de tu GLSurfaceView.

Cómo definir una proyección

Los datos para una transformación de proyección se calculan en el método onSurfaceChanged() de tu clase GLSurfaceView.Renderer. El siguiente código de ejemplo toma la altura y el ancho de GLSurfaceView, y lo usa para propagar una Matrix de transformación de proyección con el método 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);
    }
    

Este código propaga una matriz de proyección, mProjectionMatrix, que luego puedes combinar con una transformación de vista de cámara en el método onDrawFrame(), que se muestra en la siguiente sección.

Nota: La simple aplicación de una transformación de proyección a tus objetos de dibujo suele dar como resultado una pantalla muy vacía. En general, también debes aplicar una transformación de vista de cámara para que aparezca algo en la pantalla.

Define una vista de cámara

Para completar el proceso de transformación de los objetos dibujados, agrega una transformación de vista de cámara como parte del proceso de dibujo en el procesador. En el siguiente código de ejemplo, se calcula la transformación de vista de cámara con el método Matrix.setLookAtM() y, luego, se combina con la matriz de proyección calculada anteriormente. Después, se pasan las matrices de transformación combinadas a la forma dibujada.

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

Cómo aplicar transformaciones de cámara y proyección

Para usar la matriz de transformación combinada de proyección y vista de cámara que se muestra en las secciones anteriores, primero agrega una variable de matriz al sombreador de vértices definido anteriormente en la clase 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;

        ...
    }
    

A continuación, modifica el método draw() de tus objetos gráficos para aceptar la matriz de transformación combinada y aplicarla a la siguiente forma:

Kotlin

    fun draw(mvpMatrix: FloatArray) { // pass in the calculated transformation matrix

        // get handle to shape's transformation matrix
        vPMatrixHandle = GLES20.glGetUniformLocation(program, "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(program, "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);
    }
    

Una vez que hayas calculado y aplicado correctamente las transformaciones de proyección y vista de cámara, los objetos gráficos se dibujarán en proporciones correctas y deberían verse así:

Figura 1: Triángulo dibujado con una vista de cámara y proyección aplicada

Ahora que tienes una aplicación que muestra las formas con las proporciones correctas, puedes agregar movimiento.