182 lines
3.9 KiB
HLSL
182 lines
3.9 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#define QUATERNION_IDENTITY float4(0,0,0,1)
|
|
#ifndef SMALL_NUMBER
|
|
#define SMALL_NUMBER 1e-8
|
|
#endif
|
|
|
|
float4 NormalizeQuat(in float4 Quat)
|
|
{
|
|
float SquaredNorm = dot(Quat,Quat);
|
|
return (SquaredNorm >= SMALL_NUMBER) ? Quat / sqrt(SquaredNorm) : QUATERNION_IDENTITY;
|
|
}
|
|
|
|
float4 InverseQuat(in float4 Quat)
|
|
{
|
|
return float4(-Quat.x,-Quat.y,-Quat.z,Quat.w);
|
|
}
|
|
|
|
float4 MultiplyQuat(in float4 QuatA, in float4 QuatB)
|
|
{
|
|
return float4(
|
|
QuatB.xyz * QuatA.w + QuatA.xyz * QuatB.w + cross(QuatA.xyz, QuatB.xyz),
|
|
QuatA.w * QuatB.w - dot(QuatA.xyz, QuatB.xyz));
|
|
}
|
|
|
|
float3 RotateVectorByQuat(in float3 Vector, in float4 Quat)
|
|
{
|
|
float3 T = 2.0 * cross(Quat.xyz,Vector);
|
|
return Vector + Quat.w * T + cross(Quat.xyz,T);
|
|
}
|
|
|
|
float3 UnrotateVectorByQuat(in float3 Vector, in float4 Quat)
|
|
{
|
|
float3 T = 2.0 * cross(Quat.xyz,Vector);
|
|
return Vector - Quat.w * T + cross(Quat.xyz,T);
|
|
}
|
|
|
|
float4 SlerpQuat(in float4 QuatA, in float4 QuatB, float Slerp)
|
|
{
|
|
// Get cosine of angle between quats.
|
|
const float RawCosom =
|
|
QuatA.x * QuatB.x +
|
|
QuatA.y * QuatB.y +
|
|
QuatA.z * QuatB.z +
|
|
QuatA.w * QuatB.w;
|
|
// Unaligned quats - compensate, results in taking shorter route.
|
|
const float Cosom = (RawCosom >= 0.0) ? RawCosom : -RawCosom;
|
|
|
|
float Scale0, Scale1;
|
|
|
|
if( Cosom < 0.9999f )
|
|
{
|
|
const float Omega = acos(Cosom);
|
|
const float InvSin = 1.f/sin(Omega);
|
|
Scale0 = sin( (1.f - Slerp) * Omega ) * InvSin;
|
|
Scale1 = sin( Slerp * Omega ) * InvSin;
|
|
}
|
|
else
|
|
{
|
|
// Use linear interpolation.
|
|
Scale0 = 1.0f - Slerp;
|
|
Scale1 = Slerp;
|
|
}
|
|
|
|
// In keeping with our flipped Cosom:
|
|
Scale1 = (RawCosom >= 0.0) ? Scale1 : -Scale1;
|
|
|
|
float4 Result;
|
|
|
|
Result.x = Scale0 * QuatA.x + Scale1 * QuatB.x;
|
|
Result.y = Scale0 * QuatA.y + Scale1 * QuatB.y;
|
|
Result.z = Scale0 * QuatA.z + Scale1 * QuatB.z;
|
|
Result.w = Scale0 * QuatA.w + Scale1 * QuatB.w;
|
|
|
|
return NormalizeQuat(Result);
|
|
}
|
|
|
|
float4 FindQuatBetweenHelper(in float3 A, in float3 B, in float NormAB)
|
|
{
|
|
float W = NormAB + dot(A,B);
|
|
float4 Quat = (W>1e-6*NormAB) ? float4(A.y*B.z-A.z*B.y,A.z*B.x-A.x*B.z,A.x*B.y-A.y*B.x,W) :
|
|
(abs(A.x) > abs(A.y)) ? float4(-A.z,0.0,A.x,0.0) : float4(0.0,-A.z,A.y,0.0);
|
|
|
|
return NormalizeQuat(Quat);
|
|
}
|
|
|
|
float4 FindQuatBetweenInternal(in float3 An, in float3 Bn)
|
|
{
|
|
float3 Cn = normalize(An+Bn);
|
|
return float4(cross(An,Cn),dot(An,Cn));
|
|
}
|
|
|
|
float4 FindQuatBetweenNormals(in float3 NormalA, in float3 NormalB)
|
|
{
|
|
float NormAB = 1.0;
|
|
return FindQuatBetweenHelper(NormalA,NormalB,NormAB);
|
|
}
|
|
|
|
float4 FindQuatBetweenVectors(in float3 VectorA, in float3 VectorB)
|
|
{
|
|
float NormAB = sqrt(dot(VectorA,VectorA) * dot(VectorB,VectorB));
|
|
return FindQuatBetweenHelper(VectorA,VectorB,NormAB);
|
|
}
|
|
|
|
float4 QuatFromMatrix(in float3 R[3])
|
|
{
|
|
float4 Q = 0;
|
|
float s;
|
|
float tr = R[0][0] + R[1][1] + R[2][2];
|
|
|
|
if (tr > 0.0f)
|
|
{
|
|
float InvS = 1.0 / sqrt(tr + 1.f);
|
|
s = 0.5f * InvS;
|
|
|
|
Q.w = 0.5f * (1.f / InvS);
|
|
Q.x = (R[1][2] - R[2][1]) * s;
|
|
Q.y = (R[2][0] - R[0][2]) * s;
|
|
Q.z = (R[0][1] - R[1][0]) * s;
|
|
}
|
|
else
|
|
{
|
|
uint i = 0;
|
|
|
|
if (R[1][1] > R[0][0])
|
|
i = 1;
|
|
|
|
if (R[2][2] > R[i][i])
|
|
i = 2;
|
|
|
|
const uint j = (i+1)%3;
|
|
const uint k = (j+1)%3;
|
|
|
|
tr = R[i][i] - R[j][j] - R[k][k];
|
|
float InvS = 1.0 / sqrt(tr + 1.0);
|
|
s = 0.5 * InvS;
|
|
|
|
const float Qi = 0.5 * (1.0 / InvS);
|
|
const float Qj = (R[i][j] + R[j][i]) * s;
|
|
const float Qk = (R[i][k] + R[k][i]) * s;
|
|
|
|
Q.w = (R[j][k] - R[k][j]) * s;
|
|
if(i == 0)
|
|
{
|
|
Q.x = Qi;
|
|
Q.y = Qj;
|
|
Q.z = Qk;
|
|
}
|
|
else if(i == 1)
|
|
{
|
|
Q.y = Qi;
|
|
Q.z = Qj;
|
|
Q.x = Qk;
|
|
}
|
|
else if(i == 2)
|
|
{
|
|
Q.z = Qi;
|
|
Q.x = Qj;
|
|
Q.y = Qk;
|
|
}
|
|
}
|
|
return NormalizeQuat(Q);
|
|
}
|
|
|
|
float4 RotatorToQuat(float3 Rotator)
|
|
{
|
|
Rotator = frac(Rotator) * 3.1415926535897932f;
|
|
float SP, CP, SY, CY, SR, CR;
|
|
sincos(Rotator.x, SR, CR);
|
|
sincos(Rotator.y, SP, CP);
|
|
sincos(Rotator.z, SY, CY);
|
|
|
|
return float4(
|
|
CR*SP*SY - SR*CP*CY,
|
|
-CR*SP*CY - SR*CP*SY,
|
|
CR*CP*SY - SR*SP*CY,
|
|
CR*CP*CY + SR*SP*SY
|
|
);
|
|
}
|