如何最小化3D空间中围绕任意轴旋转点的浮点误差?

时间:2015-04-07 16:07:27

标签: c# opengl rotation floating-point opentk

我有一个可以在3D空间上显示平移和旋转的程序。我对主代码没有任何问题,但经过几个小时的测试后发现导致不准确的功能是任意轴上的旋转。

我的对象包含点数组,以及三个向量,它们是局部轴。我使用这些轴的旋转功能。当我的位置位于原点时,该功能很有效,但是一旦将该点转换为原点以外,它会显示略微错误的旋转,直到该点不合适为止。

我已经使用此website作为我的向导,请跳到页面底部的6.2并查看带有10个参数的函数。在同一页面上,该进程的示例用法为link。我已经确认问题在于此应用程序的浮点不准确。

我希望旋转的采样点:(0,-9,0) 与旋转轴相交的点:(0,-10,0) 旋转轴的方向矢量:< 1,0,0> 旋转角度:2度

对于每个循环,当前点旋转2度,并重复20次。第一次迭代的正确Y值是-9.0006,而在我的情况下,它给出-8.9945并且连续波动直到第5次或第6次迭代,然后在这些迭代之后显示正确的值。

这是旋转功能,请注意是您要旋转的点, AxisPoint 是与旋转轴相交的点, AxisDirection < / strong>是平行于旋转轴的方向向量,是要旋转的角度量:

private static Vector3d RotateArbitrary(Vector3d Point, Vector3d AxisPoint, Vector3d AxisDirection, double Degrees)
    {
        return new Vector3d(
            ((AxisPoint.X * (Math.Pow(AxisDirection.Y, 2) + Math.Pow(AxisDirection.Z, 2)) - AxisDirection.X * (AxisPoint.Y * AxisDirection.Y + AxisPoint.Z * AxisDirection.Z - AxisDirection.X * Point.X - AxisDirection.Y * Point.Y - AxisDirection.Z * Point.Z)) * (1 - Math.Cos(MathHelper.DegreesToRadians(Degrees))) + Point.X * Math.Cos(MathHelper.DegreesToRadians(Degrees)) + (-AxisPoint.Z * AxisDirection.Y + AxisPoint.Y * AxisDirection.Z - AxisDirection.Z * Point.Y + AxisDirection.Y * Point.Z) * Math.Sin(MathHelper.DegreesToRadians(Degrees))),
            ((AxisPoint.X * (Math.Pow(AxisDirection.X, 2) + Math.Pow(AxisDirection.Z, 2)) - AxisDirection.Y * (AxisPoint.X * AxisDirection.X + AxisPoint.Z * AxisDirection.Z - AxisDirection.X * Point.X - AxisDirection.Y * Point.Y - AxisDirection.Z * Point.Z)) * (1 - Math.Cos(MathHelper.DegreesToRadians(Degrees))) + Point.Y * Math.Cos(MathHelper.DegreesToRadians(Degrees)) + (AxisPoint.Z * AxisDirection.X - AxisPoint.X * AxisDirection.Z + AxisDirection.Z * Point.X - AxisDirection.X * Point.Z) * Math.Sin(MathHelper.DegreesToRadians(Degrees))),
            ((AxisPoint.X * (Math.Pow(AxisDirection.X, 2) + Math.Pow(AxisDirection.Y, 2)) - AxisDirection.Z * (AxisPoint.X * AxisDirection.X + AxisPoint.Y * AxisDirection.Y - AxisDirection.X * Point.X - AxisDirection.Y * Point.Y - AxisDirection.Z * Point.Z)) * (1 - Math.Cos(MathHelper.DegreesToRadians(Degrees))) + Point.Z * Math.Cos(MathHelper.DegreesToRadians(Degrees)) + (-AxisPoint.Y * AxisDirection.X + AxisPoint.X * AxisDirection.Y - AxisDirection.Y * Point.X + AxisDirection.X * Point.Y) * Math.Sin(MathHelper.DegreesToRadians(Degrees)))
            );
    }

我已经尝试了float和double数据类型,结果仍然相同,你可以提供任何解决方案,甚至改变旋转方法,我都是开放的。请帮忙。

1 个答案:

答案 0 :(得分:0)

由于我冗长的网络搜索,我终于得出结论我应该使用Quaternions。使用当前方法,我发现对浮点变量的过度操作会增加舍入误差。使用Quaternions更简单,更清洁。

以下是有兴趣的代码:

private static Vector3 RotateArbitrary(Vector3 Point, Vector3 AxisPoint, Vector3 AxisDirection, float Radians)
        {
            return Vector3.Add(Vector3.Transform(Vector3.Subtract(Point, AxisPoint), Quaternion.FromAxisAngle(AxisDirection, Radians)), AxisPoint);
        }

请注意,Point首先被翻译为AxisPoint位于原点,因此可以完成旋转。然后将结果转换为其原始位置。