首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >高效4x4矩阵求逆(仿射变换)

高效4x4矩阵求逆(仿射变换)
EN

Stack Overflow用户
提问于 2010-04-13 02:33:51
回答 5查看 44.4K关注 0票数 33

我希望有人能指出一个有效的4x4仿射矩阵变换公式。目前,我的代码使用余因子扩展,它为每个余因子分配一个临时数组。它很容易阅读,但比它应该的速度慢。

注意,这不是家庭作业,我知道如何使用4x4余因子展开手动解决它,这对我来说是一个痛苦的问题,也不是一个真正有趣的问题。此外,我已经谷歌了,并提出了一些网站,已经给你的公式(http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm)。然而,通过预先计算一些产品,这一点可能会进一步优化。我敢肯定有人在某一时刻想出了解决这个问题的“最佳”公式?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2010-04-13 05:00:20

您应该能够利用矩阵是仿射的这一事实来加快全逆运算的速度。也就是说,如果你的矩阵看起来像这样

代码语言:javascript
复制
A = [ M   b  ]
    [ 0   1  ]

其中A是4x4,M是3x3,b是3x1,底行是(0,0,0,1),则

代码语言:javascript
复制
inv(A) = [ inv(M)   -inv(M) * b ]
         [   0            1     ]

根据您的情况,计算inv(A) *x的结果可能比实际形成inv(A)更快。在这种情况下,事情简化为

代码语言:javascript
复制
inv(A) * [x] = [ inv(M) * (x - b) ]
         [1] = [        1         ] 

其中x是3x1向量(通常是三维点)。

最后,如果M表示旋转(即它的列是正交的),那么您可以使用inv(M) = transpose(M)这一事实。然后,计算A的逆只是减去平移分量,然后乘以3x3部分的转置。

请注意,您应该从问题的分析中知道矩阵是否为正交的。在运行时检查它将是相当昂贵的;尽管您可能希望在调试构建中进行检查,以检查您的假设是否成立。

希望这一切都清楚了。

票数 49
EN

Stack Overflow用户

发布于 2011-09-29 19:58:21

如果有人想省去一些输入,这是我基于phkahler发布的链接的第9页(更有效的拉普拉斯展开定理)编写的AS3版本:

代码语言:javascript
复制
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转换矩阵乘以此方法返回的逆矩阵时,这成功地产生了一个单位矩阵。我相信你可以通过搜索/替换把它翻译成你想要的任何语言。

票数 22
EN

Stack Overflow用户

发布于 2012-03-08 16:03:19

为了跟进上面pkhalerRobin Hilliard的出色响应,这里是罗宾的ActionScript 3代码转换成C#方法。希望这可以为其他C#开发人员以及需要4x4矩阵求逆函数的C/C++和Java开发人员节省一些输入:

代码语言:javascript
复制
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;
}
票数 20
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2624422

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档