Removed the MCore::Quaternion class #2600
Merge pull request #2600 from aws-lumberyard-dev/jillich/RemovedMCoreQuaternion
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include "OrthographicCamera.h"
|
||||
#include <MCore/Source/AABB.h>
|
||||
#include <MCore/Source/Compare.h>
|
||||
#include <MCore/Source/Distance.h>
|
||||
#include <EMotionFX/Source/EMotionFXManager.h>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#include "RotateManipulator.h"
|
||||
#include <MCore/Source/AzCoreConversions.h>
|
||||
|
||||
#include <MCore/Source/PlaneEq.h>
|
||||
|
||||
namespace MCommon
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
#include "ScaleManipulator.h"
|
||||
|
||||
#include <MCore/Source/PlaneEq.h>
|
||||
|
||||
namespace MCommon
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
#include "TranslateManipulator.h"
|
||||
|
||||
#include <MCore/Source/PlaneEq.h>
|
||||
|
||||
namespace MCommon
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <MCore/Source/Config.h>
|
||||
#include <MCore/Source/LogManager.h>
|
||||
#include "GLSLShader.h"
|
||||
#include "GraphicsManager.h"
|
||||
#include <QFile>
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
|
||||
#include <MCore/Source/IDGenerator.h>
|
||||
#include <MCore/Source/Compare.h>
|
||||
#include <MCore/Source/LogManager.h>
|
||||
#include <MCore/Source/OBB.h>
|
||||
|
||||
#include <Atom/RPI.Reflect/Model/MorphTargetDelta.h>
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <MCore/Source/AzCoreConversions.h>
|
||||
#include <MCore/Source/Distance.h>
|
||||
#include <MCore/Source/File.h>
|
||||
#include <MCore/Source/LogManager.h>
|
||||
#include <MCore/Source/ReflectionSerializer.h>
|
||||
#include <MCore/Source/StringConversions.h>
|
||||
#include <MCore/Source/MCoreSystem.h>
|
||||
|
||||
+1
@@ -10,6 +10,7 @@
|
||||
#define __EMSTUDIO_LOGWINDOWPLUGIN_H
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <MCore/Source/LogManager.h>
|
||||
#include "../StandardPluginsConfig.h"
|
||||
#include "../../../../EMStudioSDK/Source/DockWidgetPlugin.h"
|
||||
#endif
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include <AzCore/Math/PackedVector3.h>
|
||||
#include <MCore/Source/Algorithms.h>
|
||||
#include <MCore/Source/Color.h>
|
||||
#include <MCore/Source/Quaternion.h>
|
||||
#include <MCore/Source/Vector.h>
|
||||
#include <EMotionFX/Source/Transform.h>
|
||||
|
||||
// This file is "glue" code to convert math back-forward between MCore and AZ. It also has functions that MCore used to
|
||||
@@ -37,18 +37,6 @@ namespace MCore
|
||||
return RGBAColor(static_cast<float>(azColor.GetR()), static_cast<float>(azColor.GetG()), static_cast<float>(azColor.GetB()), static_cast<float>(azColor.GetA()));
|
||||
}
|
||||
|
||||
// Deprecated
|
||||
AZ_FORCE_INLINE AZ::Quaternion EmfxQuatToAzQuat(const MCore::Quaternion& emfxQuat)
|
||||
{
|
||||
return AZ::Quaternion(emfxQuat.x, emfxQuat.y, emfxQuat.z, emfxQuat.w);
|
||||
}
|
||||
|
||||
// Deprecated
|
||||
AZ_FORCE_INLINE MCore::Quaternion AzQuatToEmfxQuat(const AZ::Quaternion& azQuat)
|
||||
{
|
||||
return MCore::Quaternion(azQuat.GetX(), azQuat.GetY(), azQuat.GetZ(), azQuat.GetW());
|
||||
}
|
||||
|
||||
AZ_FORCE_INLINE AZ::Transform EmfxTransformToAzTransform(const EMotionFX::Transform& emfxTransform)
|
||||
{
|
||||
AZ::Transform transform = AZ::Transform::CreateFromQuaternionAndTranslation(emfxTransform.mRotation, emfxTransform.mPosition);
|
||||
@@ -530,91 +518,4 @@ namespace MCore
|
||||
AZ::Vector3ToVector4(m33.GetRow(2), translation.GetZ()),
|
||||
mat.GetRow(3));
|
||||
}
|
||||
|
||||
// Deprecated. Please use AZ::Transform instead of MCore::Matrix.
|
||||
MCORE_INLINE AZ::Quaternion MCoreMatrixToQuaternion(const MCore::Matrix& m)
|
||||
{
|
||||
const float trace = MMAT(m, 0, 0) + MMAT(m, 1, 1) + MMAT(m, 2, 2);
|
||||
if (trace > 0.0f /*Math::epsilon*/)
|
||||
{
|
||||
const float s = 0.5f / Math::Sqrt(trace + 1.0f);
|
||||
return AZ::Quaternion((MMAT(m, 1, 2) - MMAT(m, 2, 1)) * s,
|
||||
(MMAT(m, 2, 0) - MMAT(m, 0, 2)) * s,
|
||||
(MMAT(m, 0, 1) - MMAT(m, 1, 0)) * s,
|
||||
0.25f / s);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MMAT(m, 0, 0) > MMAT(m, 1, 1) && MMAT(m, 0, 0) > MMAT(m, 2, 2))
|
||||
{
|
||||
const float s = 2.0f * Math::Sqrt(1.0f + MMAT(m, 0, 0) - MMAT(m, 1, 1) - MMAT(m, 2, 2));
|
||||
const float oneOverS = 1.0f / s;
|
||||
return AZ::Quaternion(0.25f * s,
|
||||
(MMAT(m, 1, 0) + MMAT(m, 0, 1)) * oneOverS,
|
||||
(MMAT(m, 2, 0) + MMAT(m, 0, 2)) * oneOverS,
|
||||
(MMAT(m, 1, 2) - MMAT(m, 2, 1)) * oneOverS);
|
||||
}
|
||||
else if (MMAT(m, 1, 1) > MMAT(m, 2, 2))
|
||||
{
|
||||
const float s = 2.0f * Math::Sqrt(1.0f + MMAT(m, 1, 1) - MMAT(m, 0, 0) - MMAT(m, 2, 2));
|
||||
const float oneOverS = 1.0f / s;
|
||||
return AZ::Quaternion((MMAT(m, 1, 0) + MMAT(m, 0, 1)) * oneOverS,
|
||||
0.25f * s,
|
||||
(MMAT(m, 2, 1) + MMAT(m, 1, 2)) * oneOverS,
|
||||
(MMAT(m, 2, 0) - MMAT(m, 0, 2)) * oneOverS);
|
||||
}
|
||||
else
|
||||
{
|
||||
const float s = 2.0f * Math::Sqrt(1.0f + MMAT(m, 2, 2) - MMAT(m, 0, 0) - MMAT(m, 1, 1));
|
||||
const float oneOverS = 1.0f / s;
|
||||
return AZ::Quaternion((MMAT(m, 2, 0) + MMAT(m, 0, 2)) * oneOverS,
|
||||
(MMAT(m, 2, 1) + MMAT(m, 1, 2)) * oneOverS,
|
||||
0.25f * s,
|
||||
(MMAT(m, 0, 1) - MMAT(m, 1, 0)) * oneOverS);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
const float trace = MMAT(m,0,0) + MMAT(m,1,1) + MMAT(m,2,2) + 1.0f;
|
||||
if (trace > Math::epsilon)
|
||||
{
|
||||
const float s = 0.5f / Math::Sqrt(trace);
|
||||
result.w = 0.25f / s;
|
||||
result.x = ( MMAT(m,1,2) - MMAT(m,2,1) ) * s;
|
||||
result.y = ( MMAT(m,2,0) - MMAT(m,0,2) ) * s;
|
||||
result.z = ( MMAT(m,0,1) - MMAT(m,1,0) ) * s;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MMAT(m,0,0) > MMAT(m,1,1) && MMAT(m,0,0) > MMAT(m,2,2))
|
||||
{
|
||||
const float s = 2.0f * Math::Sqrt( 1.0f + MMAT(m,0,0) - MMAT(m,1,1) - MMAT(m,2,2));
|
||||
const float oneOverS = 1.0f / s;
|
||||
result.x = 0.25f * s;
|
||||
result.y = (MMAT(m,1,0) + MMAT(m,0,1) ) * oneOverS;
|
||||
result.z = (MMAT(m,2,0) + MMAT(m,0,2) ) * oneOverS;
|
||||
result.w = (MMAT(m,2,1) - MMAT(m,1,2) ) * oneOverS;
|
||||
}
|
||||
else
|
||||
if (MMAT(m,1,1) > MMAT(m,2,2))
|
||||
{
|
||||
const float s = 2.0f * Math::Sqrt( 1.0f + MMAT(m,1,1) - MMAT(m,0,0) - MMAT(m,2,2));
|
||||
const float oneOverS = 1.0f / s;
|
||||
result.x = (MMAT(m,1,0) + MMAT(m,0,1) ) * oneOverS;
|
||||
result.y = 0.25f * s;
|
||||
result.z = (MMAT(m,2,1) + MMAT(m,1,2) ) * oneOverS;
|
||||
result.w = (MMAT(m,2,0) - MMAT(m,0,2) ) * oneOverS;
|
||||
}
|
||||
else
|
||||
{
|
||||
const float s = 2.0f * Math::Sqrt( 1.0f + MMAT(m,2,2) - MMAT(m,0,0) - MMAT(m,1,1) );
|
||||
const float oneOverS = 1.0f / s;
|
||||
result.x = (MMAT(m,2,0) + MMAT(m,0,2) ) * oneOverS;
|
||||
result.y = (MMAT(m,2,1) + MMAT(m,1,2) ) * oneOverS;
|
||||
result.z = 0.25f * s;
|
||||
result.w = (MMAT(m,1,0) - MMAT(m,0,1) ) * oneOverS;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
} // namespace MCore
|
||||
|
||||
@@ -2248,27 +2248,6 @@ namespace MCore
|
||||
}
|
||||
|
||||
|
||||
|
||||
// simple decompose a matrix into translation and rotation
|
||||
void Matrix::Decompose(AZ::Vector3* outTranslation, AZ::Quaternion* outRotation) const
|
||||
{
|
||||
// make a copy of the matrix
|
||||
Matrix mat(*this);
|
||||
|
||||
// normalize the basis vectors
|
||||
mat.SetRight(SafeNormalize(mat.GetRight()));
|
||||
mat.SetUp(SafeNormalize(mat.GetUp()));
|
||||
mat.SetForward(SafeNormalize(mat.GetForward()));
|
||||
|
||||
// extract the translation from the matrix
|
||||
*outTranslation = mat.GetTranslation();
|
||||
|
||||
// convert the normalized 3x3 rotation part into a AZ::Quaternion
|
||||
*outRotation = MCore::MCoreMatrixToQuaternion(*this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// calculate a rotation matrix from two vectors
|
||||
void Matrix::SetRotationMatrixTwoVectors(const AZ::Vector3& from, const AZ::Vector3& to)
|
||||
{
|
||||
@@ -2365,30 +2344,6 @@ namespace MCore
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
void Matrix::DecomposeQRGramSchmidt(AZ::Vector3& translation, AZ::Quaternion& rot, AZ::Vector3& scale, AZ::Vector3& shear) const
|
||||
{
|
||||
Matrix rotMatrix;
|
||||
DecomposeQRGramSchmidt(translation, rotMatrix, scale, shear);
|
||||
rot = MCore::MCoreMatrixToQuaternion(*this);
|
||||
}
|
||||
|
||||
//
|
||||
void Matrix::DecomposeQRGramSchmidt(AZ::Vector3& translation, AZ::Quaternion& rot, AZ::Vector3& scale) const
|
||||
{
|
||||
Matrix rotMatrix;
|
||||
DecomposeQRGramSchmidt(translation, rotMatrix, scale);
|
||||
rot = MCore::MCoreMatrixToQuaternion(rotMatrix);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
void Matrix::DecomposeQRGramSchmidt(AZ::Vector3& translation, AZ::Quaternion& rot) const
|
||||
{
|
||||
Matrix rotMatrix;
|
||||
DecomposeQRGramSchmidt(translation, rotMatrix);
|
||||
rot = MCore::MCoreMatrixToQuaternion(rotMatrix);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
|
||||
@@ -685,26 +685,11 @@ namespace MCore
|
||||
*/
|
||||
void Frustum(float left, float right, float top, float bottom, float znear, float zfar);
|
||||
|
||||
/**
|
||||
* Decompose a transformation matrix into translation and rotation components.
|
||||
* The translation part is just the translation part of the matrix.
|
||||
* The rotation AZ::Quaternion is calculated by normalizing the basis vectors and converting the
|
||||
* 3x3 rotation part of the matrix to a AZ::Quaternion.
|
||||
* It is allowed for the matrix to contain scaling.
|
||||
* The matrix where you call Decompose on remains unchanged.
|
||||
* @param outTranslation A pointer to a vector where the translation will be written to.
|
||||
* @param outRotation A pointer to a AZ::Quaternion where the rotation will be written to.
|
||||
* @note Please keep in mind that nullptr values for the parameters are NOT allowed.
|
||||
*/
|
||||
void Decompose(AZ::Vector3* outTranslation, AZ::Quaternion* outRotation) const;
|
||||
|
||||
// QR Gram-Schmidt decomposition
|
||||
void DecomposeQRGramSchmidt(AZ::Vector3& translation, AZ::Quaternion& rot) const;
|
||||
void DecomposeQRGramSchmidt(AZ::Vector3& translation, Matrix& rot) const;
|
||||
void DecomposeQRGramSchmidt(AZ::Vector3& translation, Matrix& rot, AZ::Vector3& scale) const;
|
||||
void DecomposeQRGramSchmidt(AZ::Vector3& translation, Matrix& rot, AZ::Vector3& scale, AZ::Vector3& shear) const;
|
||||
void DecomposeQRGramSchmidt(AZ::Vector3& translation, AZ::Quaternion& rot, AZ::Vector3& scale, AZ::Vector3& shear) const;
|
||||
void DecomposeQRGramSchmidt(AZ::Vector3& translation, AZ::Quaternion& rot, AZ::Vector3& scale) const;
|
||||
|
||||
static Matrix OuterProduct(const AZ::Vector4& column, const AZ::Vector4& row);
|
||||
|
||||
|
||||
@@ -1,604 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
// include required headers
|
||||
#include "Quaternion.h"
|
||||
#include <AzCore/std/typetraits/aligned_storage.h>
|
||||
|
||||
namespace MCore
|
||||
{
|
||||
// spherical quadratic interpolation
|
||||
Quaternion Quaternion::Squad(const Quaternion& p, const Quaternion& a, const Quaternion& b, const Quaternion& q, float t)
|
||||
{
|
||||
Quaternion q0(p.Slerp(q, t));
|
||||
Quaternion q1(a.Slerp(b, t));
|
||||
return q0.Slerp(q1, 2.0f * t * (1.0f - t));
|
||||
}
|
||||
|
||||
|
||||
// returns the approximately normalized linear interpolated result [t must be between 0..1]
|
||||
Quaternion Quaternion::NLerp(const Quaternion& to, float t) const
|
||||
{
|
||||
AZ_Assert(t > -MCore::Math::epsilon && t < (1 + MCore::Math::epsilon), "Expected t to be between 0..1");
|
||||
static const float weightCloseToOne = 1.0f - MCore::Math::epsilon;
|
||||
|
||||
// Early out for boundaries (common cases)
|
||||
if (t < MCore::Math::epsilon)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
else if (t > weightCloseToOne)
|
||||
{
|
||||
return to;
|
||||
}
|
||||
|
||||
#if AZ_TRAIT_USE_PLATFORM_SIMD_SSE
|
||||
__m128 num1, num2, num3, num4, fromVec, toVec;
|
||||
const float omt = 1.0f - t;
|
||||
float dot;
|
||||
|
||||
// perform dot product between this quat and the 'to' quat
|
||||
num4 = _mm_setzero_ps(); // sets sum to zero
|
||||
fromVec = _mm_loadu_ps(&x); //
|
||||
toVec = _mm_loadu_ps(&to.x); //
|
||||
num3 = _mm_mul_ps(fromVec, toVec); // performs multiplication num3 = a[3]*b[3] a[2]*b[2] a[1]*b[1] a[0]*b[0]
|
||||
num3 = _mm_hadd_ps(num3, num3); // performs horizontal addition - num3= a[3]*b[3]+ a[2]*b[2] a[1]*b[1]+a[0]*b[0] a[3]*b[3]+ a[2]*b[2] a[1]*b[1]+a[0]*b[0]
|
||||
num4 = _mm_add_ps(num4, num3); // performs vertical addition
|
||||
num4 = _mm_hadd_ps(num4, num4);
|
||||
_mm_store_ss(&dot, num4); // store the dot result
|
||||
|
||||
if (dot < 0.0f)
|
||||
{
|
||||
t = -t;
|
||||
}
|
||||
|
||||
// calculate interpolated value
|
||||
num2 = _mm_load_ps1(&omt);
|
||||
num3 = _mm_load_ps1(&t);
|
||||
num4 = _mm_mul_ps(fromVec, num2); // omt * xyzw
|
||||
num1 = _mm_mul_ps(toVec, num3); // t * to.xyzw
|
||||
num2 = _mm_add_ps(num1, num4); // interpolated value
|
||||
|
||||
// calculate the square length
|
||||
num4 = _mm_setzero_ps();
|
||||
num3 = _mm_mul_ps(num2, num2); // square length
|
||||
num1 = _mm_hadd_ps(num3, num3);
|
||||
num4 = _mm_add_ps(num4, num1);
|
||||
num3 = _mm_hadd_ps(num4, num4);
|
||||
//num4 = _mm_rsqrt_ps( num3 ); // length (argh, too inaccurate on some models)
|
||||
|
||||
AZStd::aligned_storage<sizeof(float) * 4, 16>::type numFloatStorage;
|
||||
float* numFloat = reinterpret_cast<float*>(&numFloatStorage);
|
||||
|
||||
_mm_store_ps(numFloat, num3);
|
||||
const float invLen = Math::InvSqrt(numFloat[0]);
|
||||
num4 = _mm_load_ps1(&invLen);
|
||||
|
||||
// calc inverse length, which normalizes everything
|
||||
num1 = _mm_mul_ps(num2, num4);
|
||||
|
||||
_mm_store_ps(numFloat, num1);
|
||||
return Quaternion(numFloat[0], numFloat[1], numFloat[2], numFloat[3]);
|
||||
#else
|
||||
const float omt = 1.0f - t;
|
||||
const float dot = x * to.x + y * to.y + z * to.z + w * to.w;
|
||||
if (dot < 0.0f)
|
||||
{
|
||||
t = -t;
|
||||
}
|
||||
|
||||
// calculate the interpolated values
|
||||
const float newX = (omt * x + t * to.x);
|
||||
const float newY = (omt * y + t * to.y);
|
||||
const float newZ = (omt * z + t * to.z);
|
||||
const float newW = (omt * w + t * to.w);
|
||||
|
||||
// calculate the inverse length
|
||||
// const float invLen = 1.0f / Math::FastSqrt( newX*newX + newY*newY + newZ*newZ + newW*newW );
|
||||
// const float invLen = Math::FastInvSqrt( newX*newX + newY*newY + newZ*newZ + newW*newW );
|
||||
const float invLen = Math::InvSqrt(newX * newX + newY * newY + newZ * newZ + newW * newW);
|
||||
|
||||
// return the normalized linear interpolation
|
||||
return Quaternion(newX * invLen,
|
||||
newY * invLen,
|
||||
newZ * invLen,
|
||||
newW * invLen);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
// returns the linear interpolated result [t must be between 0..1]
|
||||
Quaternion Quaternion::Lerp(const Quaternion& to, float t) const
|
||||
{
|
||||
const float omt = 1.0f - t;
|
||||
const float cosom = x * to.x + y * to.y + z * to.z + w * to.w;
|
||||
if (cosom < 0.0f)
|
||||
{
|
||||
t = -t;
|
||||
}
|
||||
|
||||
// return the linear interpolation
|
||||
return Quaternion(omt * x + t * to.x,
|
||||
omt * y + t * to.y,
|
||||
omt * z + t * to.z,
|
||||
omt * w + t * to.w);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// quaternion from an axis and angle
|
||||
Quaternion::Quaternion(const AZ::Vector3& axis, float angle)
|
||||
{
|
||||
const float squaredLength = axis.GetLengthSq();
|
||||
if (squaredLength > 0.0f)
|
||||
{
|
||||
const float halfAngle = angle * 0.5f;
|
||||
const float sinScale = Math::Sin(halfAngle) / Math::Sqrt(squaredLength);
|
||||
x = axis.GetX() * sinScale;
|
||||
y = axis.GetY() * sinScale;
|
||||
z = axis.GetZ() * sinScale;
|
||||
w = Math::Cos(halfAngle);
|
||||
}
|
||||
else
|
||||
{
|
||||
x = y = z = 0.0f;
|
||||
w = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// quaternion from a spherical rotation
|
||||
Quaternion::Quaternion(const AZ::Vector2& spherical, float angle)
|
||||
{
|
||||
const float latitude = spherical.GetX();
|
||||
const float longitude = spherical.GetY();
|
||||
|
||||
const float s = Math::Sin(angle / 2.0f);
|
||||
const float c = Math::Cos(angle / 2.0f);
|
||||
|
||||
const float sin_lat = Math::Sin(latitude);
|
||||
const float cos_lat = Math::Cos(latitude);
|
||||
|
||||
const float sin_lon = Math::Sin(longitude);
|
||||
const float cos_lon = Math::Cos(longitude);
|
||||
|
||||
x = s * cos_lat * sin_lon;
|
||||
y = s * sin_lat;
|
||||
z = s * sin_lat * cos_lon;
|
||||
w = c;
|
||||
}
|
||||
|
||||
|
||||
// convert to an axis and angle
|
||||
void Quaternion::ToAxisAngle(AZ::Vector3* axis, float* angle) const
|
||||
{
|
||||
*angle = 2.0f * Math::ACos(w);
|
||||
|
||||
const float sinHalfAngle = Math::Sin(*angle * 0.5f);
|
||||
if (sinHalfAngle > 0.0f)
|
||||
{
|
||||
const float invS = 1.0f / sinHalfAngle;
|
||||
axis->Set(x * invS, y * invS, z * invS);
|
||||
}
|
||||
else
|
||||
{
|
||||
axis->Set(0.0f, 1.0f, 0.0f);
|
||||
*angle = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// converts from unit quaternion to spherical rotation angles
|
||||
void Quaternion::ToSpherical(AZ::Vector2* spherical, float* angle) const
|
||||
{
|
||||
AZ::Vector3 axis;
|
||||
ToAxisAngle(&axis, angle);
|
||||
|
||||
float longitude;
|
||||
if (axis.GetX() * axis.GetX() + axis.GetZ() * axis.GetZ() < 0.0001f)
|
||||
{
|
||||
longitude = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
longitude = Math::ATan2(axis.GetX(), axis.GetZ());
|
||||
if (longitude < 0.0f)
|
||||
{
|
||||
longitude += Math::twoPi;
|
||||
}
|
||||
}
|
||||
|
||||
spherical->SetX(-Math::ASin(axis.GetY()));
|
||||
spherical->SetY(longitude);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// setup the quaternion from a roll, pitch and yaw
|
||||
Quaternion& Quaternion::SetEuler(float pitch, float yaw, float roll)
|
||||
{
|
||||
// METHOD #1:
|
||||
const float halfYaw = yaw * 0.5f;
|
||||
const float halfPitch = pitch * 0.5f;
|
||||
const float halfRoll = roll * 0.5f;
|
||||
|
||||
const float cY = Math::Cos(halfYaw);
|
||||
const float sY = Math::Sin(halfYaw);
|
||||
const float cP = Math::Cos(halfPitch);
|
||||
const float sP = Math::Sin(halfPitch);
|
||||
const float cR = Math::Cos(halfRoll);
|
||||
const float sR = Math::Sin(halfRoll);
|
||||
|
||||
x = cY * sP * cR - sY * cP * sR;
|
||||
y = cY * sP * sR + sY * cP * cR;
|
||||
z = cY * cP * sR - sY * sP * cR;
|
||||
w = cY * cP * cR + sY * sP * sR;
|
||||
|
||||
// Normalize(); // we might be able to leave the normalize away, but better safe than not, this is more robust :)
|
||||
|
||||
return *this;
|
||||
|
||||
/*
|
||||
|
||||
// METHOD #2:
|
||||
Quaternion Qx(Vector3(sP, 0, 0), cP);
|
||||
Quaternion Qy(Vector3(0, sY, 0), cY);
|
||||
Quaternion Qz(Vector3(0, 0, sR), cR);
|
||||
|
||||
Quaternion result = Qx * Qy * Qz;
|
||||
|
||||
x = result.x;
|
||||
y = result.y;
|
||||
z = result.z;
|
||||
w = result.w;
|
||||
|
||||
return *this;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
// convert the quaternion to a matrix
|
||||
Matrix Quaternion::ToMatrix() const
|
||||
{
|
||||
Matrix m;
|
||||
|
||||
const float xx = x * x;
|
||||
const float xy = x * y, yy = y * y;
|
||||
const float xz = x * z, yz = y * z, zz = z * z;
|
||||
const float xw = x * w, yw = y * w, zw = z * w, ww = w * w;
|
||||
|
||||
MMAT(m, 0, 0) = +xx - yy - zz + ww;
|
||||
MMAT(m, 0, 1) = +xy + zw + xy + zw;
|
||||
MMAT(m, 0, 2) = +xz - yw + xz - yw;
|
||||
MMAT(m, 0, 3) = 0.0f;
|
||||
MMAT(m, 1, 0) = +xy - zw + xy - zw;
|
||||
MMAT(m, 1, 1) = -xx + yy - zz + ww;
|
||||
MMAT(m, 1, 2) = +yz + xw + yz + xw;
|
||||
MMAT(m, 1, 3) = 0.0f;
|
||||
MMAT(m, 2, 0) = +xz + yw + xz + yw;
|
||||
MMAT(m, 2, 1) = +yz - xw + yz - xw;
|
||||
MMAT(m, 2, 2) = -xx - yy + zz + ww;
|
||||
MMAT(m, 2, 3) = 0.0f;
|
||||
MMAT(m, 3, 0) = 0.0f;
|
||||
MMAT(m, 3, 1) = 0.0f;
|
||||
MMAT(m, 3, 2) = 0.0f;
|
||||
MMAT(m, 3, 3) = 1.0f;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// construct the quaternion from a given rotation matrix
|
||||
Quaternion Quaternion::ConvertFromMatrix(const Matrix& m)
|
||||
{
|
||||
Quaternion result;
|
||||
|
||||
const float trace = MMAT(m, 0, 0) + MMAT(m, 1, 1) + MMAT(m, 2, 2);
|
||||
if (trace > 0.0f /*Math::epsilon*/)
|
||||
{
|
||||
const float s = 0.5f / Math::Sqrt(trace + 1.0f);
|
||||
result.w = 0.25f / s;
|
||||
result.x = (MMAT(m, 1, 2) - MMAT(m, 2, 1)) * s;
|
||||
result.y = (MMAT(m, 2, 0) - MMAT(m, 0, 2)) * s;
|
||||
result.z = (MMAT(m, 0, 1) - MMAT(m, 1, 0)) * s;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MMAT(m, 0, 0) > MMAT(m, 1, 1) && MMAT(m, 0, 0) > MMAT(m, 2, 2))
|
||||
{
|
||||
const float s = 2.0f * Math::Sqrt(1.0f + MMAT(m, 0, 0) - MMAT(m, 1, 1) - MMAT(m, 2, 2));
|
||||
const float oneOverS = 1.0f / s;
|
||||
result.x = 0.25f * s;
|
||||
result.y = (MMAT(m, 1, 0) + MMAT(m, 0, 1)) * oneOverS;
|
||||
result.z = (MMAT(m, 2, 0) + MMAT(m, 0, 2)) * oneOverS;
|
||||
result.w = (MMAT(m, 1, 2) - MMAT(m, 2, 1)) * oneOverS;
|
||||
}
|
||||
else
|
||||
if (MMAT(m, 1, 1) > MMAT(m, 2, 2))
|
||||
{
|
||||
const float s = 2.0f * Math::Sqrt(1.0f + MMAT(m, 1, 1) - MMAT(m, 0, 0) - MMAT(m, 2, 2));
|
||||
const float oneOverS = 1.0f / s;
|
||||
result.x = (MMAT(m, 1, 0) + MMAT(m, 0, 1)) * oneOverS;
|
||||
result.y = 0.25f * s;
|
||||
result.z = (MMAT(m, 2, 1) + MMAT(m, 1, 2)) * oneOverS;
|
||||
result.w = (MMAT(m, 2, 0) - MMAT(m, 0, 2)) * oneOverS;
|
||||
}
|
||||
else
|
||||
{
|
||||
const float s = 2.0f * Math::Sqrt(1.0f + MMAT(m, 2, 2) - MMAT(m, 0, 0) - MMAT(m, 1, 1));
|
||||
const float oneOverS = 1.0f / s;
|
||||
result.x = (MMAT(m, 2, 0) + MMAT(m, 0, 2)) * oneOverS;
|
||||
result.y = (MMAT(m, 2, 1) + MMAT(m, 1, 2)) * oneOverS;
|
||||
result.z = 0.25f * s;
|
||||
result.w = (MMAT(m, 0, 1) - MMAT(m, 1, 0)) * oneOverS;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
const float trace = MMAT(m,0,0) + MMAT(m,1,1) + MMAT(m,2,2) + 1.0f;
|
||||
if (trace > Math::epsilon)
|
||||
{
|
||||
const float s = 0.5f / Math::Sqrt(trace);
|
||||
result.w = 0.25f / s;
|
||||
result.x = ( MMAT(m,1,2) - MMAT(m,2,1) ) * s;
|
||||
result.y = ( MMAT(m,2,0) - MMAT(m,0,2) ) * s;
|
||||
result.z = ( MMAT(m,0,1) - MMAT(m,1,0) ) * s;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MMAT(m,0,0) > MMAT(m,1,1) && MMAT(m,0,0) > MMAT(m,2,2))
|
||||
{
|
||||
const float s = 2.0f * Math::Sqrt( 1.0f + MMAT(m,0,0) - MMAT(m,1,1) - MMAT(m,2,2));
|
||||
const float oneOverS = 1.0f / s;
|
||||
result.x = 0.25f * s;
|
||||
result.y = (MMAT(m,1,0) + MMAT(m,0,1) ) * oneOverS;
|
||||
result.z = (MMAT(m,2,0) + MMAT(m,0,2) ) * oneOverS;
|
||||
result.w = (MMAT(m,2,1) - MMAT(m,1,2) ) * oneOverS;
|
||||
}
|
||||
else
|
||||
if (MMAT(m,1,1) > MMAT(m,2,2))
|
||||
{
|
||||
const float s = 2.0f * Math::Sqrt( 1.0f + MMAT(m,1,1) - MMAT(m,0,0) - MMAT(m,2,2));
|
||||
const float oneOverS = 1.0f / s;
|
||||
result.x = (MMAT(m,1,0) + MMAT(m,0,1) ) * oneOverS;
|
||||
result.y = 0.25f * s;
|
||||
result.z = (MMAT(m,2,1) + MMAT(m,1,2) ) * oneOverS;
|
||||
result.w = (MMAT(m,2,0) - MMAT(m,0,2) ) * oneOverS;
|
||||
}
|
||||
else
|
||||
{
|
||||
const float s = 2.0f * Math::Sqrt( 1.0f + MMAT(m,2,2) - MMAT(m,0,0) - MMAT(m,1,1) );
|
||||
const float oneOverS = 1.0f / s;
|
||||
result.x = (MMAT(m,2,0) + MMAT(m,0,2) ) * oneOverS;
|
||||
result.y = (MMAT(m,2,1) + MMAT(m,1,2) ) * oneOverS;
|
||||
result.z = 0.25f * s;
|
||||
result.w = (MMAT(m,1,0) - MMAT(m,0,1) ) * oneOverS;
|
||||
}
|
||||
}
|
||||
*/
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// convert a quaternion to euler angles (in degrees)
|
||||
AZ::Vector3 Quaternion::ToEuler() const
|
||||
{
|
||||
/*
|
||||
// METHOD #1:
|
||||
|
||||
Vector3 euler;
|
||||
|
||||
float matrix[3][3];
|
||||
float cx,sx;
|
||||
float cy,sy,yr;
|
||||
float cz,sz;
|
||||
|
||||
matrix[0][0] = 1.0 - (2.0 * y * y) - (2.0 * z * z);
|
||||
matrix[1][0] = (2.0 * x * y) + (2.0 * w * z);
|
||||
matrix[2][0] = (2.0 * x * z) - (2.0 * w * y);
|
||||
matrix[2][1] = (2.0 * y * z) + (2.0 * w * x);
|
||||
matrix[2][2] = 1.0 - (2.0 * x * x) - (2.0 * y * y);
|
||||
|
||||
sy = -matrix[2][0];
|
||||
cy = Math::Sqrt(1 - (sy * sy));
|
||||
yr = Math::ATan2(sy,cy);
|
||||
euler.y = yr;
|
||||
|
||||
// avoid divide by zero only where y ~90 or ~270
|
||||
if (sy != 1.0 && sy != -1.0)
|
||||
{
|
||||
cx = matrix[2][2] / cy;
|
||||
sx = matrix[2][1] / cy;
|
||||
euler.x = Math::ATan2(sx,cx);
|
||||
|
||||
cz = matrix[0][0] / cy;
|
||||
sz = matrix[1][0] / cy;
|
||||
euler.z = Math::ATan2(sz,cz);
|
||||
}
|
||||
else
|
||||
{
|
||||
matrix[1][1] = 1.0 - (2.0 * x * x) - (2.0 * z * z);
|
||||
matrix[1][2] = (2.0 * y * z) - (2.0 * w * x);
|
||||
cx = matrix[1][1];
|
||||
sx = -matrix[1][2];
|
||||
euler.x = Math::ATan2(sx,cx);
|
||||
|
||||
cz = 1.0;
|
||||
sz = 0.0;
|
||||
euler.z = Math::ATan2(sz,cz);
|
||||
}
|
||||
|
||||
return euler;
|
||||
*/
|
||||
|
||||
/*
|
||||
// METHOD #2:
|
||||
Matrix mat = ToMatrix();
|
||||
|
||||
//
|
||||
float cy = Math::Sqrt(mat.m44[0][0]*mat.m44[0][0] + mat.m44[0][1]*mat.m44[0][1]);
|
||||
if (cy > 16.0*Math::epsilon)
|
||||
{
|
||||
result.x = -atan2(mat.m44[1][2], mat.m44[2][2]);
|
||||
result.y = -atan2(-mat.m44[0][2], cy);
|
||||
result.z = -atan2(mat.m44[0][1], mat.m44[0][0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.x = -atan2(-mat.m44[2][1], mat.m44[1][1]);
|
||||
result.y = -atan2(-mat.m44[0][2], cy);
|
||||
result.z = 0.0;
|
||||
}
|
||||
|
||||
return result;
|
||||
*/
|
||||
|
||||
// METHOD #3 (without conversion to matrix first):
|
||||
// TODO: safety checks?
|
||||
float m00 = 1.0f - (2.0f * ((y * y) + z * z));
|
||||
float m01 = 2.0f * (x * y + w * z);
|
||||
|
||||
AZ::Vector3 result(
|
||||
Math::ATan2(2.0f * (y * z + w * x), 1.0f - (2.0f * ((x * x) + (y * y)))),
|
||||
Math::ATan2(-2.0f * (x * z - w * y), Math::Sqrt((m00 * m00) + (m01 * m01))),
|
||||
Math::ATan2(m01, m00)
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
float Quaternion::GetEulerZ() const
|
||||
{
|
||||
float m00 = 1.0f - (2.0f * ((y * y) + z * z));
|
||||
float m01 = 2.0f * (x * y + w * z);
|
||||
return Math::ATan2(m01, m00);
|
||||
}
|
||||
|
||||
// returns the spherical interpolated result [t must be between 0..1]
|
||||
Quaternion Quaternion::Slerp(const Quaternion& to, float t) const
|
||||
{
|
||||
float cosom = (x * to.x) + (y * to.y) + (z * to.z) + (w * to.w);
|
||||
float scale0, scale1, scale1sign = 1.0f;
|
||||
|
||||
if (cosom < 0.0f)
|
||||
{
|
||||
scale1sign = -1.0f;
|
||||
cosom *= -1.0f;
|
||||
}
|
||||
|
||||
if ((1.0 - cosom) > Math::epsilon)
|
||||
{
|
||||
const float omega = Math::ACos(cosom);
|
||||
const float sinOmega = Math::Sin(omega);
|
||||
const float oosinom = 1.0f / sinOmega;
|
||||
scale0 = Math::Sin((1.0f - t) * omega) * oosinom;
|
||||
scale1 = Math::Sin(t * omega) * oosinom;
|
||||
}
|
||||
else
|
||||
{
|
||||
scale0 = 1.0f - t;
|
||||
scale1 = t;
|
||||
}
|
||||
|
||||
scale1 *= scale1sign;
|
||||
|
||||
return Quaternion(scale0 * x + scale1 * to.x,
|
||||
scale0 * y + scale1 * to.y,
|
||||
scale0 * z + scale1 * to.z,
|
||||
scale0 * w + scale1 * to.w);
|
||||
}
|
||||
|
||||
|
||||
// set as delta rotation
|
||||
Quaternion Quaternion::CreateDeltaRotation(const AZ::Vector3& fromVector, const AZ::Vector3& toVector)
|
||||
{
|
||||
Quaternion q;
|
||||
q.SetAsDeltaRotation(fromVector, toVector);
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
// set as delta rotation but limited
|
||||
Quaternion Quaternion::CreateDeltaRotation(const AZ::Vector3& fromVector, const AZ::Vector3& toVector, float maxAngleRadians)
|
||||
{
|
||||
Quaternion q;
|
||||
q.SetAsDeltaRotation(fromVector, toVector, maxAngleRadians);
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
// set as delta rotation
|
||||
void Quaternion::SetAsDeltaRotation(const AZ::Vector3& fromVector, const AZ::Vector3& toVector)
|
||||
{
|
||||
// check if we are in parallel or not
|
||||
const float dot = fromVector.Dot(toVector);
|
||||
if (dot < 0.99999f) // we have rotated compared to the forward direction
|
||||
{
|
||||
const float angleRadians = Math::ACos(dot);
|
||||
const AZ::Vector3 rotAxis = fromVector.Cross(toVector);
|
||||
*this = Quaternion(rotAxis, angleRadians);
|
||||
}
|
||||
else
|
||||
{
|
||||
Identity();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// set as delta rotation, but limited
|
||||
void Quaternion::SetAsDeltaRotation(const AZ::Vector3& fromVector, const AZ::Vector3& toVector, float maxAngleRadians)
|
||||
{
|
||||
// check if we are in parallel or not
|
||||
const float dot = fromVector.Dot(toVector);
|
||||
if (dot < 0.99999f) // we have rotated compared to the forward direction
|
||||
{
|
||||
const float angleRadians = Math::ACos(dot);
|
||||
const float rotAngle = Min(angleRadians, maxAngleRadians);
|
||||
const AZ::Vector3 rotAxis = fromVector.Cross(toVector);
|
||||
*this = Quaternion(rotAxis, rotAngle);
|
||||
}
|
||||
else
|
||||
{
|
||||
Identity();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Decompose the rotation on to 2 parts.
|
||||
1. Twist - rotation around the "direction" vector
|
||||
2. Swing - rotation around axis that is perpendicular to "direction" vector
|
||||
The rotation can be composed back by
|
||||
rotation = swing * twist
|
||||
|
||||
has singularity in case of swing_rotation close to 180 degrees rotation.
|
||||
if the input quaternion is of non-unit length, the outputs are non-unit as well
|
||||
otherwise, outputs are both unit
|
||||
*/
|
||||
void Quaternion::DecomposeSwingTwist(const AZ::Vector3& direction, Quaternion* outSwing, Quaternion* outTwist) const
|
||||
{
|
||||
AZ::Vector3 rotAxis(x, y, z);
|
||||
AZ::Vector3 p = Projected(rotAxis, direction); // return projection v1 on to v2 (parallel component)
|
||||
outTwist->Set(p.GetX(), p.GetY(), p.GetZ(), w);
|
||||
outTwist->Normalize();
|
||||
*outSwing = *this * outTwist->Conjugated();
|
||||
}
|
||||
|
||||
|
||||
// rotate the current quaternion and renormalize it
|
||||
void Quaternion::RotateFromTo(const AZ::Vector3& fromVector, const AZ::Vector3& toVector)
|
||||
{
|
||||
*this = CreateDeltaRotation(fromVector, toVector) * *this;
|
||||
Normalize();
|
||||
}
|
||||
} // namespace MCore
|
||||
|
||||
@@ -1,386 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// include required headers
|
||||
#include <AzCore/RTTI/TypeInfo.h>
|
||||
#include <AzCore/Math/Vector2.h>
|
||||
#include "StandardHeaders.h"
|
||||
#include "FastMath.h"
|
||||
#include "Vector.h"
|
||||
#include "Matrix4.h"
|
||||
#include "Algorithms.h"
|
||||
|
||||
|
||||
namespace MCore
|
||||
{
|
||||
/**
|
||||
* Depracated. Please use AZ::Quaternion instead.
|
||||
* The quaternion class in MCore.
|
||||
* Quaternions are mostly used to represent rotations in 3D applications.
|
||||
* The advantages of quaternions over matrices are that they take up less space and that interpolation between
|
||||
* two quaternions is easier to perform. Instead of a 3x3 rotation matrix, which is 9 floats or doubles, a quaternion
|
||||
* only uses 4 floats or doubles. This template/class provides you with methods to perform all kind of operations on
|
||||
* these quaternions, from interpolation to conversion to matrices and other rotation representations.
|
||||
*/
|
||||
class MCORE_API Quaternion
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(MCore::Quaternion, "{1807CD22-EBB5-45E8-8113-3B1DABB53F12}")
|
||||
|
||||
/**
|
||||
* Default constructor. Sets x, y and z to 0 and w to 1.
|
||||
*/
|
||||
MCORE_INLINE Quaternion()
|
||||
: x(0.0f)
|
||||
, y(0.0f)
|
||||
, z(0.0f)
|
||||
, w(1.0f) {}
|
||||
|
||||
/**
|
||||
* Constructor which sets the x, y, z and w.
|
||||
* @param xVal The value of x.
|
||||
* @param yVal The value of y.
|
||||
* @param zVal The value of z.
|
||||
* @param wVal The value of w.
|
||||
*/
|
||||
MCORE_INLINE Quaternion(float xVal, float yVal, float zVal, float wVal)
|
||||
: x(xVal)
|
||||
, y(yVal)
|
||||
, z(zVal)
|
||||
, w(wVal) {}
|
||||
|
||||
/**
|
||||
* Copy constructor. Copies the x, y, z, w values from the other quaternion.
|
||||
* @param other The quaternion to copy the attributes from.
|
||||
*/
|
||||
MCORE_INLINE Quaternion(const Quaternion& other)
|
||||
: x(other.x)
|
||||
, y(other.y)
|
||||
, z(other.z)
|
||||
, w(other.w) {}
|
||||
|
||||
/**
|
||||
* Constructor which creates a quaternion from a pitch, yaw and roll.
|
||||
* @param pitch Rotation around the x-axis, in radians.
|
||||
* @param yaw Rotation around the y-axis, in radians.
|
||||
* @param roll Rotation around the z-axis, in radians.
|
||||
*/
|
||||
MCORE_INLINE Quaternion(float pitch, float yaw, float roll) { SetEuler(pitch, yaw, roll); }
|
||||
|
||||
/**
|
||||
* Constructor which takes a matrix as input parameter.
|
||||
* This converts the rotation of the specified matrix into a quaternion. Please keep in mind that the matrix may NOT contain
|
||||
* any scaling, so if it does, please normalize your matrix first!
|
||||
* @param matrix The matrix to initialize the quaternion from.
|
||||
*/
|
||||
MCORE_INLINE Quaternion(const Matrix& matrix) { FromMatrix(matrix); }
|
||||
|
||||
/**
|
||||
* Constructor which creates a quaternion from a spherical rotation.
|
||||
* @param spherical The spherical coordinates in radians, which creates an axis to rotate around.
|
||||
* @param angle The angle to rotate around this axis.
|
||||
*/
|
||||
Quaternion(const AZ::Vector2& spherical, float angle);
|
||||
|
||||
/**
|
||||
* Constructor which creates a quaternion from an axis and angle.
|
||||
* @param axis The axis to rotate around.
|
||||
* @param angle The angle in radians to rotate around the given axis.
|
||||
*/
|
||||
Quaternion(const AZ::Vector3& axis, float angle);
|
||||
|
||||
/**
|
||||
* Set the quaternion x/y/z/w component values.
|
||||
* @param vx The value of x.
|
||||
* @param vy The value of y.
|
||||
* @param vz The value of z.
|
||||
* @param vw The value of w.
|
||||
*/
|
||||
MCORE_INLINE void Set(float vx, float vy, float vz, float vw) { x = vx; y = vy; z = vz; w = vw; }
|
||||
|
||||
/**
|
||||
* Calculates the square length of the quaternion.
|
||||
* @result The square length (length*length).
|
||||
*/
|
||||
MCORE_INLINE float SquareLength() const { return (x * x + y * y + z * z + w * w); }
|
||||
|
||||
/**
|
||||
* Calculates the length of the quaternion.
|
||||
* It's safe, since it prevents a division by 0.
|
||||
* @result The length of the quaternion.
|
||||
*/
|
||||
MCORE_INLINE float Length() const;
|
||||
|
||||
/**
|
||||
* Performs a dot product on the quaternions.
|
||||
* @param q The quaternion to multiply (dot product) this quaternion with.
|
||||
* @result The quaternion which is the result of the dot product.
|
||||
*/
|
||||
MCORE_INLINE float Dot(const Quaternion& q) const { return (x * q.x + y * q.y + z * q.z + w * q.w); }
|
||||
|
||||
/**
|
||||
* Normalize the quaternion.
|
||||
* @result The normalized quaternion. It modifies itself, so no new quaternion is returned.
|
||||
*/
|
||||
MCORE_INLINE Quaternion& Normalize();
|
||||
|
||||
/**
|
||||
* Sets the quaternion to identity. Where x, y and z are set to 0 and w is set to 1.
|
||||
* @result The quaternion, now set to identity.
|
||||
*/
|
||||
MCORE_INLINE Quaternion& Identity() { x = 0.0f; y = 0.0f; z = 0.0f; w = 1.0f; return *this; }
|
||||
|
||||
/**
|
||||
* Calculate the inversed version of this quaternion.
|
||||
* @result The inversed version of this quaternion.
|
||||
*/
|
||||
MCORE_INLINE Quaternion& Inverse() { const float len = 1.0f / SquareLength(); x = -x * len; y = -y * len; z = -z * len; w = w * len; return *this; }
|
||||
|
||||
/**
|
||||
* Conjugate this quaternion.
|
||||
* @result Returns itself Conjugated.
|
||||
*/
|
||||
MCORE_INLINE Quaternion& Conjugate() { x = -x; y = -y; z = -z; return *this; }
|
||||
|
||||
/**
|
||||
* Calculate the inversed version of this quaternion.
|
||||
* @result The inversed version of this quaternion.
|
||||
*/
|
||||
MCORE_INLINE Quaternion Inversed() const { const float len = 1.0f / SquareLength(); return Quaternion(-x * len, -y * len, -z * len, w * len); }
|
||||
|
||||
/**
|
||||
* Returns the normalized version of this quaternion.
|
||||
* @result The normalized version of this quaternion.
|
||||
*/
|
||||
MCORE_INLINE Quaternion Normalized() const { Quaternion result(*this); result.Normalize(); return result; }
|
||||
|
||||
/**
|
||||
* Return the conjugated version of this quaternion.
|
||||
* @result The conjugated version of this quaternion.
|
||||
*/
|
||||
MCORE_INLINE Quaternion Conjugated() const { return Quaternion(-x, -y, -z, w); }
|
||||
|
||||
/**
|
||||
* Calculate the exponent of this quaternion.
|
||||
* @result The resulting quaternion of the exp.
|
||||
*/
|
||||
MCORE_INLINE Quaternion Exp() const { const float r = Math::Sqrt(x * x + y * y + z * z); const float expW = Math::Exp(w); const float s = (r >= 0.00001f) ? expW* Math::Sin(r) / r : 0.0f; return Quaternion(s * x, s * y, s * z, expW * Math::Cos(r)); }
|
||||
|
||||
/**
|
||||
* Calculate the log of the quaternion.
|
||||
* @result The resulting quaternion of the log.
|
||||
*/
|
||||
MCORE_INLINE Quaternion LogN() const { const float r = Math::Sqrt(x * x + y * y + z * z); float t = (r > 0.00001f) ? Math::ATan2(r, w) / r : 0.0f; return Quaternion(t * x, t * y, t * z, 0.5f * Math::Log(SquareLength())); }
|
||||
|
||||
/**
|
||||
* Calculate and get the right basis vector.
|
||||
* @result The basis vector pointing to the right. This assumes x+ points to the right.
|
||||
*/
|
||||
MCORE_INLINE AZ::Vector3 CalcRightAxis() const;
|
||||
|
||||
/**
|
||||
* Calculate and get the up basis vector.
|
||||
* @result The basis vector pointing upwards. This assumes z+ points up.
|
||||
*/
|
||||
MCORE_INLINE AZ::Vector3 CalcUpAxis() const;
|
||||
|
||||
/**
|
||||
* Calculate and get the forward basis vector.
|
||||
* @result The basis vector pointing forward. This assumes y+ points forward, into the depth.
|
||||
*/
|
||||
MCORE_INLINE AZ::Vector3 CalcForwardAxis() const;
|
||||
|
||||
/**
|
||||
* Initialize the current quaternion from a specified matrix.
|
||||
* Please note that the matrix may not contain any scaling!
|
||||
* So make sure the matrix has been normalized before, if it contains any scale.
|
||||
* @param m The matrix to initialize the quaternion from.
|
||||
*/
|
||||
MCORE_INLINE void FromMatrix(const Matrix& m) { *this = Quaternion::ConvertFromMatrix(m); }
|
||||
|
||||
/**
|
||||
* Setup the quaternion from a pitch, yaw and roll.
|
||||
* @param pitch The rotation around the x-axis, in radians.
|
||||
* @param yaw The rotation around the y-axis, in radians.
|
||||
* @param roll The rotation around the z-axis in radians.
|
||||
* @result The quaternion, now initialized with the given pitch, yaw, roll rotation.
|
||||
*/
|
||||
Quaternion& SetEuler(float pitch, float yaw, float roll);
|
||||
|
||||
/**
|
||||
* Convert the quaternion to an axis and angle. Which represents a rotation of the resulting angle around the resulting axis.
|
||||
* @param axis Pointer to the vector to store the axis in.
|
||||
* @param angle Pointer to the variable to store the angle in (will be in radians).
|
||||
*/
|
||||
void ToAxisAngle(AZ::Vector3* axis, float* angle) const;
|
||||
|
||||
/**
|
||||
* Convert the quaternion to a spherical rotation.
|
||||
* @param spherical A pointer to the 2D vector to store the spherical coordinates in radians, which build the axis.
|
||||
* @param angle The pointer to the variable to store the angle around this axis in radians.
|
||||
*/
|
||||
void ToSpherical(AZ::Vector2* spherical, float* angle) const;
|
||||
|
||||
/**
|
||||
* Extract the euler angles in radians.
|
||||
* The x component of the resulting vector represents the rotation around the x-axis (pitch).
|
||||
* The y component results the rotation around the y-axis (yaw) and the z component represents
|
||||
* the rotation around the z-axis (roll).
|
||||
* @result The 3D vector containing the euler angles in radians, around each axis.
|
||||
*/
|
||||
AZ::Vector3 ToEuler() const;
|
||||
|
||||
/**
|
||||
* Returns the angle of rotation about the z axis. This is same as
|
||||
* the z component of the vector returned by the ToEuler method. It
|
||||
* is just more efficient to call this when one is interested only in rotation about the z axis.
|
||||
* @result The angle of rotation about z axis in radians.
|
||||
*/
|
||||
float GetEulerZ() const;
|
||||
|
||||
/**
|
||||
* Convert this quaternion into a matrix.
|
||||
* @result The matrix representing the rotation of this quaternion.
|
||||
*/
|
||||
Matrix ToMatrix() const;
|
||||
|
||||
/**
|
||||
* Convert a matrix into a quaternion.
|
||||
* Please keep in mind that the specified matrix may NOT contain any scaling!
|
||||
* So make sure the matrix has been normalized before, if it contains any scale.
|
||||
* @param m The matrix to extract the rotation from.
|
||||
* @result The quaternion, now containing the rotation of the given matrix, in quaternion form.
|
||||
*/
|
||||
static Quaternion ConvertFromMatrix(const Matrix& m);
|
||||
|
||||
/**
|
||||
* Create a delta rotation that rotates one vector onto another vector.
|
||||
* @param fromVector The normalized vector to start from. This must be normalized!
|
||||
* @param toVector The normalized vector to rotate towards. This must be normalized as well!
|
||||
* @result The delta rotation quaternion.
|
||||
*/
|
||||
static Quaternion CreateDeltaRotation(const AZ::Vector3& fromVector, const AZ::Vector3& toVector);
|
||||
|
||||
/**
|
||||
* Create a delta rotation that rotates one vector onto another vector.
|
||||
* If the angle is bigger than the max allowed angle that is specified it will rotate with an angle of the maximum specified angle.
|
||||
* So if the angle between the vectors is 40 degrees and you maxAngleRadians equals 10 degrees (in radians) it will only rotate 10 degrees.
|
||||
* @param fromVector The normalized vector to start from. This must be normalized!
|
||||
* @param toVector The normalized vector to rotate towards. This must be normalized as well!
|
||||
* @param maxAngleRadians The maximum rotation angle on the plane defined by the two vectors. This cannot be more than Math::pi (180 degrees).
|
||||
* @result The delta rotation quaternion.
|
||||
*/
|
||||
static Quaternion CreateDeltaRotation(const AZ::Vector3& fromVector, const AZ::Vector3& toVector, float maxAngleRadians);
|
||||
|
||||
/**
|
||||
* Init this quaternion as a delta rotation that rotates one vector onto another vector.
|
||||
* @param fromVector The normalized vector to start from. This must be normalized!
|
||||
* @param toVector The normalized vector to rotate towards. This must be normalized as well!
|
||||
*/
|
||||
void SetAsDeltaRotation(const AZ::Vector3& fromVector, const AZ::Vector3& toVector);
|
||||
|
||||
/**
|
||||
* Init this quaternion as a delta rotation that rotates one vector onto another vector.
|
||||
* If the angle is bigger than the max allowed angle that is specified it will rotate with an angle of the maximum specified angle.
|
||||
* So if the angle between the vectors is 40 degrees and you maxAngleRadians equals 10 degrees (in radians) it will only rotate 10 degrees.
|
||||
* @param fromVector The normalized vector to start from. This must be normalized!
|
||||
* @param toVector The normalized vector to rotate towards. This must be normalized as well!
|
||||
* @param maxAngleRadians The maximum rotation angle on the plane defined by the two vectors. This cannot be more than Math::pi (180 degrees).
|
||||
*/
|
||||
void SetAsDeltaRotation(const AZ::Vector3& fromVector, const AZ::Vector3& toVector, float maxAngleRadians);
|
||||
|
||||
/**
|
||||
* Rotate this current quaternion using a given delta that is calculated from two vectors.
|
||||
* The rotation axis used is the cross product between the from and to vector. The rotation angle is the angle between these two vectors.
|
||||
* @param fromVector The current direction vector, must be normalized.
|
||||
* @param toVector The desired new direction vector, must be normalized.
|
||||
*/
|
||||
void RotateFromTo(const AZ::Vector3& fromVector, const AZ::Vector3& toVector);
|
||||
|
||||
/**
|
||||
* Decompose into swing and twist.
|
||||
* The original rotation quat can be reassembled by doing swing * twist.
|
||||
* @param direction The direction vector to get the twist from.
|
||||
* @param outSwing This will contain the swing quaternion.
|
||||
* @param outTwist This will contain the twist quaternion.
|
||||
*/
|
||||
void DecomposeSwingTwist(const AZ::Vector3& direction, Quaternion* outSwing, Quaternion* outTwist) const;
|
||||
|
||||
/**
|
||||
* Linear interpolate between this and another quaternion.
|
||||
* @param to The quaternion to interpolate towards.
|
||||
* @param t The time value, between 0 and 1.
|
||||
* @result The quaternion at the given time in the interpolation process.
|
||||
*/
|
||||
Quaternion Lerp(const Quaternion& to, float t) const;
|
||||
|
||||
/**
|
||||
* Linear interpolate between this and another quaternion, and normalize afterwards.
|
||||
* @param to The quaternion to interpolate towards.
|
||||
* @param t The time value, between 0 and 1.
|
||||
* @result The normalized quaternion at the given time in the interpolation process.
|
||||
*/
|
||||
Quaternion NLerp(const Quaternion& to, float t) const;
|
||||
|
||||
/**
|
||||
* Spherical Linear interpolate between this and another quaternion.
|
||||
* @param to The quaternion to interpolate towards.
|
||||
* @param t The time value, between 0 and 1.
|
||||
* @result The quaternion at the given time in the interpolation process.
|
||||
*/
|
||||
Quaternion Slerp(const Quaternion& to, float t) const;
|
||||
|
||||
/**
|
||||
* Spherical cubic interpolate.
|
||||
* @param p The first quaternion.
|
||||
* @param a The second quaternion.
|
||||
* @param b The third quaternion.
|
||||
* @param q The fourth quaternion.
|
||||
* @param t The time value, between 0 and 1.
|
||||
* @result The quaternion at the given time in the interpolation process.
|
||||
*/
|
||||
static Quaternion Squad(const Quaternion& p, const Quaternion& a, const Quaternion& b, const Quaternion& q, float t);
|
||||
|
||||
// operators
|
||||
MCORE_INLINE const Quaternion& operator=(const Matrix& m) { FromMatrix(m); return *this; }
|
||||
MCORE_INLINE const Quaternion& operator=(const Quaternion& other) { x = other.x; y = other.y; z = other.z; w = other.w; return *this; }
|
||||
MCORE_INLINE Quaternion operator-() const { return Quaternion(-x, -y, -z, -w); }
|
||||
MCORE_INLINE const Quaternion& operator+=(const Quaternion& q) { x += q.x; y += q.y; z += q.z; w += q.w; return *this; }
|
||||
MCORE_INLINE const Quaternion& operator-=(const Quaternion& q) { x -= q.x; y -= q.y; z -= q.z; w -= q.w; return *this; }
|
||||
MCORE_INLINE const Quaternion& operator*=(const Quaternion& q);
|
||||
MCORE_INLINE const Quaternion& operator*=(float f) { x *= f; y *= f; z *= f; w *= f; return *this; }
|
||||
//MCORE_INLINE const Quaternion& operator*=(double f) { x*=f; y*=f; z*=f; w*=f; return *this; }
|
||||
MCORE_INLINE bool operator==(const Quaternion& q) const { return ((q.x == x) && (q.y == y) && (q.z == z) && (q.w == w)); }
|
||||
MCORE_INLINE bool operator!=(const Quaternion& q) const { return ((q.x != x) || (q.y != y) || (q.z != z) || (q.w != w)); }
|
||||
|
||||
//MCORE_INLINE float& operator[](int32 row) { return ((float*)&x)[row]; }
|
||||
MCORE_INLINE operator float*() { return (float*)&x; }
|
||||
MCORE_INLINE operator const float*() const { return (const float*)&x; }
|
||||
|
||||
MCORE_INLINE AZ::Vector3 operator*(const AZ::Vector3& p) const; // multiply a vector by a quaternion
|
||||
MCORE_INLINE Quaternion operator/(const Quaternion& q) const; // returns the ratio of two quaternions
|
||||
|
||||
// attributes
|
||||
float x, y, z, w;
|
||||
};
|
||||
|
||||
|
||||
// operators
|
||||
MCORE_INLINE Quaternion operator*(const Quaternion& a, float f) { return Quaternion(a.x * f, a.y * f, a.z * f, a.w * f); }
|
||||
MCORE_INLINE Quaternion operator*(float f, const Quaternion& b) { return Quaternion(f * b.x, f * b.y, f * b.z, f * b.w); }
|
||||
//MCORE_INLINE Quaternion operator*(const Quaternion& a, double f) { return Quaternion(a.x*f, a.y*f, a.z*f, a.w*f); }
|
||||
//MCORE_INLINE Quaternion operator*(double f, const Quaternion& b) { return Quaternion(f*b.x, f*b.y, f*b.z, f*b.w); }
|
||||
MCORE_INLINE Quaternion operator+(const Quaternion& a, const Quaternion& b) { return Quaternion(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); }
|
||||
MCORE_INLINE Quaternion operator-(const Quaternion& a, const Quaternion& b) { return Quaternion(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); }
|
||||
MCORE_INLINE Quaternion operator*(const Quaternion& a, const Quaternion& b) { return Quaternion(a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y, a.w * b.y + a.y * b.w + a.z * b.x - a.x * b.z, a.w * b.z + a.z * b.w + a.x * b.y - a.y * b.x, a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z); }
|
||||
|
||||
// include the inline code
|
||||
#include "Quaternion.inl"
|
||||
} // namespace MCore
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
// multiply a vector by a quaternion
|
||||
MCORE_INLINE AZ::Vector3 Quaternion::operator * (const AZ::Vector3& p) const
|
||||
{
|
||||
Quaternion v(p.GetX(), p.GetY(), p.GetZ(), 0.0f);
|
||||
v = *this* v* this->Conjugated();
|
||||
return AZ::Vector3(v.x, v.y, v.z);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// returns the ratio of two quaternions
|
||||
MCORE_INLINE Quaternion Quaternion::operator / (const Quaternion& q) const
|
||||
{
|
||||
Quaternion t((*this) * -q);
|
||||
Quaternion s((-q) * (-q));
|
||||
t *= (1.0f / s.w);
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// calculates the length of the quaternion
|
||||
MCORE_INLINE float Quaternion::Length() const
|
||||
{
|
||||
const float sqLen = SquareLength();
|
||||
return Math::SafeSqrt(sqLen);
|
||||
}
|
||||
|
||||
|
||||
// normalizes the quaternion using approximation
|
||||
MCORE_INLINE Quaternion& Quaternion::Normalize()
|
||||
{
|
||||
// calculate 1.0 / length
|
||||
// const float ooLen = 1.0f / Math::FastSqrt(x*x + y*y + z*z + w*w);
|
||||
// const float ooLen = Math::FastInvSqrt(x*x + y*y + z*z + w*w);
|
||||
const float squareValue = x * x + y * y + z * z + w * w;
|
||||
const float ooLen = Math::InvSqrt(squareValue);
|
||||
|
||||
x *= ooLen;
|
||||
y *= ooLen;
|
||||
z *= ooLen;
|
||||
w *= ooLen;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// get the right axis
|
||||
MCORE_INLINE AZ::Vector3 Quaternion::CalcRightAxis() const
|
||||
{
|
||||
return AZ::Vector3(1.0f - 2.0f * y * y - 2.0f * z * z,
|
||||
2.0f * x * y + 2.0f * z * w,
|
||||
2.0f * x * z - 2.0f * y * w);
|
||||
}
|
||||
|
||||
|
||||
// get the forward axis
|
||||
MCORE_INLINE AZ::Vector3 Quaternion::CalcForwardAxis() const
|
||||
{
|
||||
return AZ::Vector3(2.0f * x * y - 2.0f * z * w,
|
||||
1.0f - 2.0f * x * x - 2.0f * z * z,
|
||||
2.0f * y * z + 2.0f * x * w);
|
||||
}
|
||||
|
||||
|
||||
// get the up axis
|
||||
MCORE_INLINE AZ::Vector3 Quaternion::CalcUpAxis() const
|
||||
{
|
||||
return AZ::Vector3(2.0f * x * z + 2.0f * y * w,
|
||||
2.0f * y * z - 2.0f * x * w,
|
||||
1.0f - 2.0f * x * x - 2.0f * y * y);
|
||||
}
|
||||
|
||||
|
||||
// multiply by a quaternion
|
||||
MCORE_INLINE const Quaternion& Quaternion::operator*=(const Quaternion& q)
|
||||
{
|
||||
const float vx = w * q.x + x * q.w + y * q.z - z * q.y;
|
||||
const float vy = w * q.y + y * q.w + z * q.x - x * q.z;
|
||||
const float vz = w * q.z + z * q.w + x * q.y - y * q.x;
|
||||
const float vw = w * q.w - x * q.x - y * q.y - z * q.z;
|
||||
x = vx;
|
||||
y = vy;
|
||||
z = vz;
|
||||
w = vw;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -107,9 +107,6 @@ set(FILES
|
||||
Source/PlaneEq.cpp
|
||||
Source/PlaneEq.h
|
||||
Source/PlaneEq.inl
|
||||
Source/Quaternion.cpp
|
||||
Source/Quaternion.h
|
||||
Source/Quaternion.inl
|
||||
Source/Random.cpp
|
||||
Source/Random.h
|
||||
Source/Ray.cpp
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <AzCore/Math/Matrix4x4.h>
|
||||
#include <AzCore/Math/MathUtils.h>
|
||||
|
||||
#include <MCore/Source/Quaternion.h>
|
||||
#include <MCore/Source/Vector.h>
|
||||
#include <MCore/Source/AzCoreConversions.h>
|
||||
|
||||
@@ -25,7 +24,6 @@ protected:
|
||||
{
|
||||
m_azNormalizedVector3_a = AZ::Vector3(s_x1, s_y1, s_z1);
|
||||
m_azNormalizedVector3_a.Normalize();
|
||||
m_emQuaternion_a = MCore::Quaternion(m_azNormalizedVector3_a, s_angle_a);
|
||||
m_azQuaternion_a = AZ::Quaternion::CreateFromAxisAngle(m_azNormalizedVector3_a, s_angle_a);
|
||||
}
|
||||
|
||||
@@ -55,26 +53,6 @@ protected:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EmfxQuaternionCompareExact(MCore::Quaternion& quaternion, float x, float y, float z, float w)
|
||||
{
|
||||
if (quaternion.x != x)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (quaternion.y != y)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (quaternion.z != z)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (quaternion.w != w)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AZQuaternionCompareClose(AZ::Quaternion& quaternion, float x, float y, float z, float w, float tolerance)
|
||||
{
|
||||
@@ -131,26 +109,6 @@ protected:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AZEMQuaternionsAreEqual(AZ::Quaternion& azQuaternion, const MCore::Quaternion& emQuaternion)
|
||||
{
|
||||
if (AZQuaternionCompareExact(azQuaternion, emQuaternion.x, emQuaternion.y,
|
||||
emQuaternion.z, emQuaternion.w))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AZEMQuaternionsAreClose(AZ::Quaternion& azQuaternion, const MCore::Quaternion& emQuaternion, const float tolerance)
|
||||
{
|
||||
if (AZQuaternionCompareClose(azQuaternion, emQuaternion.x, emQuaternion.y,
|
||||
emQuaternion.z, emQuaternion.w, tolerance))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const float s_toleranceHigh;
|
||||
static const float s_toleranceMedium;
|
||||
static const float s_toleranceLow;
|
||||
@@ -161,7 +119,6 @@ protected:
|
||||
static const float s_angle_a;
|
||||
AZ::Vector3 m_azNormalizedVector3_a;
|
||||
AZ::Quaternion m_azQuaternion_a;
|
||||
MCore::Quaternion m_emQuaternion_a;
|
||||
};
|
||||
|
||||
const float EmotionFXMathLibTests::s_toleranceHigh = 0.00001f;
|
||||
@@ -174,18 +131,6 @@ const float EmotionFXMathLibTests::s_y1 = 0.3f;
|
||||
const float EmotionFXMathLibTests::s_z1 = 0.4f;
|
||||
const float EmotionFXMathLibTests::s_angle_a = 0.5f;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// MCore::Quaternion: Test identity values
|
||||
TEST_F(EmotionFXMathLibTests, QuaternionIdentity_Identity_Success)
|
||||
{
|
||||
MCore::Quaternion test(0.1f, 0.2f, 0.3f, 0.4f);
|
||||
test.Identity();
|
||||
ASSERT_TRUE(test == MCore::Quaternion(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
//Getting and setting of Quaternions
|
||||
//////////////////////////////////////////////////////////////////
|
||||
@@ -196,52 +141,6 @@ TEST_F(EmotionFXMathLibTests, AZQuaternionGet_Elements_Success)
|
||||
ASSERT_TRUE(AZQuaternionCompareExact(test, 0.1f, 0.2f, 0.3f, 0.4f));
|
||||
}
|
||||
|
||||
// Compare equivalent normalized quaternions between systems
|
||||
TEST_F(EmotionFXMathLibTests, AZEMQuaternionNormalizeEquivalent_Success)
|
||||
{
|
||||
AZ::Quaternion azTest(0.1f, 0.2f, 0.3f, 0.4f);
|
||||
MCore::Quaternion emTest(0.1f, 0.2f, 0.3f, 0.4f);
|
||||
azTest.Normalize();
|
||||
emTest.Normalize();
|
||||
|
||||
ASSERT_TRUE(AZQuaternionCompareClose(azTest, emTest.x, emTest.y, emTest.z, emTest.w, s_toleranceMedium));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Axis Angle
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Compare setting a quaternion using axis and angle
|
||||
TEST_F(EmotionFXMathLibTests, AZEMQuaternionConversion_SetToAxisAngleEquivalent_Success)
|
||||
{
|
||||
MCore::Quaternion emQuaternion(m_azNormalizedVector3_a, s_angle_a);
|
||||
AZ::Quaternion azQuaternion = AZ::Quaternion::CreateFromAxisAngle(m_azNormalizedVector3_a, s_angle_a);
|
||||
|
||||
ASSERT_TRUE(AZQuaternionCompareClose(azQuaternion, emQuaternion.x, emQuaternion.y, emQuaternion.z, emQuaternion.w, s_toleranceLow));
|
||||
}
|
||||
|
||||
// Compare equivalent conversions quaternions -> (axis, angle) between systems
|
||||
TEST_F(EmotionFXMathLibTests, AZEMQuaternionConversion_ToAxisAngleEquivalent_Success)
|
||||
{
|
||||
//populate Quaternions with same data
|
||||
MCore::Quaternion emTest = m_emQuaternion_a;
|
||||
AZ::Quaternion azTest(emTest.x, emTest.y, emTest.z, emTest.w);
|
||||
|
||||
AZ::Vector3 emAxis;
|
||||
float emAngle;
|
||||
emTest.ToAxisAngle(&emAxis, &emAngle);
|
||||
|
||||
AZ::Vector3 azAxis;
|
||||
float azAngle;
|
||||
AZ::ConvertQuaternionToAxisAngle(azTest, azAxis, azAngle);
|
||||
|
||||
bool same = AZ::IsClose(azAngle, emAngle, s_toleranceLow) &&
|
||||
AZVector3CompareClose(azAxis, emAxis, s_toleranceLow);
|
||||
|
||||
ASSERT_TRUE(same);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//Basic rotations
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -420,18 +319,6 @@ TEST_F(EmotionFXMathLibTests, AZQuaternion_EulerGetSet3ComponentAxisCompareTrans
|
||||
ASSERT_TRUE(same);
|
||||
}
|
||||
|
||||
|
||||
// EM Quaternion to Euler test
|
||||
TEST_F(EmotionFXMathLibTests, EMQuaternionConversion_ToEulerEquivalent_Success)
|
||||
{
|
||||
AZ::Vector3 eulerIn(0.1f, 0.2f, 0.3f);
|
||||
MCore::Quaternion test;
|
||||
test.SetEuler(eulerIn.GetX(), eulerIn.GetY(), eulerIn.GetZ());
|
||||
AZ::Vector3 eulerOut = test.ToEuler();
|
||||
|
||||
ASSERT_TRUE(AZVector3CompareClose(eulerOut, 0.1f, 0.2f, 0.3f, s_toleranceHigh));
|
||||
}
|
||||
|
||||
// AZ Quaternion to Euler test
|
||||
//only way to test Quaternions sameness is to apply it to a vector and measure result
|
||||
TEST_F(EmotionFXMathLibTests, AZQuaternionConversion_ToEulerEquivalent_Success)
|
||||
@@ -456,41 +343,6 @@ TEST_F(EmotionFXMathLibTests, AZQuaternionConversion_ToEulerEquivalent_Success)
|
||||
ASSERT_TRUE(AZVector3CompareClose(eulerOut1, eulerOut2, s_toleranceReallyLow));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//Quaternion order test
|
||||
//determines that ordering is same between systems.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_F(EmotionFXMathLibTests, AZEMQuaternion_OrderTest_Success)
|
||||
{
|
||||
AZ::Vector3 axis = AZ::Vector3(1.0f, 0.7f, 0.3f);
|
||||
axis.Normalize();
|
||||
AZ::Quaternion azQuaternion1 = AZ::Quaternion::CreateFromAxisAngle(axis, AZ::Constants::HalfPi);
|
||||
|
||||
AZ::Vector3 axis2 = AZ::Vector3(0.2f, 0.5f, 0.9f);
|
||||
axis2.Normalize();
|
||||
AZ::Quaternion azQuaternion2 = AZ::Quaternion::CreateFromAxisAngle(axis2, AZ::Constants::HalfPi);
|
||||
|
||||
MCore::Quaternion emQuaternion1(azQuaternion1.GetX(), azQuaternion1.GetY(), azQuaternion1.GetZ(), azQuaternion1.GetW());
|
||||
MCore::Quaternion emQuaternion2(azQuaternion2.GetX(), azQuaternion2.GetY(), azQuaternion2.GetZ(), azQuaternion2.GetW());
|
||||
|
||||
AZ::Quaternion azQuaterionOut = azQuaternion1 * azQuaternion2;
|
||||
AZ::Quaternion azQuaterionOut2 = azQuaternion2 * azQuaternion1;
|
||||
MCore::Quaternion emQuaterionOut = emQuaternion1 * emQuaternion2;
|
||||
|
||||
AZ::Vector3 azVertexIn(0.1f, 0.2f, 0.3f);
|
||||
|
||||
AZ::Vector3 azVertexOut, azVertexOut2;
|
||||
AZ::Vector3 emVertexOut;
|
||||
|
||||
azVertexOut = azQuaterionOut.TransformVector(azVertexIn);
|
||||
azVertexOut2 = azQuaterionOut2.TransformVector(azVertexIn);
|
||||
emVertexOut = emQuaterionOut * azVertexIn;
|
||||
|
||||
bool same = AZVector3CompareClose(emVertexOut, azVertexOut.GetX(), azVertexOut.GetY(), azVertexOut.GetZ(), s_toleranceMedium);
|
||||
ASSERT_TRUE(same);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Quaternion Matrix
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -616,225 +468,6 @@ TEST_F(EmotionFXMathLibTests, AZQuaternionConversion_ToMatrix_Success)
|
||||
ASSERT_TRUE(AZ::IsClose(azMatrix.GetElement(3, 3), 1.0f, s_toleranceReallyLow));
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// AZEMQuaternion Compare Output tests
|
||||
// Determines the AZ and MCore quaternion outputs are same/close after same math operations.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
TEST_F(EmotionFXMathLibTests, AZEMQuaternion_CompareOperatorAddEquivalent_Success)
|
||||
{
|
||||
// Quaternion test: operator '+' and operator '+='
|
||||
AZ::Quaternion azQuaternion = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f);
|
||||
AZ::Quaternion azQuaternion2 = AZ::Quaternion(0.8f, 0.7f, 0.6f, 1.0f);
|
||||
azQuaternion.Normalize();
|
||||
azQuaternion2.Normalize();
|
||||
azQuaternion = azQuaternion + azQuaternion2;
|
||||
azQuaternion2 += azQuaternion;
|
||||
|
||||
MCore::Quaternion emQuaternion = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f);
|
||||
MCore::Quaternion emQuaternion2 = MCore::Quaternion(0.8f, 0.7f, 0.6f, 1.0f);
|
||||
emQuaternion.Normalize();
|
||||
emQuaternion2.Normalize();
|
||||
emQuaternion = emQuaternion + emQuaternion2;
|
||||
emQuaternion2 += emQuaternion;
|
||||
|
||||
EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternion, emQuaternion, s_toleranceLow)) << "AZ/MCore Quaternions should have similar output with operator '+'";
|
||||
EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternion2, emQuaternion2, s_toleranceLow)) << "AZ/MCore Quaternions should have similar output with operator '+='";
|
||||
}
|
||||
|
||||
TEST_F(EmotionFXMathLibTests, AZEMQuaternion_CompareOperatorSubtractEquivalent_Success)
|
||||
{
|
||||
// Quaternion test: operator '-' and operator '-='
|
||||
AZ::Quaternion azQuaternion = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f);
|
||||
AZ::Quaternion azQuaternion2 = AZ::Quaternion(0.8f, 0.7f, 0.6f, 1.0f);
|
||||
azQuaternion.Normalize();
|
||||
azQuaternion2.Normalize();
|
||||
azQuaternion = azQuaternion - azQuaternion2;
|
||||
azQuaternion2 -= azQuaternion;
|
||||
|
||||
MCore::Quaternion emQuaternion = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f);
|
||||
MCore::Quaternion emQuaternion2 = MCore::Quaternion(0.8f, 0.7f, 0.6f, 1.0f);
|
||||
emQuaternion.Normalize();
|
||||
emQuaternion2.Normalize();
|
||||
emQuaternion = emQuaternion - emQuaternion2;
|
||||
emQuaternion2 -= emQuaternion;
|
||||
|
||||
EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternion, emQuaternion, s_toleranceLow)) << "AZ/MCore Quaternions should have similar output with operator '-'";
|
||||
EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternion2, emQuaternion2, s_toleranceLow)) << "AZ/MCore Quaternions should have similar output with operator '-='";
|
||||
}
|
||||
|
||||
TEST_F(EmotionFXMathLibTests, AZEMQuaternion_CompareOperatorMultiplyHasSimilarOutput_Success)
|
||||
{
|
||||
// Quaternion test: operator '*' and operator '*=' with another quaternion, vector3 and float
|
||||
AZ::Quaternion azQuaternion = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f);
|
||||
AZ::Quaternion azQuaternion2 = AZ::Quaternion(0.8f, 0.7f, 0.6f, 1.0f);
|
||||
AZ::Quaternion azQuaternion3 = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f);
|
||||
azQuaternion.Normalize();
|
||||
azQuaternion2.Normalize();
|
||||
azQuaternion3.Normalize();
|
||||
azQuaternion = azQuaternion * azQuaternion2;
|
||||
azQuaternion2 *= azQuaternion;
|
||||
azQuaternion3 *= 0.5f;
|
||||
AZ::Vector3 aztestVec3 = azQuaternion2.TransformVector(m_azNormalizedVector3_a);
|
||||
|
||||
MCore::Quaternion emQuaternion = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f);
|
||||
MCore::Quaternion emQuaternion2 = MCore::Quaternion(0.8f, 0.7f, 0.6f, 1.0f);
|
||||
MCore::Quaternion emQuaternion3 = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f);
|
||||
emQuaternion.Normalize();
|
||||
emQuaternion2.Normalize();
|
||||
emQuaternion3.Normalize();
|
||||
emQuaternion = emQuaternion * emQuaternion2;
|
||||
emQuaternion2 *= emQuaternion;
|
||||
emQuaternion3 *= 0.5f;
|
||||
AZ::Vector3 emtestVec3 = emQuaternion2 * m_azNormalizedVector3_a;
|
||||
|
||||
EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternion, emQuaternion, s_toleranceLow)) << "AZ/MCore Quaternions should have similar output with operator '*' with another quaternion";
|
||||
EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternion2, emQuaternion2, s_toleranceLow)) << "AZ/MCore Quaternions should have similar output with operator '*=' with another quaternion";
|
||||
EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternion3, emQuaternion3, s_toleranceLow)) << "AZ/MCore Quaternions should have similar output with operator '*=' with a float value";
|
||||
EXPECT_TRUE(AZVector3CompareClose(aztestVec3, emtestVec3, s_toleranceLow)) << "AZ/MCore Quaternions should have similar output with operator '*' with a vector3";
|
||||
}
|
||||
|
||||
TEST_F(EmotionFXMathLibTests, AZEMQuaternion_EquivalentOperatorsHasSameOutput_Success)
|
||||
{
|
||||
// Testing Quaternion == Quaternion and operator!=
|
||||
bool azCheck = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized() == AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized();
|
||||
bool azCheck2 = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized() == AZ::Quaternion(0.1000001f, 0.2000001f, 0.3000001f, 1.0f).GetNormalized();
|
||||
bool azCheck3 = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized() != AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized();
|
||||
bool azCheck4 = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized() != AZ::Quaternion(0.1000001f, 0.2000001f, 0.3000001f, 1.0f).GetNormalized();
|
||||
|
||||
bool emCheck = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized() == MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized();
|
||||
bool emCheck2 = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized() == MCore::Quaternion(0.1000001f, 0.2000001f, 0.3000001f, 1.0f).Normalized();
|
||||
bool emCheck3 = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized() != MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized();
|
||||
bool emCheck4 = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized() != MCore::Quaternion(0.1000001f, 0.2000001f, 0.3000001f, 1.0f).Normalized();
|
||||
|
||||
EXPECT_TRUE(azCheck == emCheck) << "AZ/MCore Quaternions should have same output of 'true' with operator '=='";
|
||||
EXPECT_TRUE(azCheck2 == emCheck2) << "AZ/MCore Quaternions should have same output of 'false' with operator '=='";
|
||||
EXPECT_TRUE(azCheck3 == emCheck3) << "AZ/MCore Quaternions should have same output of 'false' with operator '!='";
|
||||
EXPECT_TRUE(azCheck4 == emCheck4) << "AZ/MCore Quaternions should have same output of 'true' with operator '!='";
|
||||
}
|
||||
|
||||
TEST_F(EmotionFXMathLibTests, AZEMQuaternion_InverseHasSimilarOutput_Success)
|
||||
{
|
||||
// Test quaternions inverse method
|
||||
AZ::Quaternion azQuaternion = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized().GetInverseFull();
|
||||
AZ::Quaternion azQuaternion2 = AZ::Quaternion(0.0f, 0.0f, 0.0f, 1.0f).GetNormalized().GetInverseFull();
|
||||
|
||||
MCore::Quaternion emQuaternion = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized().Inverse();
|
||||
MCore::Quaternion emQuaternion2 = MCore::Quaternion(0.0f, 0.0f, 0.0f, 1.0f).Normalized().Inverse();
|
||||
|
||||
EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternion, emQuaternion, s_toleranceLow)) << "AZ/MCore Quaternions should have similar Inverse output";
|
||||
EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternion2, emQuaternion2, s_toleranceLow)) << "AZ/MCore Quaternion(0.0f, 0.0f, 0.0f, 1.0f) should have similar Inverse output";
|
||||
}
|
||||
|
||||
TEST_F(EmotionFXMathLibTests, AZEMQuaternion_ConjugateHasSimilarOutput_Success)
|
||||
{
|
||||
// Test quaternion conjugate method
|
||||
AZ::Quaternion azQuaternion = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized().GetConjugate();
|
||||
AZ::Quaternion azQuaternion2 = AZ::Quaternion(0.0f, 0.0f, 0.0f, 1.0f).GetNormalized().GetConjugate();
|
||||
|
||||
MCore::Quaternion emQuaternion = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized().Conjugate();
|
||||
MCore::Quaternion emQuaternion2 = MCore::Quaternion(0.0f, 0.0f, 0.0f, 1.0f).Normalized().Conjugate();
|
||||
|
||||
EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternion, emQuaternion, s_toleranceLow)) << "AZ/MCore Quaternions should have similar Conjugate output";
|
||||
EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternion2, emQuaternion2, s_toleranceLow)) << "AZ/MCore Quaternion(0.0f, 0.0f, 0.0f, 1.0f) should have similar Conjugate output";
|
||||
}
|
||||
|
||||
TEST_F(EmotionFXMathLibTests, AZEMQuaternion_HasSameSquareLengthOutput_Success)
|
||||
{
|
||||
// Test AZ and MCore quaternions to have similar square length
|
||||
float azTest = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized().GetLengthSq();
|
||||
float azTest2 = AZ::Quaternion(0.0f, 0.0f, 0.0f, 1.0f).GetNormalized().GetLengthSq();
|
||||
|
||||
float emTest = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized().SquareLength();
|
||||
float emTest2 = MCore::Quaternion(0.0f, 0.0f, 0.0f, 1.0f).Normalized().SquareLength();
|
||||
|
||||
EXPECT_TRUE(AZ::GetAbs(azTest - emTest) < s_toleranceLow) << "AZ/MCore Quaternions should have similar square length output";
|
||||
EXPECT_TRUE(AZ::GetAbs(azTest2 - emTest2) < s_toleranceLow) << "AZ/MCore Quaternion(0.0f, 0.0f, 0.0f, 1.0f) should have similar square length output";
|
||||
}
|
||||
|
||||
TEST_F(EmotionFXMathLibTests, AZEMQuaternion_HasSameLengthOutput_Success)
|
||||
{
|
||||
// Test AZ and MCore quaternions to have similar length
|
||||
// AZ GetLength, GetLengthApprox, GetLength all returns sqrtf(Dot(*this))
|
||||
float azTest = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized().GetLength();
|
||||
float azTest2 = AZ::Quaternion(0.0f, 0.0f, 0.0f, 1.0f).GetNormalized().GetLength();
|
||||
|
||||
float emTest = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized().Length();
|
||||
float emTest2 = MCore::Quaternion(0.0f, 0.0f, 0.0f, 1.0f).Normalized().Length();
|
||||
|
||||
EXPECT_TRUE(AZ::GetAbs(azTest - emTest) < s_toleranceLow) << "AZ/MCore Quaternions should have similar length output";
|
||||
EXPECT_TRUE(AZ::GetAbs(azTest2 - emTest2) < s_toleranceLow) << "AZ/MCore Quaternion(0.0f, 0.0f, 0.0f, 1.0f) should have similar length output";
|
||||
}
|
||||
|
||||
TEST_F(EmotionFXMathLibTests, AZEMQuaternion_HasSameDotProductOutput_Success)
|
||||
{
|
||||
// Test AZ and MCore quaternions to have similar dot product
|
||||
float azDotTest = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized().Dot(AZ::Quaternion(0.8f, 0.7f, 0.6f, 1.0f));
|
||||
float azDotTest2 = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized().Dot(AZ::Quaternion(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
float azDotTest3 = AZ::Quaternion(0.0f, 0.0f, 0.0f, 1.0f).GetNormalized().Dot(AZ::Quaternion(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
|
||||
float emDotTest = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized().Dot(MCore::Quaternion(0.8f, 0.7f, 0.6f, 1.0f));
|
||||
float emDotTest2 = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized().Dot(MCore::Quaternion(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
float emDotTest3 = MCore::Quaternion(0.0f, 0.0f, 0.0f, 1.0f).Normalized().Dot(MCore::Quaternion(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
|
||||
EXPECT_TRUE(AZ::GetAbs(azDotTest - emDotTest) < s_toleranceLow) << "AZ/MCore Quaternions should have similar dot product output";
|
||||
EXPECT_TRUE(AZ::GetAbs(azDotTest2 - emDotTest2) < s_toleranceLow) << "AZ/MCore Quaternions should have similar dot product output";
|
||||
EXPECT_TRUE(AZ::GetAbs(azDotTest3 - emDotTest3) < s_toleranceLow) << "AZ/MCore Quaternion(0.0f, 0.0f, 0.0f, 1.0f) should have similar dot product output";
|
||||
}
|
||||
|
||||
TEST_F(EmotionFXMathLibTests, AZEMQuaternion_HasSimilarLerpOutput_Success)
|
||||
{
|
||||
// Test AZ and MCore quaternions to have similar Linear Interpolated quaternions
|
||||
float testCases[6] = { 0.0f, 0.1f, 0.25f, 0.5f, 0.8f, 1.0f };
|
||||
for (float testVal : testCases)
|
||||
{
|
||||
AZ::Quaternion azQuaternionA = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized();
|
||||
AZ::Quaternion azQuaternionB = AZ::Quaternion(0.8f, 0.7f, 0.6f, 1.0f).GetNormalized();
|
||||
AZ::Quaternion azQuaternionC = azQuaternionA.Lerp(azQuaternionB, testVal);
|
||||
|
||||
MCore::Quaternion emQuaternionA = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized();
|
||||
MCore::Quaternion emQuaternionB = MCore::Quaternion(0.8f, 0.7f, 0.6f, 1.0f).Normalized();
|
||||
MCore::Quaternion emQuaternionC = emQuaternionA.Lerp(emQuaternionB, testVal);
|
||||
|
||||
EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternionA, emQuaternionA, s_toleranceLow)) << "AZ/MCore Quaternions should have similar Lerp output with given float: " << testVal;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(EmotionFXMathLibTests, AZEMQuaternion_HasSimilarNLerpOutput_Success)
|
||||
{
|
||||
// Test AZ and MCore quaternions to have similar Linear Interpolated and then normalized quaternions
|
||||
float testCases[6] = {0.0f, 0.1f, 0.25f, 0.5f, 0.8f, 1.0f};
|
||||
for (float testVal : testCases)
|
||||
{
|
||||
AZ::Quaternion azQuaternionA = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized();
|
||||
AZ::Quaternion azQuaternionB = AZ::Quaternion(0.8f, 0.7f, 0.6f, 1.0f).GetNormalized();
|
||||
AZ::Quaternion azQuaternionC = azQuaternionA.NLerp(azQuaternionB, testVal);
|
||||
|
||||
MCore::Quaternion emQuaternionA = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized();
|
||||
MCore::Quaternion emQuaternionB = MCore::Quaternion(0.8f, 0.7f, 0.6f, 1.0f).Normalized();
|
||||
MCore::Quaternion emQuaternionC = emQuaternionA.NLerp(emQuaternionB, testVal);
|
||||
|
||||
EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternionA, emQuaternionA, s_toleranceLow)) << "AZ/MCore Quaternions should have similar NLerp output with given float: " << testVal;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(EmotionFXMathLibTests, AZEMQuaternion_HasSimilarSLerpOutput_Success)
|
||||
{
|
||||
// Test AZ and MCore quaternions to have similar spherical Linear Interpolated quaternions
|
||||
float testCases[6] = { 0.0f, 0.1f, 0.25f, 0.5f, 0.8f, 1.0f };
|
||||
for (float testVal : testCases)
|
||||
{
|
||||
AZ::Quaternion azQuaternionA = AZ::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).GetNormalized();
|
||||
AZ::Quaternion azQuaternionB = AZ::Quaternion(0.8f, 0.7f, 0.6f, 1.0f).GetNormalized();
|
||||
AZ::Quaternion azQuaternionC = azQuaternionA.Slerp(azQuaternionB, testVal);
|
||||
|
||||
MCore::Quaternion emQuaternionA = MCore::Quaternion(0.1f, 0.2f, 0.3f, 1.0f).Normalized();
|
||||
MCore::Quaternion emQuaternionB = MCore::Quaternion(0.8f, 0.7f, 0.6f, 1.0f).Normalized();
|
||||
MCore::Quaternion emQuaternionC = emQuaternionA.Slerp(emQuaternionB, testVal);
|
||||
|
||||
EXPECT_TRUE(AZEMQuaternionsAreClose(azQuaternionA, emQuaternionA, s_toleranceLow)) << "AZ/MCore Quaternions should have similar Slerp output with given float: " << testVal;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Skinning
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
#include <AzCore/Math/Quaternion.h>
|
||||
#include <EMotionFX/Source/EMotionFXConfig.h>
|
||||
#include <EMotionFX/Source/Transform.h>
|
||||
#include <MCore/Source/Quaternion.h>
|
||||
#include <MCore/Source/Compare.h>
|
||||
#include <MCore/Source/Matrix4.h>
|
||||
#include <Tests/Printers.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
|
||||
@@ -76,37 +76,6 @@ inline bool IsCloseMatcherP<AZ::Quaternion>::gmock_Impl<const AZ::Quaternion&>::
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
template<>
|
||||
inline bool IsCloseMatcherP<MCore::Quaternion>::gmock_Impl<const MCore::Quaternion&>::MatchAndExplain(const MCore::Quaternion& arg, ::testing::MatchResultListener* result_listener) const
|
||||
{
|
||||
const MCore::Quaternion compareQuat = (expected.Dot(arg) < 0.0f) ? -arg : arg;
|
||||
const AZ::Vector4 compareVec4(compareQuat.x, compareQuat.y, compareQuat.z, compareQuat.w);
|
||||
|
||||
if (::testing::ExplainMatchResult(IsClose(AZ::Vector4(expected.x, expected.y, expected.z, expected.w)), compareVec4, result_listener))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
AZ::Vector3 gotAxis;
|
||||
AZ::Vector3 expectedAxis;
|
||||
float gotAngle;
|
||||
float expectedAngle;
|
||||
|
||||
// convert to an axis and angle representation
|
||||
expected.ToAxisAngle(&expectedAxis, &expectedAngle);
|
||||
compareQuat.ToAxisAngle(&gotAxis, &gotAngle);
|
||||
|
||||
*result_listener << "\n Got Axis: ";
|
||||
PrintTo(gotAxis, result_listener->stream());
|
||||
*result_listener << ", Got Angle: " << gotAngle << "\n";
|
||||
*result_listener << "Expected Axis: ";
|
||||
PrintTo(expectedAxis, result_listener->stream());
|
||||
*result_listener << ", Expected Angle: " << expectedAngle;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
template<>
|
||||
inline bool IsCloseMatcherP<EMotionFX::Transform>::gmock_Impl<const EMotionFX::Transform&>::MatchAndExplain(const EMotionFX::Transform& arg, ::testing::MatchResultListener* result_listener) const
|
||||
|
||||
@@ -34,18 +34,6 @@ namespace AZStd
|
||||
}
|
||||
} // namespace AZStd
|
||||
|
||||
namespace MCore
|
||||
{
|
||||
void PrintTo(const Quaternion& quaternion, ::std::ostream* os)
|
||||
{
|
||||
*os << "(x: " << quaternion.x
|
||||
<< ", y: " << quaternion.y
|
||||
<< ", z: " << quaternion.z
|
||||
<< ", w: " << quaternion.w
|
||||
<< ")";
|
||||
}
|
||||
} // namespace MCore
|
||||
|
||||
namespace EMotionFX
|
||||
{
|
||||
void PrintTo(const Transform& transform, ::std::ostream* os)
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/Math/Quaternion.h>
|
||||
#include <MCore/Source/Quaternion.h>
|
||||
#include <EMotionFX/Source/Transform.h>
|
||||
|
||||
namespace AZ
|
||||
@@ -25,11 +24,6 @@ namespace AZStd
|
||||
void PrintTo(const string& string, ::std::ostream* os);
|
||||
} // namespace AZStd
|
||||
|
||||
namespace MCore
|
||||
{
|
||||
void PrintTo(const Quaternion& quaternion, ::std::ostream* os);
|
||||
} // namespace MCore
|
||||
|
||||
namespace EMotionFX
|
||||
{
|
||||
void PrintTo(const Transform& transform, ::std::ostream* os);
|
||||
|
||||
Reference in New Issue
Block a user