mirror of
https://github.com/thepigeongenerator/sdl_template.git
synced 2025-12-17 05:55:47 +01:00
implement quaternion functions
This commit is contained in:
@@ -1,44 +1,93 @@
|
|||||||
#include "../../error.h"
|
#include <math.h>
|
||||||
|
|
||||||
#include "float3.h"
|
#include "float3.h"
|
||||||
#include "float4.h"
|
#include "float4.h"
|
||||||
|
|
||||||
|
// converts a float3 to a quaternion
|
||||||
|
static inline float4 quat_from_float3(float3 v) {
|
||||||
|
return (float4){
|
||||||
|
.w = 0.0F,
|
||||||
|
.x = v.x,
|
||||||
|
.y = v.y,
|
||||||
|
.z = v.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// converts euler angles into quaternion
|
// converts euler angles into quaternion (ordered roll, pitch, yaw) (in radians)
|
||||||
static inline float4 quat_from_euler(float3 euler) {
|
static inline float4 quat_from_euler(float3 euler) {
|
||||||
(void)euler;
|
euler = float3_mul_s(euler, 0.5F); // half the angles due to quaternions using θ/2 in the formula
|
||||||
error(STATUS_ERROR, __FILE_NAME__, __LINE__, "this function is not implemented"); // TODO: write an implementation for this function
|
float cx = cosf32(euler.x), sx = sinf32(euler.x);
|
||||||
|
float cy = cosf32(euler.y), sy = sinf32(euler.y);
|
||||||
|
float cz = cosf32(euler.z), sz = sinf32(euler.z);
|
||||||
|
|
||||||
|
return (float4){
|
||||||
|
.w = cx * cy * cz - sx * sy * sz,
|
||||||
|
.x = sx * cy * cz + cx * sy * sz,
|
||||||
|
.y = cx * sy * cz - sx * cy * sz,
|
||||||
|
.z = cx * cy * sz + sx * sy * cz,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// converts quaternion into euler angles
|
// converts quaternion into euler angles (ordered as roll, pitch, yaw)
|
||||||
static inline float3 quat_to_euler(float4 q) {
|
static inline float3 quat_to_euler(float4 q) {
|
||||||
(void)q;
|
// warn: do not read from these variables until set
|
||||||
error(STATUS_ERROR, __FILE_NAME__, __LINE__, "this function is not implemented"); // TODO: write an implementation for this function
|
float3 euler;
|
||||||
}
|
float a, b;
|
||||||
|
|
||||||
// adds two quaternions
|
// compute the roll (Φ)
|
||||||
static inline float4 quat_add(float4 q1, float4 q2) {
|
a = 2 * (q.w * q.x + q.y * q.z); // sin(r)•cos(p)
|
||||||
(void)q1, (void)q2;
|
b = 1 - 2 * (q.x * q.x + q.y * q.y); // cos(r)•cos(p)
|
||||||
error(STATUS_ERROR, __FILE_NAME__, __LINE__, "this function is not implemented"); // TODO: write an implementation for this function
|
euler.x = atan2f(a, b);
|
||||||
}
|
|
||||||
|
|
||||||
// subtracts two quaternions
|
// compute the pitch (θ)
|
||||||
static inline float4 quat_sub(float4 q1, float4 q2) {
|
a = 2 * (q.w * q.y - q.z * q.x);
|
||||||
(void)q1, (void)q2;
|
euler.y = fabsf(a) >= 1 ? copysignf(M_PI_2, a) : asinf(a); // if |a| >=1, sgn(a)•(π/2), else asin(a)
|
||||||
error(STATUS_ERROR, __FILE_NAME__, __LINE__, "this function is not implemented"); // TODO: write an implementation for this function
|
|
||||||
|
// compute the yaw (ψ)
|
||||||
|
a = 2 * (q.w * q.z + q.x * q.y); // sin(y)•cos(y)
|
||||||
|
b = 1 - 2 * (q.y * q.y + q.z * q.z); // cos(y)•cos(y)
|
||||||
|
euler.z = atan2f(a, b);
|
||||||
|
|
||||||
|
// return the final angles
|
||||||
|
return euler;
|
||||||
}
|
}
|
||||||
|
|
||||||
// multiplies two quaternions
|
// multiplies two quaternions
|
||||||
static inline float4 quat_mul(float4 q1, float4 q2) {
|
static inline float4 quat_mul(float4 q1, float4 q2) {
|
||||||
return (float4){
|
return (float4){
|
||||||
q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y, // x
|
.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z,
|
||||||
q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z, // y
|
.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y,
|
||||||
q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x, // z
|
.y = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z,
|
||||||
q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z, // w
|
.z = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// multiplies two quaternions
|
// get the conjugate of the quaternion (negates the vector portion)
|
||||||
static inline float4 quat_div(float4 q1, float4 q2) {
|
static inline float4 quat_conj(float4 q) {
|
||||||
(void)q1, (void)q2;
|
return (float4){
|
||||||
error(STATUS_ERROR, __FILE_NAME__, __LINE__, "this function is not implemented"); // TODO: write an implementation for this function
|
.w = q.w,
|
||||||
|
.x = -q.x,
|
||||||
|
.y = -q.y,
|
||||||
|
.z = -q.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the multiplicative inverse of the quaternion (conj / mag²)
|
||||||
|
static inline float4 quat_inv(float4 q) {
|
||||||
|
float mag2 = float4_mag2(q);
|
||||||
|
if (mag2 == 0.0F) return (float4){0};
|
||||||
|
mag2 = 1.0F / mag2;
|
||||||
|
return float4_mul_s(quat_conj(q), mag2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// rotates a vector by the quaternion (q must be a unit quaternion (normalized))
|
||||||
|
static inline float3 quat_rot(float4 q, float3 v) {
|
||||||
|
q = quat_mul(quat_mul(q, quat_from_float3(v)), quat_conj(q)); // q•v•q¯¹ (using conjugate for q⁻¹, as for unit quaternions this is the same as the multiplicative inverse)
|
||||||
|
return (float3){q.x, q.y, q.z};
|
||||||
|
}
|
||||||
|
|
||||||
|
// rotates a vector by the quaternion, q may be non-normalized
|
||||||
|
static inline float3 quat_rot_s(float4 q, float3 v) {
|
||||||
|
q = quat_mul(quat_mul(q, quat_from_float3(v)), quat_inv(q)); // q•v•q¯¹
|
||||||
|
return (float3){q.x, q.y, q.z};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user