大学学的线性代数和矩阵基本忘记的差不多了,理解起矩阵Matrix着实有点费劲,记了一次笔记还把左乘右乘记错了。
项目中会使用到矩阵的场景:
【注意】:这里提到了两种场景就对应了两种坐标体系,2种矩阵
【注】:项目中没有使用Skew和Rotate不详细讨论
这里强调这三个函数是因为很容易歧义,但是实际使用中最常用绕不开就是这几个简单操作。Translate ,Scale ,Skew 都有这三个函数,以平移为例:
因为存在post 和pre ,就要区分这两个函数的区别,就容易逻辑开叉到底,post和pre哪个是左乘,哪个是右乘。什么场合用post,什么场合用pre。
重学了一遍线性代数里矩阵的一些知识,越学越懵,也读了不少blog,有些说post 是左乘,有些说post是右乘,我的笔记里第一次也是记post为右乘。虽然 也有看post函数的注释,但是理解上还是出现了偏差:
1、官方注释
/**
* Postconcats the matrix with the specified translation. M' = T(dx, dy) * M
*/
public boolean postTranslate(float dx, float dy) {
nPostTranslate(native_instance, dx, dy);
return true;
}
2、识记理解
这里:M’ = T(dx, dy) * M 其中:M是原矩阵,T是位移阵可以理解为目标变换。目标变换在左边就是左乘。目标变换在右边就是右乘。
3、post VS pref
关于左乘右乘区别说的比较好的有2个观点:
https://www.zhihu.com/question/263660493
空间中的向量用列向量表示。
小结:
1、Android的Matrix 的几何变换可以都用post来计算,因为Android是固定坐标系空间变换用post左乘来来做是符合逻辑的。同一组计算变换里一会用post一会用pre逻辑容易乱,需要改变顺序的时候可以拿两个矩阵通过写A.postConcat(B) 或者B.postConcat(A)来修改。
2、android.renderscript.Matrix4f ,android.opengl.Matrix这两个4*4矩阵是能对应的起来的。这两个矩阵类里是不存在post和pref一说,里面的变换都是左乘 post的方式。所以理解起来反而更简单。so,我认为android Matrix都用post来更好理解
场景一:指定点的放大,缩小。
opengles 的矩阵在这里不详述,因为它的坐标系和坐标比例计算方式都不一样。opengles 坐标依赖顶点坐标和[-1,1]范围计算。后面再写一篇介绍。
1、可以直接用指定点放大缩小函数
m.setScale(scale, scale, cx, cy)
2、使用平移和缩放(android.opengl.Matrix和Matrix4f 都没有上一种方法)
T(cx,cy)*S(s,s)*T(-cx,-cy)*m
因为android的坐标0,0是左上角,如果是opengles 移动的点第一次变换就不是m.postTranslate(-cx, -cy)
// android matrix
//平移原点到目标点
m.postTranslate(-cx, -cy)
m.postScale(scale, scale)
m.postTranslate(cx, cy)
opengl es的矩阵
//opengles matrix
Matrix4f matrix4f = new Matrix4f();
matrix4f.loadTranslate(x, y, 0);
matrix4f.scale(scaleX,scaleX,1);
//满足结合率,所以可以先算变换矩阵
matrix4f.translate(-x,-y,0);
current.multiply(matrix4f);
3、先缩放再平移
这边的1相关是推导出来的公式
m.postScale(scale, scale)
m.postTranslate(-(scale-1)*cx,-(scale-1)*cy)
4、推导的一些公式
指定点放大缩小:位移,中心点,倍数之间最后效果的时候关系
cx,cy:定点x,定点y
dx:平移
s:缩放倍数
dx = -(s-1)*cx = (1-s)*cx
cx = dx/(1-s)
同理
cy = dy/(1-s)
【注】:同样适用于