4.2Android Matrix的使用

[TOC]

Matrix

特点:实际变换和执行顺序相反

Android实际执行的变换和调用Matrix相反

Matrix.setIdentityM(modelMatrix2, 0);
Matrix.translateM(modelMatrix2, 0, 0.5f, 1.0f, -1.5f);
Matrix.rotateM(modelMatrix2, 0, angle, 0.0f, 1.0f, 0.0f);
Matrix.scaleM(modelMatrix2, 0, 1.5f, 1.5f, 1.5f);

在顶点坐标上先左乘缩放矩阵,再左乘旋转矩阵,然后再左乘平移矩阵,跟代码调用的顺序正好相反。

以scaleM和translateM进行推导

    float[] matrix = new float[]{
            1f, 5f, 9f, 13f,
            2f, 6f, 10f, 14f,
            3f, 7f, 11f, 15f,
            4f, 8f, 12f, 16f,
    };

    float[] result = new float[16];

scaleM

        Matrix.scaleM(result,0, matrix, 0,2,1, 1 );
        Matrix.scaleM(matrix,0,2,1, 1);


        结果:
        2f, 10f, 18f, 26f,
        2f, 6f, 10f, 14f,
        3f, 7f, 11f, 15f,
        4f, 8f, 12f, 16f,

为什么第一行都乘以2了???

记住!OpenGL的Matrix都是列主序列

我们之前推导的缩放矩阵

假设原矩阵

和scale矩阵相乘,

可以看到列向量分别乘以了scale的factor,但是别忘了是列主顺序,所以对应的结果是第一行乘以了2.

为什么不能右乘?因为矩阵乘法不满足交换律。

假设之前有变换矩阵M0,那么直接作用在原顶点坐标P(x,y,z,w),则有M0*P

此时我们调用scaleM方法,

Matrix.scaleM(M0,0,sx,sy,sz);

得到的M1矩阵,那么M1 = M0*S

作用于顶点向量 M1 * P = M0 * S * P = M0 * (S * P)

此时相当于先执行 scale再执行之前的变换。

translateM

平移

public static void translateM (float[] m, 
                int mOffset, 
                float x, 
                float y, 
                float z)

public static void translateM (float[] tm, 
                int tmOffset, 
                float[] m, 
                int mOffset, 
                float x, 
                float y, 
                float z)

    //等价
    Matrix.translateM(result,0, matrix, 0,1,1, 1 );
    Matrix.translateM(matrix,0,1,1, 1 );


    /**结果是
     1f, 5f, 9f, 13f,
     2f, 6f, 10f, 14f,
     3f, 7f, 11f, 15f,
     10f, 26f, 42f, 58f,
    */

可以看到作用在最后列向量上,对应于列主序列的最后一行。

Android Matrix的操作

https://www.learnopengles.com/understanding-opengls-matrices/

类似于glm,Android在Java层提供了对矩阵的操作。Matrix是一个工具类,操作OpenGL ES的float类型的矩阵、向量。

矩阵和向量是column-major的格式。

  m[offset +  0] m[offset +  4] m[offset +  8] m[offset + 12]
  m[offset +  1] m[offset +  5] m[offset +  9] m[offset + 13]
  m[offset +  2] m[offset +  6] m[offset + 10] m[offset + 14]
  m[offset +  3] m[offset +  7] m[offset + 11] m[offset + 15]

  v[offset + 0]
  v[offset + 1]
  v[offset + 2]
  v[offset + 3]

模型矩阵

rotateM

public static void rotateM (float[] m, 
                int mOffset, 
                float a, 
                float x, 
                float y, 
                float z)

public static void rotateM (float[] rm, 
                int rmOffset, 
                float[] m, 
                int mOffset, 
                float a, 
                float x, 
                float y, 
                float z)                

和 setRotateM区别是作用于之前的上一个矩阵。

public static void rotateM(float[] rm, int rmOffset,
            float[] m, int mOffset,
            float a, float x, float y, float z) {
    synchronized(sTemp) {
        setRotateM(sTemp, 0, a, x, y, z);
        multiplyMM(rm, rmOffset, m, mOffset, sTemp, 0);
    }
}

scaleM

public static void scaleM (float[] m, 
                int mOffset, 
                float x, 
                float y, 
                float z)


public static void scaleM (float[] sm, 
                int smOffset, 
                float[] m, 
                int mOffset, 
                float x, 
                float y, 
                float z)                

setRotateEulerM

public static void setRotateEulerM (float[] rm, 
                int rmOffset, 
                float x, 
                float y, 
                float z)

欧拉角转成旋转矩阵。

setRotateM

public static void setRotateM (float[] rm, 
                int rmOffset, 
                float a, 
                float x, 
                float y, 
                float z)

创建一个矩阵,围绕锚点 x,y,z 旋转 a 角度

translateM

平移

观察矩阵

setLookAtM

public static void setLookAtM (float[] rm, 
                int rmOffset, 
                float eyeX, 
                float eyeY, 
                float eyeZ, 
                float centerX, 
                float centerY, 
                float centerZ, 
                float upX, 
                float upY, 
                float upZ)

//TODO
创建一个viewing transformation

an eye point, a center of view, and an up vector.

投影矩阵

frustumM

public static void frustumM (float[] m, 
                int offset, 
                float left, 
                float right, 
                float bottom, 
                float top, 
                float near, 
                float far)

Defines a projection matrix in terms of six clip planes.

//TODO

orthoM

public static void orthoM (float[] m, 
                int mOffset, 
                float left, 
                float right, 
                float bottom, 
                float top, 
                float near, 
                float far)

//TODO
Computes an orthographic projection matrix.

perspectiveM

public static void perspectiveM (float[] m, 
                int offset, 
                float fovy, 
                float aspect, 
                float zNear, 
                float zFar)

//TODO

Defines a projection matrix in terms of a field of view angle, an aspect ratio, and z clip planes.

其他矩阵操作

invertM

public static boolean invertM (float[] mInv, 
                int mInvOffset, 
                float[] m, 
                int mOffset)

求逆矩阵

length

public static float length (float x, 
                float y, 
                float z)

求向量长度,针对(0,0,0)为原点

multiplyMM

public static void multiplyMM (float[] result, 
                int resultOffset, 
                float[] lhs, 
                int lhsOffset, 
                float[] rhs, 
                int rhsOffset)

4*4矩阵相乘

//TODO

multiplyMV

4 * 4矩阵和4 * 1向量相乘

setIdentityM

public static void setIdentityM (float[] sm, 
                int smOffset)

将sm变为单位矩阵,注意数组越界

    public static void setIdentityM(float[] sm, int smOffset) {
        for (int i=0 ; i<16 ; i++) {
            sm[smOffset + i] = 0;
        }
        for(int i = 0; i < 16; i += 5) {
            sm[smOffset + i] = 1.0f;
        }
    }

transposeM

转置矩阵

public static void transposeM (float[] mTrans, 
                int mTransOffset, 
                float[] m, 
                int mOffset)