Skip to content

Commit

Permalink
Hardware accelerated implementation of Quaternion multiply (#96624)
Browse files Browse the repository at this point in the history
* Vector based implementation of Quaternion multiply

I saw on the Discord that Quaternion multiply wasnt yet vectorised, this PR adds that. The non accelerated path is the exact same as before, and the accelerated path appears to return the same results.

* Convert tabs to spaces

* Update src/libraries/System.Private.CoreLib/src/System/Numerics/Quaternion.cs

Copy  paste error!

Co-authored-by: Austin Wise <AustinWise@gmail.com>

* Even faster version

Tanner provided an even quicker version. I've changed it to use GetElementUnsafe as i saw other API's doing the same, and we can reasonably argue these fields to exist.

* Update src/libraries/System.Private.CoreLib/src/System/Numerics/Quaternion.cs

Co-authored-by: Tanner Gooding <tagoo@outlook.com>

* Fix incorrect non-hardware accelerated version

---------

Co-authored-by: Austin Wise <AustinWise@gmail.com>
Co-authored-by: Tanner Gooding <tagoo@outlook.com>
  • Loading branch information
3 people authored Jan 17, 2024
1 parent bdbdf3e commit db7d269
Showing 1 changed file with 33 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -188,31 +188,45 @@ public readonly bool IsIdentity
/// <remarks>The <see cref="Quaternion.op_Multiply" /> method defines the operation of the multiplication operator for <see cref="Quaternion" /> objects.</remarks>
public static Quaternion operator *(Quaternion value1, Quaternion value2)
{
Quaternion ans;
if (Vector128.IsHardwareAccelerated)
{
var left = value1.AsVector128();
var right = value2.AsVector128();

var result = right * left.GetElementUnsafe(3);
result += (Vector128.Shuffle(right, Vector128.Create(3, 2, 1, 0)) * left.GetElementUnsafe(0)) * Vector128.Create(+1.0f, -1.0f, +1.0f, -1.0f);
result += (Vector128.Shuffle(right, Vector128.Create(2, 3, 0, 1)) * left.GetElementUnsafe(1)) * Vector128.Create(+1.0f, +1.0f, -1.0f, -1.0f);
result += (Vector128.Shuffle(right, Vector128.Create(1, 0, 3, 2)) * left.GetElementUnsafe(2)) * Vector128.Create(-1.0f, +1.0f, +1.0f, -1.0f);
return Unsafe.BitCast<Vector128<float>, Quaternion>(result);
}
else
{
Quaternion ans;

float q1x = value1.X;
float q1y = value1.Y;
float q1z = value1.Z;
float q1w = value1.W;
float q1x = value1.X;
float q1y = value1.Y;
float q1z = value1.Z;
float q1w = value1.W;

float q2x = value2.X;
float q2y = value2.Y;
float q2z = value2.Z;
float q2w = value2.W;
float q2x = value2.X;
float q2y = value2.Y;
float q2z = value2.Z;
float q2w = value2.W;

// cross(av, bv)
float cx = q1y * q2z - q1z * q2y;
float cy = q1z * q2x - q1x * q2z;
float cz = q1x * q2y - q1y * q2x;
// cross(av, bv)
float cx = q1y * q2z - q1z * q2y;
float cy = q1z * q2x - q1x * q2z;
float cz = q1x * q2y - q1y * q2x;

float dot = q1x * q2x + q1y * q2y + q1z * q2z;
float dot = q1x * q2x + q1y * q2y + q1z * q2z;

ans.X = q1x * q2w + q2x * q1w + cx;
ans.Y = q1y * q2w + q2y * q1w + cy;
ans.Z = q1z * q2w + q2z * q1w + cz;
ans.W = q1w * q2w - dot;
ans.X = q1x * q2w + q2x * q1w + cx;
ans.Y = q1y * q2w + q2y * q1w + cy;
ans.Z = q1z * q2w + q2z * q1w + cz;
ans.W = q1w * q2w - dot;

return ans;
return ans;
}
}

/// <summary>Returns the quaternion that results from scaling all the components of a specified quaternion by a scalar factor.</summary>
Expand Down

0 comments on commit db7d269

Please sign in to comment.