Vector3(d).Cross: do not modify 'result' more than once to ensure that Cross(ref a, ref b, out a) works correctly.

Optimized vector-quaternion transform. Fixes issue [#1373]: "[Math] optimize Vector transform by Quaternion".
This commit is contained in:
the_fiddler 2009-11-16 13:23:04 +00:00
parent 0605607e6a
commit bbe606da53
2 changed files with 30 additions and 24 deletions

View file

@ -837,9 +837,9 @@ namespace OpenTK
/// <returns>The cross product of the two inputs</returns> /// <returns>The cross product of the two inputs</returns>
public static Vector3 Cross(Vector3 left, Vector3 right) public static Vector3 Cross(Vector3 left, Vector3 right)
{ {
return new Vector3(left.Y * right.Z - left.Z * right.Y, Vector3 result;
left.Z * right.X - left.X * right.Z, Cross(ref left, ref right, out result);
left.X * right.Y - left.Y * right.X); return result;
} }
/// <summary> /// <summary>
@ -851,9 +851,9 @@ namespace OpenTK
/// <param name="result">The cross product of the two inputs</param> /// <param name="result">The cross product of the two inputs</param>
public static void Cross(ref Vector3 left, ref Vector3 right, out Vector3 result) public static void Cross(ref Vector3 left, ref Vector3 right, out Vector3 result)
{ {
result.X = left.Y * right.Z - left.Z * right.Y; result = new Vector3(left.Y * right.Z - left.Z * right.Y,
result.Y = left.Z * right.X - left.X * right.Z; left.Z * right.X - left.X * right.Z,
result.Z = left.X * right.Y - left.Y * right.X; left.X * right.Y - left.Y * right.X);
} }
#endregion #endregion
@ -1115,12 +1115,15 @@ namespace OpenTK
/// <param name="result">The result of the operation.</param> /// <param name="result">The result of the operation.</param>
public static void Transform(ref Vector3 vec, ref Quaternion quat, out Vector3 result) public static void Transform(ref Vector3 vec, ref Quaternion quat, out Vector3 result)
{ {
Quaternion v = new Quaternion(vec.X, vec.Y, vec.Z, 0), i, t; // Since vec.W == 0, we can optimize quat * vec * quat^-1 as follows:
Quaternion.Invert(ref quat, out i); // vec + 2.0 * cross(quat.xyz, cross(quat.xyz, vec) + quat.w * vec)
Quaternion.Multiply(ref quat, ref v, out t); Vector3 xyz = quat.Xyz, temp, temp2;
Quaternion.Multiply(ref t, ref i, out v); Vector3.Cross(ref xyz, ref vec, out temp);
Vector3.Multiply(ref vec, quat.W, out temp2);
result = new Vector3(v.X, v.Y, v.Z); Vector3.Add(ref temp, ref temp2, out temp);
Vector3.Cross(ref xyz, ref temp, out temp);
Vector3.Multiply(ref temp, 2, out temp);
Vector3.Add(ref vec, ref temp, out result);
} }
/// <summary>Transform a Vector3 by the given Matrix, and project the resulting Vector4 back to a Vector3</summary> /// <summary>Transform a Vector3 by the given Matrix, and project the resulting Vector4 back to a Vector3</summary>

View file

@ -836,9 +836,9 @@ namespace OpenTK
/// <returns>The cross product of the two inputs</returns> /// <returns>The cross product of the two inputs</returns>
public static Vector3d Cross(Vector3d left, Vector3d right) public static Vector3d Cross(Vector3d left, Vector3d right)
{ {
return new Vector3d(left.Y * right.Z - left.Z * right.Y, Vector3d result;
left.Z * right.X - left.X * right.Z, Cross(ref left, ref right, out result);
left.X * right.Y - left.Y * right.X); return result;
} }
/// <summary> /// <summary>
@ -850,9 +850,9 @@ namespace OpenTK
/// <param name="result">The cross product of the two inputs</param> /// <param name="result">The cross product of the two inputs</param>
public static void Cross(ref Vector3d left, ref Vector3d right, out Vector3d result) public static void Cross(ref Vector3d left, ref Vector3d right, out Vector3d result)
{ {
result.X = left.Y * right.Z - left.Z * right.Y; result = new Vector3d(left.Y * right.Z - left.Z * right.Y,
result.Y = left.Z * right.X - left.X * right.Z; left.Z * right.X - left.X * right.Z,
result.Z = left.X * right.Y - left.Y * right.X; left.X * right.Y - left.Y * right.X);
} }
#endregion #endregion
@ -1111,12 +1111,15 @@ namespace OpenTK
/// <param name="result">The result of the operation.</param> /// <param name="result">The result of the operation.</param>
public static void Transform(ref Vector3d vec, ref Quaterniond quat, out Vector3d result) public static void Transform(ref Vector3d vec, ref Quaterniond quat, out Vector3d result)
{ {
Quaterniond v = new Quaterniond(vec.X, vec.Y, vec.Z, 0), i, t; // Since vec.W == 0, we can optimize quat * vec * quat^-1 as follows:
Quaterniond.Invert(ref quat, out i); // vec + 2.0 * cross(quat.xyz, cross(quat.xyz, vec) + quat.w * vec)
Quaterniond.Multiply(ref quat, ref v, out t); Vector3d xyz = quat.Xyz, temp, temp2;
Quaterniond.Multiply(ref t, ref i, out v); Vector3d.Cross(ref xyz, ref vec, out temp);
Vector3d.Multiply(ref vec, quat.W, out temp2);
result = new Vector3d(v.X, v.Y, v.Z); Vector3d.Add(ref temp, ref temp2, out temp);
Vector3d.Cross(ref xyz, ref temp, out temp);
Vector3d.Multiply(ref temp, 2, out temp);
Vector3d.Add(ref vec, ref temp, out result);
} }
/// <summary> /// <summary>