mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Added Quaternions
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using GlitchyEngine.Math;
|
||||
using GlitchyEngine;
|
||||
|
||||
namespace DirectX.Math
|
||||
{
|
||||
extension Matrix
|
||||
{
|
||||
public static Self RotationQuaternion(Quaternion quat)
|
||||
{
|
||||
float xSq = quat.X * quat.X;
|
||||
float ySq = quat.Y * quat.Y;
|
||||
float zSq = quat.Z * quat.Z;
|
||||
|
||||
float xy = quat.X * quat.Y;
|
||||
float xz = quat.X * quat.Z;
|
||||
float xw = quat.X * quat.W;
|
||||
float yz = quat.Y * quat.Z;
|
||||
float yw = quat.Y * quat.W;
|
||||
float zw = quat.Z * quat.W;
|
||||
|
||||
Self result = .(
|
||||
1 - 2 * ySq - 2 * zSq, 2 * xy + 2 * zw, 2 * xz - 2 * yw, 0,
|
||||
2 * xy - 2 * zw, 1 - 2 * xSq - 2 * zSq, 2 * yz + 2 * xw, 0,
|
||||
2 * xz + 2 * yw, 2 * yz - 2 * xw, 1 - 2 * xSq - 2 * ySq, 0,
|
||||
0, 0, 0, 1);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*[Test]
|
||||
static void TestQuaternionToMatrix()
|
||||
{
|
||||
// Rotation around Z-Axis by 90°
|
||||
Quaternion quat = .(0, 0, 0.707107f, 0.707107f);
|
||||
quat.Normalize();
|
||||
|
||||
|
||||
}*/
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
using System;
|
||||
|
||||
namespace GlitchyEngine.Math
|
||||
{
|
||||
public struct Quaternion
|
||||
{
|
||||
public const Quaternion Zero = .();
|
||||
public const Quaternion One = .(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
public const Quaternion Identity = .(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
// qv: (X, Y, Z), sv: W
|
||||
public float X, Y, Z, W;
|
||||
|
||||
public this() => this = default;
|
||||
|
||||
public this(float x, float y, float z, float w)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Z = z;
|
||||
W = w;
|
||||
}
|
||||
|
||||
public this(Vector3 xy, float z, float w)
|
||||
{
|
||||
X = xy.X;
|
||||
Y = xy.Y;
|
||||
Z = z;
|
||||
W = w;
|
||||
}
|
||||
|
||||
public this(Vector3 xyz, float w)
|
||||
{
|
||||
X = xyz.X;
|
||||
Y = xyz.Y;
|
||||
Z = xyz.Z;
|
||||
W = w;
|
||||
}
|
||||
|
||||
public this(Vector4 vector)
|
||||
{
|
||||
X = vector.X;
|
||||
Y = vector.Y;
|
||||
Z = vector.Z;
|
||||
W = vector.W;
|
||||
}
|
||||
|
||||
public Vector3 Axis => .(X, Y, Z);
|
||||
public float Scalar => W;
|
||||
|
||||
public void Normalize() mut
|
||||
{
|
||||
float invLength = 1.0f / Length();
|
||||
|
||||
X *= invLength;
|
||||
Y *= invLength;
|
||||
Z *= invLength;
|
||||
W *= invLength;
|
||||
}
|
||||
|
||||
public static Quaternion Normalize(Quaternion q)
|
||||
{
|
||||
float invLength = 1.0f / Length(q);
|
||||
|
||||
return Quaternion(q.X * invLength, q.Y * invLength, q.Z * invLength, q.W * invLength);
|
||||
}
|
||||
|
||||
public float Length()
|
||||
{
|
||||
return Math.Sqrt([Inline]LengthSquared());
|
||||
}
|
||||
|
||||
public static float Length(Quaternion q)
|
||||
{
|
||||
return Math.Sqrt([Inline]LengthSquared(q));
|
||||
}
|
||||
|
||||
public float LengthSquared()
|
||||
{
|
||||
return X * X + Y * Y + Z * Z + W * W;
|
||||
}
|
||||
|
||||
public static float LengthSquared(Quaternion q)
|
||||
{
|
||||
return q.X * q.X + q.Y * q.Y + q.Z * q.Z + q.W * q.W;
|
||||
}
|
||||
|
||||
public static float Dot(Self l, Self r)
|
||||
{
|
||||
return l.X * r.X + l.Y * r.Y + l.Z * r.Z + l.W * r.W;
|
||||
}
|
||||
|
||||
public static Quaternion Lerp(Quaternion a, Quaternion b, float interpolationValue)
|
||||
{
|
||||
return a + interpolationValue * (b - a);
|
||||
}
|
||||
|
||||
public static Quaternion Slerp(Quaternion previousQuaternion, Quaternion nextQuaternion, float interpolationValue)
|
||||
{
|
||||
// Based on https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_007_Animations.md
|
||||
|
||||
var nextQuaternion;
|
||||
|
||||
float dot = Dot(previousQuaternion, nextQuaternion);
|
||||
|
||||
//make sure we take the shortest path in case dot Product is negative
|
||||
if(dot < 0.0f)
|
||||
{
|
||||
nextQuaternion = -nextQuaternion;
|
||||
dot = -dot;
|
||||
}
|
||||
|
||||
//if the two quaternions are too close to each other, just linear interpolate between the 4D vector
|
||||
if(dot > 0.9995f)
|
||||
return Normalize(previousQuaternion + interpolationValue * (nextQuaternion - previousQuaternion));
|
||||
|
||||
//perform the spherical linear interpolation
|
||||
var theta_0 = Math.Acos(dot);
|
||||
var theta = interpolationValue * theta_0;
|
||||
var sin_theta = Math.Sin(theta);
|
||||
var sin_theta_0 = Math.Sin(theta_0);
|
||||
|
||||
var scalePreviousQuat = Math.Cos(theta) - dot * sin_theta / sin_theta_0;
|
||||
var scaleNextQuat = sin_theta / sin_theta_0;
|
||||
return scalePreviousQuat * previousQuaternion + scaleNextQuat * nextQuaternion;
|
||||
}
|
||||
|
||||
public static Quaternion FromMatrix(Matrix matrix)
|
||||
{
|
||||
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
|
||||
|
||||
var m = matrix.V;
|
||||
|
||||
Quaternion result = ?;
|
||||
|
||||
float tr = m._11 + m._22 + m._33;
|
||||
|
||||
if (tr > 0) {
|
||||
float S = Math.Sqrt(tr + 1.0f) * 2f; // S=4*result.W
|
||||
result.W = 0.25f * S;
|
||||
result.X = (m._32 - m._23) / S;
|
||||
result.Y = (m._13 - m._31) / S;
|
||||
result.Z = (m._21 - m._12) / S;
|
||||
} else if ((m._11 > m._22)&(m._11 > m._33)) {
|
||||
float S = Math.Sqrt(1.0f + m._11 - m._22 - m._33) * 2f; // S=4*result.X
|
||||
result.W = (m._32 - m._23) / S;
|
||||
result.X = 0.25f * S;
|
||||
result.Y = (m._12 + m._21) / S;
|
||||
result.Z = (m._13 + m._31) / S;
|
||||
} else if (m._22 > m._33) {
|
||||
float S = Math.Sqrt(1.0f + m._22 - m._11 - m._33) * 2f; // S=4*result.Y
|
||||
result.W = (m._13 - m._31) / S;
|
||||
result.X = (m._12 + m._21) / S;
|
||||
result.Y = 0.25f * S;
|
||||
result.Z = (m._23 + m._32) / S;
|
||||
} else {
|
||||
float S = Math.Sqrt(1.0f + m._33 - m._11 - m._22) * 2f; // S=4*result.Z
|
||||
result.W = (m._21 - m._12) / S;
|
||||
result.X = (m._13 + m._31) / S;
|
||||
result.Y = (m._23 + m._32) / S;
|
||||
result.Z = 0.25f * S;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Self operator +(Self value) => value;
|
||||
|
||||
public static Self operator +(Self l, Self r) => Self(l.X + r.X, l.Y + r.Y, l.Z + r.Z, l.W + r.W);
|
||||
|
||||
public static Self operator -(Self value) => Self(-value.X, -value.Y, -value.Z, -value.W);
|
||||
|
||||
public static Self operator -(Self l, Self r) => Self(l.X - r.X, l.Y - r.Y, l.Z - r.Z, l.W - r.W);
|
||||
|
||||
public static Self operator *(float l, Self r) => Self(l * r.X, l * r.Y, l * r.Z, l * r.W);
|
||||
|
||||
|
||||
[Inline]
|
||||
public static implicit operator Vector4(in Self value) => *(Vector4*)&value;
|
||||
|
||||
[Inline]
|
||||
public static implicit operator Quaternion(in Vector4 value) => *(Quaternion*)&value;
|
||||
|
||||
//public static Quaternion operator +(Self left, Self right) => return .();
|
||||
|
||||
/*
|
||||
public static Quaternion Conjugate(Quaternion q)
|
||||
{
|
||||
return Quaternion(-q.Axis, q.Scalar);
|
||||
}
|
||||
|
||||
public static Quaternion Inverse(Quaternion q)
|
||||
{
|
||||
Quaternion conjugate = Conjugate(q);
|
||||
|
||||
float magSquared = LengthSquared(q);
|
||||
|
||||
return Quaternion(conjugate / magSquared);
|
||||
}
|
||||
|
||||
public static Quaternion operator *(Quaternion left, Quaternion right)
|
||||
{
|
||||
return Quaternion(left.Scalar * right.Axis + right.Scalar * left.Axis + Vector3.Cross(left.Axis, right.Axis),
|
||||
left.Scalar * right.Scalar - Vector3.Dot(left.Axis, right.Axis));
|
||||
}
|
||||
*/
|
||||
|
||||
//public static Quaternion operator /(Quaternion left, float right) => Quaternion(left.X / right, left.Y / right, left.Z / right, left.W / right);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user