OpenGLES 矩阵优化
OpenGLES Matrix optimization
我正在 OpenGLES 中渲染 100 多个 3D 对象,我想知道是否可以优化此标准矩阵代码以提高性能速度:
Matrix.setIdentityM(modelMatrix, 0);
Matrix.translateM(modelMatrix, 0, x, y, z);
Matrix.scaleM(modelMatrix, 0, scale,scale,1.0f);
Matrix.rotateM(modelMatrix, 0, angle, 0.0f, 0.0f, 1.0f);
Matrix.multiplyMM(modelViewProjectionMatrix, 0, viewMatrix, 0, modelMatrix, 0);
Matrix.multiplyMM(modelViewProjectionMatrix, 0, projectionMatrix, 0, modelViewProjectionMatrix, 0);
所有对象都以不同的方式缩放、旋转和定位,我的应用程序运行速度太慢。我正在研究许多其他领域,但探查器显示这段代码对性能有很大影响,那么数学可以更快地完成吗?
任何提示,非常感谢。
通过直接输入矩阵值丢失平移、缩放和旋转调用,您可能会收获很多。旋转调用可能会很慢...
矩阵起始 3x3 子矩阵由 3 个基向量(X
、Y
、Z
)组成,可以设置为(在您发布的示例中):
X = (cos(angle)*scale, sin(angle)*scale, .0f)
Y = (-sin(angle)*scale, cos(angle)*scale, .0f)
Z = (.0f, .0f, 1.0f)
注意:顺序取决于实现
接下来的第 4 行或第 4 列(再次取决于订单实施)在您的情况下是翻译:
T = (x, y, z, 1.0f)
仅此一项不会为您带来任何性能,因为 rotate
中也使用了 4 个昂贵的三角函数调用(sin
和 cos
)。如果可能,请尝试丢失角度参数并将其替换为 way
向量,该向量是对象面向的向量。一个标准是还包括 up
向量,它是从对象面朝上的向量。有了这两个向量,您就可以使用前两个向量的叉积来计算 right
向量。结果是有 3 个垂直向量,它们应该被归一化并乘以比例,然后直接插入到矩阵中作为上面提到的 3 个基本向量。
在您的情况下,您可以获得一个方向,并且由于您的 Z
向量似乎是静态的,您可以对这两个向量使用叉积来获得第三个方向。
你的矩阵乘法的结果可以写成:
结果 = ITSR。
对于每个矩阵乘法(我假设矩阵是 4x4),你有 64 次乘法和 64 次加法。现在你有 4 个要相乘的矩阵。这是很多加法和乘法!假设您使用的是列向量。
要加快速度,请执行以下操作:
翻译矩阵将只有最后(第 4)列中的值。因此,当您乘以 IxT 时,生成的矩阵仍将只有第 4 列中的值。所以为了加快速度,只需创建一个矩阵,其中第 4 列是平移向量,就像这样,而不是进行完整的矩阵乘法:
So, we have IT = | 1 0 0 0 | | 1 0 0 tx | | 1 0 0 tx |
| 0 1 0 0 | | 0 1 0 ty | = | 0 1 0 ty |
| 0 0 1 0 | | 0 0 1 tz | | 0 0 1 tz |
| 0 0 0 1 | | 0 0 0 1 | | 0 0 0 1 |
转到 ITxS,因为缩放只影响对角线 - 它只影响元素 m[0][0]、m[1][1] 和 m[2][2],你可以简单地乘以这些元素矩阵的比例。所以我们将有:
Sx = m[0][0] * scale;
Sy = m[1][1] * scale;
Sz = m[2][2] * 1.0;
但是,由于IT中所有的对角线元素都是1,所以你可以直接把scale值写进对角线里……像这样:
ITS = | Sx 0 0 tx |
| 0 Sy 0 ty |
| 0 0 Sz tz |
| 0 0 0 1 |
到目前为止,我们没有执行任何矩阵乘法 - 我们只是手动创建了矩阵。所以你可以创建一个看起来像 ITS 的矩阵。这为您节省了 2 次矩阵乘法!!
现在转到 ITSR ......在这里,只需执行标准矩阵乘法即可:
Result = ITSR = | Sx 0 0 tx | | A D G 0 |
| 0 Sy 0 ty | | B E H 0 |
| 0 0 Sz tz | | C F I 0 |
| 0 0 0 1 | | 0 0 0 1 |
您可以稍微加快速度,但为了清晰起见,只需进行全矩阵乘法。所以你只需要做一个矩阵乘法,而不是 3.
此外,如果您的相机视图没有改变(viewMatrix),则不必为每一帧都推导它,投影矩阵也是如此。不知道你有没有……只是说。
希望这对您有所帮助。
@user3725725 - 我假设您使用的是列向量
Matrix.setIdentityM(modelMatrix, 0);
// Set up the scale
modelMatrix[0] = scale;
modelMatrix[5] = scale;
// Set up Translation
modelMatrix[12] = tx;
modelMatrix[13] = ty;
modelMatrix[14] = tz;
// Do the rest of the matrix multiplication
Matrix.rotateM(modelMatrix, 0, angle, 0.0f, 0.0f, 1.0f);
Matrix.multiplyMM(modelViewProjectionMatrix, 0, viewMatrix, 0, modelMatrix, 0);
Matrix.multiplyMM(modelViewProjectionMatrix, 0, projectionMatrix, 0, modelViewProjectionMatrix, 0);
PS。如果这有帮助,请考虑投赞成票 :) 谢谢!
我正在 OpenGLES 中渲染 100 多个 3D 对象,我想知道是否可以优化此标准矩阵代码以提高性能速度:
Matrix.setIdentityM(modelMatrix, 0);
Matrix.translateM(modelMatrix, 0, x, y, z);
Matrix.scaleM(modelMatrix, 0, scale,scale,1.0f);
Matrix.rotateM(modelMatrix, 0, angle, 0.0f, 0.0f, 1.0f);
Matrix.multiplyMM(modelViewProjectionMatrix, 0, viewMatrix, 0, modelMatrix, 0);
Matrix.multiplyMM(modelViewProjectionMatrix, 0, projectionMatrix, 0, modelViewProjectionMatrix, 0);
所有对象都以不同的方式缩放、旋转和定位,我的应用程序运行速度太慢。我正在研究许多其他领域,但探查器显示这段代码对性能有很大影响,那么数学可以更快地完成吗?
任何提示,非常感谢。
通过直接输入矩阵值丢失平移、缩放和旋转调用,您可能会收获很多。旋转调用可能会很慢...
矩阵起始 3x3 子矩阵由 3 个基向量(X
、Y
、Z
)组成,可以设置为(在您发布的示例中):
X = (cos(angle)*scale, sin(angle)*scale, .0f)
Y = (-sin(angle)*scale, cos(angle)*scale, .0f)
Z = (.0f, .0f, 1.0f)
注意:顺序取决于实现
接下来的第 4 行或第 4 列(再次取决于订单实施)在您的情况下是翻译:
T = (x, y, z, 1.0f)
仅此一项不会为您带来任何性能,因为 rotate
中也使用了 4 个昂贵的三角函数调用(sin
和 cos
)。如果可能,请尝试丢失角度参数并将其替换为 way
向量,该向量是对象面向的向量。一个标准是还包括 up
向量,它是从对象面朝上的向量。有了这两个向量,您就可以使用前两个向量的叉积来计算 right
向量。结果是有 3 个垂直向量,它们应该被归一化并乘以比例,然后直接插入到矩阵中作为上面提到的 3 个基本向量。
在您的情况下,您可以获得一个方向,并且由于您的 Z
向量似乎是静态的,您可以对这两个向量使用叉积来获得第三个方向。
你的矩阵乘法的结果可以写成:
结果 = ITSR。
对于每个矩阵乘法(我假设矩阵是 4x4),你有 64 次乘法和 64 次加法。现在你有 4 个要相乘的矩阵。这是很多加法和乘法!假设您使用的是列向量。
要加快速度,请执行以下操作:
翻译矩阵将只有最后(第 4)列中的值。因此,当您乘以 IxT 时,生成的矩阵仍将只有第 4 列中的值。所以为了加快速度,只需创建一个矩阵,其中第 4 列是平移向量,就像这样,而不是进行完整的矩阵乘法:
So, we have IT = | 1 0 0 0 | | 1 0 0 tx | | 1 0 0 tx |
| 0 1 0 0 | | 0 1 0 ty | = | 0 1 0 ty |
| 0 0 1 0 | | 0 0 1 tz | | 0 0 1 tz |
| 0 0 0 1 | | 0 0 0 1 | | 0 0 0 1 |
转到 ITxS,因为缩放只影响对角线 - 它只影响元素 m[0][0]、m[1][1] 和 m[2][2],你可以简单地乘以这些元素矩阵的比例。所以我们将有:
Sx = m[0][0] * scale;
Sy = m[1][1] * scale;
Sz = m[2][2] * 1.0;
但是,由于IT中所有的对角线元素都是1,所以你可以直接把scale值写进对角线里……像这样:
ITS = | Sx 0 0 tx |
| 0 Sy 0 ty |
| 0 0 Sz tz |
| 0 0 0 1 |
到目前为止,我们没有执行任何矩阵乘法 - 我们只是手动创建了矩阵。所以你可以创建一个看起来像 ITS 的矩阵。这为您节省了 2 次矩阵乘法!!
现在转到 ITSR ......在这里,只需执行标准矩阵乘法即可:
Result = ITSR = | Sx 0 0 tx | | A D G 0 |
| 0 Sy 0 ty | | B E H 0 |
| 0 0 Sz tz | | C F I 0 |
| 0 0 0 1 | | 0 0 0 1 |
您可以稍微加快速度,但为了清晰起见,只需进行全矩阵乘法。所以你只需要做一个矩阵乘法,而不是 3.
此外,如果您的相机视图没有改变(viewMatrix),则不必为每一帧都推导它,投影矩阵也是如此。不知道你有没有……只是说。
希望这对您有所帮助。
@user3725725 - 我假设您使用的是列向量
Matrix.setIdentityM(modelMatrix, 0);
// Set up the scale
modelMatrix[0] = scale;
modelMatrix[5] = scale;
// Set up Translation
modelMatrix[12] = tx;
modelMatrix[13] = ty;
modelMatrix[14] = tz;
// Do the rest of the matrix multiplication
Matrix.rotateM(modelMatrix, 0, angle, 0.0f, 0.0f, 1.0f);
Matrix.multiplyMM(modelViewProjectionMatrix, 0, viewMatrix, 0, modelMatrix, 0);
Matrix.multiplyMM(modelViewProjectionMatrix, 0, projectionMatrix, 0, modelViewProjectionMatrix, 0);
PS。如果这有帮助,请考虑投赞成票 :) 谢谢!