Skip to content

Instantly share code, notes, and snippets.

@outsidecontext
Last active December 16, 2024 14:23
Show Gist options
  • Select an option

  • Save outsidecontext/6083f490d4bd56b3e34b7893e6a34480 to your computer and use it in GitHub Desktop.

Select an option

Save outsidecontext/6083f490d4bd56b3e34b7893e6a34480 to your computer and use it in GitHub Desktop.
HLSL Maths Utils
float4x4 GetRotationDir(float3 direction, float3 up = float3(0, 1, 0))
{
float4x4 result;
float3 xaxis = normalize(cross(up, direction));
float3 yaxis = normalize(cross(direction, xaxis));
result._11 = xaxis.x;
result._12 = yaxis.x;
result._13 = direction.x;
result._14 = 0;
result._21 = xaxis.y;
result._22 = yaxis.y;
result._23 = direction.y;
result._24 = 0;
result._31 = xaxis.z;
result._32 = yaxis.z;
result._33 = direction.z;
result._34 = 0;
result._41 = 0;
result._42 = 0;
result._43 = 0;
result._44 = 1;
return result;
}
float4x4 GetRotationDir(float3 direction, float3 xaxis, float3 yaxis)
{
float4x4 result;
result._11 = xaxis.x;
result._12 = yaxis.x;
result._13 = direction.x;
result._14 = 0;
result._21 = xaxis.y;
result._22 = yaxis.y;
result._23 = direction.y;
result._24 = 0;
result._31 = xaxis.z;
result._32 = yaxis.z;
result._33 = direction.z;
result._34 = 0;
result._41 = 0;
result._42 = 0;
result._43 = 0;
result._44 = 1;
return result;
}
float dotfloat4(float4 a, float4 b)
{
return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
}
// Returns inverse matrix of specified matrix
float4x4 inverse(float4x4 input)
{
#define minor(a,b,c) determinant(float3x3(input.a, input.b, input.c))
float4x4 cofactors = float4x4(
minor(_22_23_24, _32_33_34, _42_43_44),
-minor(_21_23_24, _31_33_34, _41_43_44),
minor(_21_22_24, _31_32_34, _41_42_44),
-minor(_21_22_23, _31_32_33, _41_42_43),
-minor(_12_13_14, _32_33_34, _42_43_44),
minor(_11_13_14, _31_33_34, _41_43_44),
-minor(_11_12_14, _31_32_34, _41_42_44),
minor(_11_12_13, _31_32_33, _41_42_43),
minor(_12_13_14, _22_23_24, _42_43_44),
-minor(_11_13_14, _21_23_24, _41_43_44),
minor(_11_12_14, _21_22_24, _41_42_44),
-minor(_11_12_13, _21_22_23, _41_42_43),
-minor(_12_13_14, _22_23_24, _32_33_34),
minor(_11_13_14, _21_23_24, _31_33_34),
-minor(_11_12_14, _21_22_24, _31_32_34),
minor(_11_12_13, _21_22_23, _31_32_33)
);
#undef minor
return transpose(cofactors) / determinant(input);
}
float4 quat_from_axis_angle(float3 axis, float angle)
{
float4 qr;
float half_angle = (angle * .5); // * 3.14159 / 180.0; // stick to radians
qr.x = axis.x * sin(half_angle);
qr.y = axis.y * sin(half_angle);
qr.z = axis.z * sin(half_angle);
qr.w = cos(half_angle);
return qr;
}
/// Converts a Quaternion rotation to a 4x4 matrix
float4x4 quaternion_to_rotation_matrix(float4 quat)
{
float4x4 mReturn;
mReturn._11 = 1.0f - 2.0f*quat.y*quat.y - 2.0f*quat.z*quat.z;
mReturn._12 = 2.0f*quat.x*quat.y - 2.0f*quat.w*quat.z;
mReturn._13 = 2.0f*quat.x*quat.z + 2.0f*quat.w*quat.y;
mReturn._14 = 0;
mReturn._21 = 2.0f*quat.x*quat.y + 2.0f*quat.w*quat.z;
mReturn._22 = 1.0f - 2.0f*quat.x*quat.x - 2.0f*quat.z*quat.z;
mReturn._23 = 2.0f*quat.y*quat.z - 2.0f*quat.w*quat.x;
mReturn._24 = 0;
mReturn._31 = 2.0f*quat.x*quat.z - 2.0f*quat.w*quat.y;
mReturn._32 = 2.0f*quat.y*quat.z + 2.0f*quat.w*quat.x;
mReturn._33 = 1.0f - 2.0f*quat.x*quat.x - 2.0f*quat.y*quat.y;
mReturn._34 = 0;
mReturn._41 = 0;
mReturn._42 = 0;
mReturn._43 = 0;
mReturn._44 = 1;
return mReturn;
}
float4 slerp(float4 v0, float4 v1, float t)
{
// Compute the cosine of the angle between the two vectors.
float dot = dotfloat4(v0, v1);
const float DOT_THRESHOLD = 0.9995;
if (abs(dot) > DOT_THRESHOLD)
{
// If the inputs are too close for comfort, linearly interpolate
// and normalize the result.
float4 result = v0 + t * (v1 - v0);
normalize(result);
return result;
}
// If the dot product is negative, the quaternions
// have opposite handed-ness and slerp won't take
// the shorter path. Fix by reversing one quaternion.
if (dot < 0.0f)
{
v1 = -v1;
dot = -dot;
}
clamp(dot, -1, 1); // Robustness: Stay within domain of acos()
float theta_0 = acos(dot); // theta_0 = angle between input vectors
float theta = theta_0 * t; // theta = angle between v0 and result
float4 v2 = v1 - v0 * dot;
normalize(v2); // { v0, v2 } is now an orthonormal basis
return v0 * cos(theta) + v2 * sin(theta);
}
// https://blog.demofox.org/2016/02/19/normalized-vector-interpolation-tldr/
float3 slerp(float3 start, float3 end, float percent)
{
// Dot product - the cosine of the angle between 2 vectors.
float slerpDot = dot(start, end);
// Clamp it to be in the range of Acos()
// This may be unnecessary, but floating point
// precision can be a fickle mistress.
slerpDot = clamp(slerpDot, -1.0, 1.0);
// Acos(dot) returns the angle between start and end,
// And multiplying that by percent returns the angle between
// start and the final result.
float theta = acos(slerpDot) * percent;
float3 RelativeVec = normalize(end - start * slerpDot); // Orthonormal basis
// The final result.
return ((start * cos(theta)) + (RelativeVec * sin(theta)));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment