Opengl 关于矩阵变换操作效果理解-1

对于初学Opengl的同学来说,经常会碰到这样一个问题。一个模型经过平移、缩放、旋转等变化后的效果为什么和我想象的不一样!!!为了解决这个问题,下面谈一下个人对矩阵变换实际产生效果的理解。

在这之前我们先来看一下这个方法

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

这个方法的结果是将两个矩阵相乘,Opengl中的意义是将两个变换矩阵的效果组合起来。那么问题来了这个组合的效果是先执行lhs矩阵还是rhs矩阵呢?

查阅资料我们会得到这样一个结果,Opengl中的矩阵是以列主序来存储的,所以点的变换是左乘(前乘)变换矩阵。ok,我们现在有了依据即变换后的点P’是原始点P左乘变换矩阵M得到的结果。表达式如下:

P’= M * P
那么假设上面的矩阵M是由两个矩阵Ml(lhs),Mr(rhs)组合得到的,根据multiplyMM方法的定义有 :
M = Ml*Mr
带人上式得:
P’= Ml * MR * P
根据矩阵乘法的结合了有:
P’= Ml * (MR * P)
到这里之前的问题就得到了解答,利用multiplyMM得到的组合矩阵的执行效果是先执行右边的矩阵(rhs)后执行左边矩阵(lhs)。好了那我们看如下这段代码

float[] vec=new float[]{1,5,8,1}

float[] fMatrix = new float[16];
Matrix.setIdentityM(fMatrix,0);//初始一个单位矩阵
Matrix.transLateM(fMatrix,0,0,0,3);//向z平移3个单位
Matrix.rotateM(fMatrix,0,90,0,1,0);//以Y轴为基准旋转90度 *注1

float[] rVec = new float[4];
Matrix.multiplyMV(rVec,0,fMatrix,0,vec,0);

大家来猜想下rVec的结果,如果你得到的是rVec=[11,5,-1,1]恭喜你已经踩坑里了。这段代码最后执行的结果是rVec=[8,5,2,1]。我们来剖析以下代码看看到底发生了什么?

Matix.setIdentityM和Matix.transLateM没有什么问题不做解释,问题就出在Matrix.rotateM这个方法上。来看下这个方法在做什么:

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

我们看到这个方法里根据传入的旋转参数,将一个临时的矩阵sTemp变为一个旋转矩阵,然后重点来了这里利用了multiplyMM方法将两个矩阵进行了组合并且将旋转矩阵放在了右边,通过之前我们的研究知道了multiplyMM方法会先执行右边矩阵的效果。那好经过这个rotateM方法后我们实际是先执行了旋转然后才执行了之前设置的平移变换。

看到这里大家怎么想。WTF!这么搞代码要倒着写不成?为什么要这样很容易弄错啊。

其实产生这种结果的原因,是由于我们的所有变换是以世界坐标系为基准来进行的。还有一种办法来理解这段代码的变换效果。那就是以物体的坐标系为基准(或者理解为将变换作用在物体的坐标系上)来看这个问题。之前的变换步骤可以理解成如下效果:
1.将物体的坐标系沿物体坐标系Z方向移动3个单位。
2.以物体坐标系Y轴为基准将物体的坐标系逆时针旋转90度
现在我们来想象Vec经过如上变换后在世界坐标系中的位置是不是就得到了[8,5,2,1]的结果。
记得这种方法所有的操作都要基于当前物体坐标系的情况来理解(平移,旋转,缩放)大多数情况下用这种方法会比较好理解,但如果加入了缩放理解起来就又有些困难了因为物体坐标系缩放会导致x,y,z方向1单位大小改变,请大家在实际使用中细细体会,根据自己习惯选择理解方法。

最后我们总结下变换矩阵相乘叠加效果的理解:
1.当我们以世界坐标系为基准时,右边的矩阵为先执行效果。
2.当我们以物体坐标系为基准时,左边的矩阵为先执行效果。

以上就是个人对Opengl坐标系和矩阵变换操作的理解,希望对大家有帮助,也希望大家补充和纠正。


*注
1.Opengl中旋转方向:看向旋转轴负方向,逆时针旋转方向为正值。

你可能感兴趣的:(opengl)