Aplicar projeção e visualizações de câmera

No ambiente OpenGL ES, a projeção e as visualizações de câmera permitem exibir objetos desenhados em uma mais parecida com a forma como você vê objetos físicos com seus olhos. Essa simulação de a visualização física é feita com transformações matemáticas de coordenadas de objetos desenhados:

  • Projeção: esta transformação ajusta as coordenadas de objetos desenhados com base no a largura e a altura da GLSurfaceView em que elas são exibidas. Sem esse cálculo, objetos desenhados pelo OpenGL ES são distorcidos pelas proporções desiguais da visualização janela. Uma transformação de projeção normalmente só precisa ser calculada quando as proporções do A visualização do OpenGL é estabelecida ou alterada no método onSurfaceChanged() do renderizador. Para mais informações sobre projeções do OpenGL ES e o mapeamento de coordenadas, consulte Coordenadas de mapeamento para desenho objetos.
  • Visualização da câmera: esta transformação ajusta as coordenadas de objetos desenhados com base em uma a posição da câmera virtual. É importante observar que o OpenGL ES não define uma câmera real em vez disso, fornece métodos utilitários que simulam uma câmera, transformando a exibição do objetos desenhados. Uma transformação de visualização da câmera pode ser calculada apenas uma vez quando você estabelecer sua GLSurfaceView ou podem mudar dinamicamente com base nas ações do usuário ou nos seus função do aplicativo.

Esta lição descreve como criar uma projeção e uma visualização de câmera e aplicá-las a formas desenhadas seu GLSurfaceView.

Definir uma projeção

Os dados de uma transformação de projeção são calculados no onSurfaceChanged(). da classe GLSurfaceView.Renderer. O código de exemplo a seguir usa a altura e a largura da GLSurfaceView para preencher uma transformação de projeção Matrix usando o 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);
}

Esse código preenche uma matriz de projeção, mProjectionMatrix, que você pode combinar com uma transformação de visualização da câmera no método onDrawFrame(), que é mostrado na próxima seção.

Observação:basta aplicar uma transformação de projeção às suas objetos de desenho normalmente resulta em uma exibição muito vazia. Em geral, também é preciso aplicar uma visualização para que tudo apareça na tela.

Definir uma visualização de câmera

Complete o processo de transformação de objetos desenhados adicionando uma transformação de visualização de câmera como do processo de desenho em seu renderizador. No código de exemplo a seguir, a visualização da câmera a transformação é calculada usando a função Matrix.setLookAtM() e depois combinados com a matriz de projeção calculada anteriormente. A combinação matrizes de transformação são passadas para a forma desenhada.

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

Aplicar projeção e transformações de câmera

Para usar a matriz combinada de projeção e transformação de visualização de câmera mostrada no visualizar as seções, primeiro adicione uma variável de matriz ao sombreador de vértice definido anteriormente na 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;

    ...
}

Em seguida, modifique o método draw() dos objetos gráficos para aceitar a combinação matriz de transformação e aplicá-la ao formato:

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

Depois de calcular e aplicar corretamente as transformações de projeção e visualização de câmera, seus objetos gráficos foram desenhados nas proporções corretas e devem ter a seguinte aparência:

Figura 1. Triângulo desenhado com uma projeção e uma visualização de câmera aplicadas.

Agora que você tem um aplicativo que exibe suas formas nas proporções corretas, é hora de adicionar movimento às formas.