From the sources of android.opengl.Matrix.translateM(float[] m, int mOffset, float x, float y, float z)
:
/**
* Translates matrix m by x, y, and z in place.
* @param m matrix
* @param mOffset index into m where the matrix starts
* @param x translation factor x
* @param y translation factor y
* @param z translation factor z
*/
public static void translateM(
float[] m, int mOffset,
float x, float y, float z) {
for (int i=0 ; i<4 ; i++) {
int mi = mOffset + i;
m[12 + mi] += m[mi] * x + m[4 + mi] * y + m[8 + mi] * z;
}
}
The question is about this line (or the entire for-loop):
m[12 + mi] += m[mi] * x + m[4 + mi] * y + m[8 + mi] * z;
Why x, y and z components of translate parameters are multiplied to the source matrix components here? Shouldn't it be simple this (this lines replace the entire for-cycle):
m[12 + mi] += x;
m[13 + mi] += y;
m[14 + mi] += z;
Background of the problem:
I am doing some 2d game in OpenGL ES 2.0. I whant to scale and move some object there. While I simple move it:
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, x, y, 0);
all goes fine. As soon as I do scaling before moving - at this time moving translations:
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.scaleM(mModelMatrix, 0, xScaleFactor, yScaleFactor, 1);
Matrix.translateM(mModelMatrix, 0, x, y, 0);
are in fact multiplied by scaling :(
OpenGL is column-major, the proper order for Scaling, Rotation and Translation is actually Translation * Rotation * Scaling
. In D3D and any row-major matrix library, Scale * Rotate * Translate
would be correct. You have to think about things from right-to-left when you use column-major matrices.
Alternatively, you could transpose each matrix before multiplication - it is usually simpler just to follow the canonical order for column-major matrix multiplication though. Note that this applies to things like Position * Model * View * Projection
(D3D / row-major) as well, in GL (column-major) the proper order is Projection * View * Model * Position
.