Search code examples
javaandroidopengl-esopengl-es-2.0coordinate-transformation

OpenGL ES 2.0: From orthogonal to perspective (card flip effect)


I set up the orthogonal matrix this way:

ratio = (float) width / height;
left = -ratio;
right = ratio;
bottom = -1f;
top = 1f;
Matrix.orthoM(projectionMatrix, 0, left, right, bottom, top, -1f, 1f);
viewProjMatrix = projectionMatrix;

Creating some tiles is done this way:

float widthF = (right - left) / numColumns; // left to right
float heightF = (bottom - top) / numRows; // top to bottom
for (int row = 0; row < numRows; ++row) {
    for (int col = 0; col < numColumns; ++col) {
        float x1 = left + col * widthF;
        float y1 = top + row * heightF;
        float x2 = left + (col + 1) * widthF;
        float y2 = top + (row + 1) * heightF;
        float z = 0f;
        // and so on, add to vertex buffer
    }
}

And the result is:

orthogonal projection

This may look even better if I use a perspective matrix instead of an orthogonal matrix:

Matrix.frustumM(projectionMatrix, 0, left, right, bottom, top, 1f, 10f);
Matrix.setLookAtM(viewMatrix, 0, 0f, 0f, 2f, 0f, 0f, 0f, 0f, 1f, 0f);
Matrix.multiplyMM(viewProjMatrix, 0, projectionMatrix, 0, viewMatrix, 0);

And the result is:

perspective projection

But, how to get the image displayed in "full screen", meaning filling the viewport? The way the orthogonal matrix fills the viewport but this time with a perspective.

(This card flip effect is inpired by the Tiles3D transition of Flux Slider)


Solution

  • The projection matrix describes the mapping from 3D points of a scene, to 2D points of the viewport. The projection matrix transforms from view space to the clip space, and the coordinates in the clip space are transformed to the normalized device coordinates (NDC) in the range (-1, -1, -1) to (1, 1, 1) by dividing with the w component of the clip coordinates.

    At Perspective Projection the projection matrix describes the mapping from 3D points in the world as they are seen from of a pinhole camera, to 2D points of the viewport.
    The eye space coordinates in the camera frustum (a truncated pyramid) are mapped to a cube (the normalized device coordinates).

    enter image description here

    The relation between the projected area in view space and the Z coordinate of the view space is linear. It depends on the field of view angle and the aspect ratio.

    enter image description here

    You have to adjust the field of fiew to the image. For this you have to know the distance of the image to the camera position.

    float distZ = ....; // distance of the camera to the image
    float sizeX = ....; // width of the rectangle where the image is placed in
    float sizeY = ....; // height of the rectangle where the image is placed in
    
    float near = 1f;
    float far  = 10f;
    
    float left   = -0.5 * sizeX * near / distZ;
    float right  =  0.5 * sizeX * near / distZ;
    float bottom = -0.5 * sizeY * near / distZ;
    float top    =  0.5 * sizeY * near / distZ;
    
    Matrix.frustumM(projectionMatrix, 0, left, right, bottom, top, near, far);
    

    Note, of course the image has to be "centered" to the view.