我试图将一架飞机安装到3D空间中的一组点上。我最初尝试了一个详尽的最小二乘法,但事实证明这太慢了。我读到最有效的解决方案是执行奇异值分解。
这方面的数学超出了我的要求,但我找到了一堆资源来尝试让它发挥作用。
根据this post中的答案,我需要计算点的质心,从所有点中减去质心,将它们放入3xN矩阵并执行SVD。然后我将左奇异向量作为平面的法线。
到目前为止一切顺利。
我找到了一个名为alglib的C#数学库,它具有SVD功能。可以找到算法的定义here。这就是我遇到问题的地方,因为除了数据点矩阵之外,它还需要两个矩阵作为输入,我并不真正理解它们应该放在什么内容中。无论如何,我都运行了这段代码:
Vector3 centroid = getCentroid(planeVerts);
double[,] dataMat = substractCentroid(planeVerts, centroid);
double[] w = new double[3];
double[,] u = new double[1,1];
double[,] t = new double[1, 1];
bool a = alglib.svd.rmatrixsvd(dataMat, 3, planeVerts.Length, 0, 0, 2, ref w, ref u, ref t);
Vector3 planeNorm = new Vector3((float) w[0], (float) w[1], (float) w[2]);
所以理论上我认为" w"将包含我的飞机正常,但不幸的是它没有(我在Unity3D中可视化它并且它是在错误的角度)。 " u"和" t"矩阵是令我困惑的,我不知道应该把它们设置为什么。
可以找到rmatrixsvd函数的详细API here。
是否有任何数学或算法资深人士能够分享他们对此事的知识?我需要使用C#,因为我的项目在Unity3D中。如果需要,我很乐意提供更多信息。
答案 0 :(得分:2)
查看文档,看起来w将包含您的奇异值,U将包含左奇异向量,V将包含正确的奇异向量。由于dataMat是3xN,因此U应为3x3,V应为NxN。正如你所说,你需要左边的奇异向量,设置UNeeded = 1并且只取U的第一列。因为你不需要正确的奇异向量,你也可以设置VNeeded = 0.