You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

186 lines
3.6 KiB
HLSL

/******************************************************************************/
/*
Project - MudBun
Publisher - Long Bunny Labs
http://LongBunnyLabs.com
Author - Ming-Lun "Allen" Chou
http://AllenChou.net
*/
/******************************************************************************/
#ifndef MUDBUN_QUATERNION
#define MUDBUN_QUATERNION
#include "MathConst.cginc"
#include "Vector.cginc"
#define kQuatIdentity (float4(0.0f, 0.0f, 0.0f, 1.0f))
float4 quat_conj(float4 q)
{
return float4(-q.xyz, q.w);
}
float4 quat_inv(float4 q)
{
return quat_conj(q);
}
// q must be unit quaternion
float4 quat_pow(float4 q, float p)
{
float r = length(q.xyz);
if (r < kEpsilon)
return kQuatIdentity;
float t = p * atan2(q.w, r);
return float4(sin(t) * q.xyz / r, cos(t));
}
float3 quat_rot(float4 q, float3 v)
{
return
dot(q.xyz, v) * q.xyz
+ q.w * q.w * v
+ 2.0 * q.w * cross(q.xyz, v)
- cross(cross(q.xyz, v), q.xyz);
}
float4 quat_axis_angle(float3 v, float a)
{
float h = 0.5 * a;
return float4(sin(h) * normalize(v), cos(h));
}
float4 quat_from_to(float3 from, float3 to)
{
float3 c = cross(from, to);
float cc = dot(c, c);
if (cc < kEpsilon)
return kQuatIdentity;
float3 axis = c / sqrt(cc);
float angle = acos(clamp(dot(from, to), -1.0f, 1.0f));
return quat_axis_angle(axis, angle);
}
float3 quat_get_axis(float4 q)
{
float d = dot(q.xyz, q.xyz);
return
d > kEpsilon
? q.xyz / sqrt(d)
: float3(0.0f, 0.0f, 1.0f);
}
float3 quat_get_angle(float4 q)
{
return 2.0f * acos(clamp(q.w, -1.0f, 1.0f));
}
float4 quat_mul(float4 q1, float4 q2)
{
return
float4
(
q1.w * q2.xyz + q2.w * q1.xyz + cross(q1.xyz, q2.xyz),
q1.w * q2.w - dot(q1.xyz, q2.xyz)
);
}
float4 quat_mat(float3x3 m)
{
float tr = m._m00 + m._m11 + m._m22;
if (tr > 0.0f) {
float s = sqrt(tr + 1.0f) * 2.0f;
float sInv = 1.0f / s;
return
float4
(
(m._m21 - m._m12) * sInv,
(m._m02 - m._m20) * sInv,
(m._m10 - m._m01) * sInv,
0.25 * s
);
}
else if ((m._m00 > m._m11) && (m._m00 > m._m22))
{
float s = sqrt(1.0f + m._m00 - m._m11 - m._m22) * 2.0f;
float sInv = 1.0f / s;
return
float4
(
0.25f * s,
(m._m01 + m._m10) * sInv,
(m._m02 + m._m20) * sInv,
(m._m21 - m._m12) * sInv
);
}
else if (m._m11 > m._m22)
{
float s = sqrt(1.0f + m._m11 - m._m00 - m._m22) * 2.0f;
float sInv = 1.0f / s;
return
float4
(
(m._m01 + m._m10) * sInv,
0.25 * s,
(m._m12 + m._m21) * sInv,
(m._m02 - m._m20) * sInv
);
}
else {
float s = sqrt(1.0f + m._m22 - m._m00 - m._m11) * 2.0f;
float sInv = 1.0f / s;
return
float4
(
(m._m02 + m._m20) * sInv,
(m._m12 + m._m21) * sInv,
0.25 * s,
(m._m10 - m._m01) * sInv
);
}
}
float4 quat_look_at(float3 dir, float3 up)
{
return quat_mat(mat_look_at(dir, up));
}
// order: ZXY
float4 quat_euler(float3 rot)
{
return
quat_mul
(
quat_mul
(
quat_axis_angle(kUnitY, rot.x),
quat_axis_angle(kUnitX, rot.y)
),
quat_axis_angle(kUnitZ, rot.z)
);
}
float4 slerp(float4 a, float4 b, float t)
{
float d = dot(normalize(a), normalize(b));
if (d > kEpsilonComp)
{
return lerp(a, b, t);
}
float r = acos(clamp(d, -1.0f, 1.0f));
return (sin((1.0 - t) * r) * a + sin(t * r) * b) / sin(r);
}
float4 nlerp(float4 a, float b, float t)
{
return normalize(lerp(a, b, t));
}
#endif