有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java为什么不支持安卓。opengl。矩阵translateM()是否会产生意外的结果?

从{}的{a1}开始:

/**
 * 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;
    }
}

问题是关于这一行(或整个for循环):

m[12 + mi] += m[mi] * x + m[4 + mi] * y + m[8 + mi] * z;

为什么平移参数的x、y和z分量在此处与源矩阵分量相乘?这不是很简单吗(这一行代替了整个for循环):

m[12 + mi] += x;
m[13 + mi] += y;
m[14 + mi] += z;

问题背景

我正在用OpenGLES2.0做一些2d游戏。我不想在那里缩放和移动一些物体。我只是简单地移动它:

Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, x, y, 0);

一切顺利。一旦我在移动前进行缩放-此时移动平移:

Matrix.setIdentityM(mModelMatrix, 0);
Matrix.scaleM(mModelMatrix, 0, xScaleFactor, yScaleFactor, 1);
Matrix.translateM(mModelMatrix, 0, x, y, 0);

事实上是乘以比例:(


共 (2) 个答案

  1. # 1 楼答案

    OpenGL是以列为主的,缩放、旋转和平移的正确顺序实际上是Translation * Rotation * Scaling。在D3D和任何行主矩阵库中,Scale * Rotate * Translate都是正确的。使用列主矩阵时,必须从右到左考虑问题

    或者,您可以在乘法之前对每个矩阵进行转置——不过,只遵循列主矩阵乘法的规范顺序通常更简单。请注意,这也适用于Position * Model * View * Projection(D3D/行主调)之类的事情,在GL(列主调)中,正确的顺序是Projection * View * Model * Position

  2. # 2 楼答案

    translateM模拟mXT矩阵乘法,其中T是转换矩阵

    翻译矩阵类似于单位矩阵(对角线1),最后一列为翻译的x,y,z,1。(1是用于同质坐标的,我将不深入讨论)

    假设您知道矩阵乘法(其中第一个操作数的每一行由第二个操作数的每一列按对互乘),它利用转换矩阵T的细节,走捷径:

    它实际上并不创建转换矩阵T,而是模拟乘法m x T。大多数值都不会更改(因为这部分类似于单位矩阵),所以它只需要计算更改的值(涉及T的最后一列)

    每个循环迭代以成对方式将m的一行乘以转换矩阵的最后一列(即x,y,z,1)。代码行应该是(其中im的行和T的列):

    m[12+i] = m[0+i]*x + m[4+i]*y + m[8+i]*z + m[12+i]*1f;
    

    但是他们用+=操作符简化了它;使用mi作为偏移量;并省略0+

    不改变的元素可以留在那里,因为这个版本的translateM是“就地”的

    请记住,它使用主列形式的矩阵,带有索引:

    0  4  8  12
    1  5  9  13
    2  6  10 14
    3  7  11 15
    

    在遍历数组时,向下遍历列中的每个元素,并在其末尾遍历下一列,以此类推。因此,行i和列j中的元素位于m[i + 4*j]。也就是说,向下是+1,穿过是+4。thr next(另一种方式是行主键,在这里您可以穿过一行,向下到下一行等。更直观的打印方式,但不是android.opengl.Matrix使用的方式。)


    你的scaleM那么translateM等价于S x T(缩放矩阵S,平移矩阵T)。效果是从右向左(即向后),首先是平移,然后是缩放。因此,翻译也得到了扩展

    正如公认的答案所说,做translateM然后scaleM(即T x S)具有缩放然后翻译的效果(因此翻译不缩放)

    考虑这一点的一种方法是,这个矩阵最终将被一个列向量v:(T x S) x v相乘。从不同的角度开始,用S x v = v'缩放v,然后用T x v'转换结果,我们可以将它们组合为T x (S x v)。这似乎很自然,缩放必须是第一位的。也许令人惊讶的是,因为矩阵乘法是关联的,所以它与(T x S) x v相同。如果我们忽略最后一个x v(在GPU上完成),我们有T x S,这意味着“缩放,然后转换”。最靠近右边的矩阵首先完成

    顺便说一句,矩阵乘法的关联性类似于java字符串串联,其中求值顺序无关紧要,其中(a+b)+c = a+(b+c)(尽管操作数的顺序无关紧要,例如a+b+c != c+b+a-两者都不是可交换的)。这意味着我们可以先选择适合我们的部分


    顺便说一句:这里有几个层次:矩阵乘法、排序效果、齐次坐标、平移矩阵、乘法排序效果、列主形式、上面的乘法捷径、+=mOffset,mi`(对于一个数组中的多个矩阵)

    很多编程都可以理解,但对于这一点,最好是依次进入每一层的顶部