[OpenGL]矩阵乘法引发的血案
来源:互联网 发布:大数据与软件工程 编辑:程序博客网 时间:2024/06/02 00:48
最近被矩阵乘法折腾的死去活来,感觉要打回去重新学线代了。
Matrix定义
OpenGL中Matrix被定义成一个列主序的矩阵,大小为3x3或者4x4
/** * Matrix math utilities. These methods operate on OpenGL ES format * matrices and vectors stored in float arrays. * <p> * Matrices are 4 x 4 column-vector matrices stored in column-major * order: * <pre> * 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]</pre> * * Vectors are 4 x 1 column vectors stored in order: * <pre> * v[offset + 0] * v[offset + 1] * v[offset + 2] * v[offset + 3]</pre> */
Matrix.multiplyMM在干什么
函数原型:
public static native void multiplyMM(float[] result, int resultOffset, float[] lhs, int lhsOffset, float[] rhs, int rhsOffset);
看起来好像挺简单,就是把左边的矩阵和右边的矩阵乘起来放到结果里面去,但是之前说到Matrix是列主序的,那乘法到底是怎么操作的呢?
我们知道常规的行主序的矩阵乘法,结果的第一行第一列的元素是由lhs的第一行和rhs第一列相乘累加得到的,那既然这个矩阵是列主序的,是不是lhs的第一列和rhs的第一行呢?
这是个native函数,直接上代码:
#define I(_i, _j) ((_j)+ 4*(_i))float sTemp[16];void multiplyMM(float* r, const float* lhs, const float* rhs) { for (int i=0 ; i<4 ; i++) { register const float rhs_i0 = rhs[ I(i,0) ]; register float ri0 = lhs[ I(0,0) ] * rhs_i0; register float ri1 = lhs[ I(0,1) ] * rhs_i0; register float ri2 = lhs[ I(0,2) ] * rhs_i0; register float ri3 = lhs[ I(0,3) ] * rhs_i0; for (int j=1 ; j<4 ; j++) { register const float rhs_ij = rhs[ I(i,j) ]; ri0 += lhs[ I(j,0) ] * rhs_ij; ri1 += lhs[ I(j,1) ] * rhs_ij; ri2 += lhs[ I(j,2) ] * rhs_ij; ri3 += lhs[ I(j,3) ] * rhs_ij; } r[ I(i,0) ] = ri0; r[ I(i,1) ] = ri1; r[ I(i,2) ] = ri2; r[ I(i,3) ] = ri3; }}
看完代码以后,我发现这个乘法还是lhs的第一行和rhs第一列呀。
貌似列主序只是存取的方式有变化,矩阵还是那个矩阵,乘法还是那个乘法。
OpenGL矩阵乘法顺序
* Multiplies two 4x4 matrices together and stores the result in a third 4x4 * matrix. In matrix notation: result = lhs x rhs. Due to the way * matrix multiplication works, the result matrix will have the same * effect as first multiplying by the rhs matrix, then multiplying by * the lhs matrix. This is the opposite of what you might expect.
Android的Matrix(OpenGL)类中有一段话,说虽然乘法的结果是lhs x rhs,但是结果相当于先乘上rhs,再乘上lhs
我们使用glsl并且在Java层传递MVP矩阵的时候,乘法顺序是这样的:
//P * V * M * TMatrix.multiplyMM(modelViewMatrix, 0, viewMatrix, 0, modelMatrix, 0);Matrix.multiplyMM(mMVPMatrix, 0, projectionMatrix, 0, modelViewMatrix, 0);
相当于对于一个顶点(用列主序向量表示),先左乘model转换成世界坐标,再左乘view转换成眼坐标,再左乘projection转换成裁剪坐标
对于modelMatrix,平移操作在旋转操作之前,因为旋转后参考的坐标轴也会发生改变
但是viewMatrix刚好相反,是先旋转再平移因为相机的姿态变化相当于世界坐标的反向变化,如果对viewMatrix取逆,那么就相当于求出了相机(想象的概念)在世界坐标系下面的位置和姿态。
但是使用gl原生接口(OpenGL1.0时),是这样子的
glMatrixMode(GL_PROJECTION);glLoadMatrixf(projectionM);glMatrixMode(GL_MODELVIEW);glLoadMatrixf(viewM);glMultMatrixf(modelM);//draw points
执行glMultMatrixf(M)以后,相当于当前的矩阵C=V变成了C=M*V 。虽然代码执行顺序刚好相反,但是结果是一样的。
坐标系重映射
有些时候我们需要将一个坐标系映射到另外一个坐标系,先来看下面的代码
Matrix.setIdentityM(tmpMatrix,0);Matrix.rotateM(tmpMatrix,0, +180.0f, 1.0f, 0.0f, 0.0f);
结果是什么呢?应该是一个这样的矩阵:
1.0 0.0 0.0 0.00.0 -1.0 0.0 0.00.0 0.0 -1.0 0.00.0 0.0 0.0 1.0
如果用这个矩阵左乘上当前矩阵M,相当于翻转当前矩阵的第二行和第三行,如果是右乘,则是翻转第二列和第三列。
- [OpenGL]矩阵乘法引发的血案
- ActiveX引发的“血案”
- size_t引发的血案
- 一个 * 引发的血案
- gets引发的血案
- Print 引发的“血案”
- lease引发的血案
- 一个“-”引发的血案
- MD5引发的血案
- 一个"/"引发的血案
- wrap_content引发的血案
- merge_all引发的血案
- PersistableBundle引发的血案
- 看球引发的血案
- 一个松果引发的血案
- 一个memset引发的血案
- 一条语句引发的血案
- 一条短信引发的血案
- 网络电视精灵
- C++ delete错误
- 归并排序
- 搬家结束~~~
- sqlalchemy一对多的关系表案例
- [OpenGL]矩阵乘法引发的血案
- Codeforces Beta Round #17 C. Balance DP
- Matplotlib进阶:Seaborn教程
- JSON之stringify()、parse()
- Java提高篇(二六)------hashCode
- [nginx] upstream结束和keepalive实现
- spring的学习(二)
- 跟踪分析Linux内核的启动过程
- 传输层协议