这个答案不是原创的,它只是为了方便那些想要@rhashimoto 提供的正确答案的 Unity 用户,为他们制定。我的贡献(希望)是提供代码,通过丢弃所有零结果,将正常的 16 次乘法和 12 次加法(假设 Unity 仅执行 4x4 矩阵)减少到 2 次乘法和 2 次加法。我通过测试跑了不到一百万点,每次检查我的计算是否与基本矩阵计算一致 - 定义为两个结果之间的绝对差异小于机器 epsilon - 我对此感到满意要知道@rhashimoto 可能会出现并在其中戳一个大洞:-)
如果要来回切换,请记住这是 C#,因此 USEMATRIXMATH 定义必须出现在文件开头。
鉴于目前只有一个 Tango 设备,并且我假设所有设备的内在函数都是恒定的,我只是将它们作为常量转储,这样
fx = 1042.73999023438
fy = 1042.96997070313
cx = 637.273986816406
cy = 352.928985595703
k1 = 0.228532999753952
k2 = -0.663019001483917
k3 = 0.642908990383148
是的,它们可以作为常量转储,这将使内容更具可读性,而且 C# 可能足够聪明,可以对其进行优化 - 但是,我在 Agner Fogg 的东西上花费了太多时间,而且总是偏执。
底部注释掉的代码用于测试差异,如果您愿意的话。如果您想测试结果,您必须取消注释一些其他内容,并注释掉返回值。
再次感谢@rhashimoto,这比我拥有的要好得多
我一直忠实于他的逻辑,记住这些是像素坐标,而不是 UV 坐标 - 他是正确的,您可以预乘变换以获得标准化的 UV 值,但既然他已经教过我一次,我会坚持正是他在我摆弄太多之前提出的数学:-)
static public Vector2 PictureUV(Vector3 tangoDepthPoint)
{
Vector2 imageCoords = new Vector2(tangoDepthPoint.x / tangoDepthPoint.z, tangoDepthPoint.y / tangoDepthPoint.z);
float r2 = Vector2.Dot(imageCoords, imageCoords);
float r4 = r2*r2;
float r6 = r2*r4;
imageCoords *= 1.0f + 0.228532999753952f*r2 + -0.663019001483917f*r4 + 0.642908990383148f*r6;
Vector3 ic3 = new Vector3(imageCoords.x,imageCoords.y,1);
#if USEMATRIXMATH
Matrix4x4 cameraTransform = new Matrix4x4();
cameraTransform.SetRow(0,new Vector4(1042.73999023438f,0,637.273986816406f,0));
cameraTransform.SetRow(1, new Vector4(0, 1042.96997070313f, 352.928985595703f, 0));
cameraTransform.SetRow(2, new Vector4(0, 0, 1, 0));
cameraTransform.SetRow(3, new Vector4(0, 0, 0, 1));
Vector3 pixelCoords = cameraTransform * ic3;
return new Vector2(pixelCoords.x, pixelCoords.y);
#else
//float v1 = 1042.73999023438f * imageCoords.x + 637.273986816406f;
//float v2 = 1042.96997070313f * imageCoords.y + 352.928985595703f;
//float v3 = 1;
return new Vector2(1042.73999023438f * imageCoords.x + 637.273986816406f,1042.96997070313f * imageCoords.y + 352.928985595703);
#endif
//float dx = Math.Abs(v1 - pixelCoords.x);
//float dy = Math.Abs(v2 - pixelCoords.y);
//float dz = Math.Abs(v3 - pixelCoords.z);
//if (dx > float.Epsilon || dy > float.Epsilon || dz > float.Epsilon)
// UnityEngine.Debug.Log("Well, that didn't work");
//return new Vector2(v1, v2);
}
最后一点,请注意他提供的代码是 GLSL - 如果您只是将它用于漂亮的图片,请使用它 - 这是用于那些实际需要执行额外处理的代码。