我希望有人可以指出4x4仿射矩阵变换的有效公式.目前我的代码使用辅助因子扩展,并为每个辅助因子分配一个临时数组.它很容易阅读,但它应该比它应该慢.
请注意,这不是作业,我知道如何使用4x4辅助因子扩展手动完成它,这只是一个痛苦,对我来说并不是一个真正有趣的问题.我也用谷歌搜索了一些网站,它们已经为你提供了公式(http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm).然而,通过预先计算一些产品,可能会进一步优化这一点.我敢肯定有人在某个时刻想出了"最好"的公式吗?
你应该能够利用矩阵是仿射的事实来加速完全反转.也就是说,如果您的矩阵看起来像这样
A = [ M b ] [ 0 1 ]
其中A是4x4,M是3x3,b是3x1,底行是(0,0,0,1),然后
inv(A) = [ inv(M) -inv(M) * b ] [ 0 1 ]
根据您的情况,计算inv(A)*x的结果可能更快,而不是实际形成inv(A).在这种情况下,事情简化为
inv(A) * [x] = [ inv(M) * (x - b) ] [1] = [ 1 ]
其中x是3x1向量(通常是3D点).
最后,如果M代表一个旋转(即它的列是正交的),那么你可以使用inv(M)= transpose(M)的事实.然后计算A的倒数只是减去平移分量,并乘以3x3部分的转置.
请注意,矩阵是否是正交矩阵是您应该从问题分析中了解到的.在运行期间检查它会相当昂贵; 虽然您可能希望在调试版本中执行此操作以检查您的假设是否成立.
希望所有这些都清楚......
为了防止有人想保存一些打字,这是我在上面由phkahler发布的链接第9页(拉普拉斯扩展定理的更有效版本)编写的AS3版本:
public function invert() : Matrix4 { var m : Matrix4 = new Matrix4(); var s0 : Number = i00 * i11 - i10 * i01; var s1 : Number = i00 * i12 - i10 * i02; var s2 : Number = i00 * i13 - i10 * i03; var s3 : Number = i01 * i12 - i11 * i02; var s4 : Number = i01 * i13 - i11 * i03; var s5 : Number = i02 * i13 - i12 * i03; var c5 : Number = i22 * i33 - i32 * i23; var c4 : Number = i21 * i33 - i31 * i23; var c3 : Number = i21 * i32 - i31 * i22; var c2 : Number = i20 * i33 - i30 * i23; var c1 : Number = i20 * i32 - i30 * i22; var c0 : Number = i20 * i31 - i30 * i21; // Should check for 0 determinant var invdet : Number = 1 / (s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0); m.i00 = (i11 * c5 - i12 * c4 + i13 * c3) * invdet; m.i01 = (-i01 * c5 + i02 * c4 - i03 * c3) * invdet; m.i02 = (i31 * s5 - i32 * s4 + i33 * s3) * invdet; m.i03 = (-i21 * s5 + i22 * s4 - i23 * s3) * invdet; m.i10 = (-i10 * c5 + i12 * c2 - i13 * c1) * invdet; m.i11 = (i00 * c5 - i02 * c2 + i03 * c1) * invdet; m.i12 = (-i30 * s5 + i32 * s2 - i33 * s1) * invdet; m.i13 = (i20 * s5 - i22 * s2 + i23 * s1) * invdet; m.i20 = (i10 * c4 - i11 * c2 + i13 * c0) * invdet; m.i21 = (-i00 * c4 + i01 * c2 - i03 * c0) * invdet; m.i22 = (i30 * s4 - i31 * s2 + i33 * s0) * invdet; m.i23 = (-i20 * s4 + i21 * s2 - i23 * s0) * invdet; m.i30 = (-i10 * c3 + i11 * c1 - i12 * c0) * invdet; m.i31 = (i00 * c3 - i01 * c1 + i02 * c0) * invdet; m.i32 = (-i30 * s3 + i31 * s1 - i32 * s0) * invdet; m.i33 = (i20 * s3 - i21 * s1 + i22 * s0) * invdet; return m; }
当我将各种3D变换矩阵乘以从该方法返回的逆时,这成功地产生了单位矩阵.我相信你可以搜索/替换你想要的任何语言.
为了跟进pkhaler和Robin Hilliard上面的优秀回答,这里是Robin的ActionScript 3代码转换为C#方法.希望这可以为其他C#开发人员以及需要4x4矩阵反转功能的C/C++和Java开发人员节省一些输入:
public static double[,] GetInverse(double[,] a) { var s0 = a[0, 0] * a[1, 1] - a[1, 0] * a[0, 1]; var s1 = a[0, 0] * a[1, 2] - a[1, 0] * a[0, 2]; var s2 = a[0, 0] * a[1, 3] - a[1, 0] * a[0, 3]; var s3 = a[0, 1] * a[1, 2] - a[1, 1] * a[0, 2]; var s4 = a[0, 1] * a[1, 3] - a[1, 1] * a[0, 3]; var s5 = a[0, 2] * a[1, 3] - a[1, 2] * a[0, 3]; var c5 = a[2, 2] * a[3, 3] - a[3, 2] * a[2, 3]; var c4 = a[2, 1] * a[3, 3] - a[3, 1] * a[2, 3]; var c3 = a[2, 1] * a[3, 2] - a[3, 1] * a[2, 2]; var c2 = a[2, 0] * a[3, 3] - a[3, 0] * a[2, 3]; var c1 = a[2, 0] * a[3, 2] - a[3, 0] * a[2, 2]; var c0 = a[2, 0] * a[3, 1] - a[3, 0] * a[2, 1]; // Should check for 0 determinant var invdet = 1.0 / (s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0); var b = new double[4, 4]; b[0, 0] = ( a[1, 1] * c5 - a[1, 2] * c4 + a[1, 3] * c3) * invdet; b[0, 1] = (-a[0, 1] * c5 + a[0, 2] * c4 - a[0, 3] * c3) * invdet; b[0, 2] = ( a[3, 1] * s5 - a[3, 2] * s4 + a[3, 3] * s3) * invdet; b[0, 3] = (-a[2, 1] * s5 + a[2, 2] * s4 - a[2, 3] * s3) * invdet; b[1, 0] = (-a[1, 0] * c5 + a[1, 2] * c2 - a[1, 3] * c1) * invdet; b[1, 1] = ( a[0, 0] * c5 - a[0, 2] * c2 + a[0, 3] * c1) * invdet; b[1, 2] = (-a[3, 0] * s5 + a[3, 2] * s2 - a[3, 3] * s1) * invdet; b[1, 3] = ( a[2, 0] * s5 - a[2, 2] * s2 + a[2, 3] * s1) * invdet; b[2, 0] = ( a[1, 0] * c4 - a[1, 1] * c2 + a[1, 3] * c0) * invdet; b[2, 1] = (-a[0, 0] * c4 + a[0, 1] * c2 - a[0, 3] * c0) * invdet; b[2, 2] = ( a[3, 0] * s4 - a[3, 1] * s2 + a[3, 3] * s0) * invdet; b[2, 3] = (-a[2, 0] * s4 + a[2, 1] * s2 - a[2, 3] * s0) * invdet; b[3, 0] = (-a[1, 0] * c3 + a[1, 1] * c1 - a[1, 2] * c0) * invdet; b[3, 1] = ( a[0, 0] * c3 - a[0, 1] * c1 + a[0, 2] * c0) * invdet; b[3, 2] = (-a[3, 0] * s3 + a[3, 1] * s1 - a[3, 2] * s0) * invdet; b[3, 3] = ( a[2, 0] * s3 - a[2, 1] * s1 + a[2, 2] * s0) * invdet; return b; }