
Quaternion rotation bug
Posted Friday, 6 May, 2011 - 20:14 by nothing1212| Project: | The Open Toolkit library |
| Version: | 1.0-2010-10-06 |
| Component: | Code |
| Category: | bug report |
| Priority: | critical |
| Assigned: | Unassigned |
| Status: | fixed |
Jump to:
Description
This is a major bug... a simple quaternion multiplication can result in a NAN. Here is a test case that reproduces the bug.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using OpenTK; namespace Cardio3D { class Quaternion_Bug { public static void test() { Quaternion cameraQuaternion = Quaternion.Identity; float delta = 0.005f; for (float i = 0.0f; i <= Math.PI*2.1; i=i+delta) { Vector3 rotAxis = new Vector3(0.0f, 1.0f, 0.0f); Quaternion deltaQuat = Quaternion.FromAxisAngle(rotAxis, delta); cameraQuaternion = deltaQuat * cameraQuaternion; Vector3 axis = Vector3.Zero; float angle = 0.0f; System.Console.WriteLine("Cam quat: {0}", cameraQuaternion); //@tag Correction in a OpenTK bug? //if (cameraQuaternion.W < -1.0f) //{ // cameraQuaternion.W = -1.0f; //} cameraQuaternion.ToAxisAngle(out axis, out angle); axis.Normalize(); //System.Diagnostics.Debug.Assert(!float.IsNaN(angle)); if (float.IsNaN(angle)) { throw new System.ApplicationException("Invalid rotation angle"); } angle = OpenTK.MathHelper.RadiansToDegrees(angle); System.Console.WriteLine("Axis around: {0}", axis); System.Console.WriteLine("Axis rotation applied: {0}", angle); } } } }


Comments
#1
I am not able to reproduce this in svn trunk. Can you please check whether the issue is solved there?
#2
#3
I have recently just come across this issue myself.
The problem is that Quaternion.FromAxisAngle does not check if angle == 0.0f or angle smaller then float.Epsilon which is what causes the problem. If the value is 0.0 or close to zero, it should return Quaternion.Identity.
// current source for Quaternion.cs
public void Normalize()
{
float scale = 1.0f / this.Length;
Xyz *= scale;
W *= scale;
}
public static Quaternion FromAxisAngle(Vector3 axis, float angle)
{
if (axis.LengthSquared == 0.0f)
return Identity;
Quaternion result = Identity;
angle *= 0.5f;
axis.Normalize();
result.Xyz = axis * (float)System.Math.Sin(angle);
result.W = (float)System.Math.Cos(angle);
return Normalize(result);
}
The above source code is the issue. If the angle is Zero, the resulting XYZW components will be zero. Normalizing this will result in 1.0f / a length of zero (divide by zero error), creating NaN.
I hope this helps.
#4
Issue fixed in trunk r3070 and will be in the upcoming beta.
FromAxisAngle was actually correct. If angle = 0, Math.Cos() is 1 so Normalize() works correctly.
The issue was an invalid check in ToAxisAngle (W > 1.0 instead of Math.Abs(W) > 1.0).
#5
Ah! I must of hit the wrong button on my calculator. Then that should definitely work. My bad. Haha.
#6
[Mod edit: separate issue moved to #2585: Vector3.CalculateAngle() may return NaN]