204 lines
8.2 KiB
C++
204 lines
8.2 KiB
C++
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
|
|
|
#include "Engine/Core/Math/Matrix.h"
|
|
#include "Engine/Core/Math/Packed.h"
|
|
#include "Engine/Core/Math/Vector3.h"
|
|
#include "Engine/Core/Math/Vector4.h"
|
|
#include "Engine/Core/Math/Quaternion.h"
|
|
#include "Engine/Core/Math/Transform.h"
|
|
#include "Engine/Core/RandomStream.h"
|
|
#include <ThirdParty/catch2/catch.hpp>
|
|
|
|
static Quaternion RotationX(float angle)
|
|
{
|
|
const float halfAngle = angle * 0.5f;
|
|
return Quaternion(Math::Sin(halfAngle), 0.0f, 0.0f, Math::Cos(halfAngle));
|
|
}
|
|
|
|
TEST_CASE("FloatR10G10B10A2")
|
|
{
|
|
SECTION("Test Conversion")
|
|
{
|
|
CHECK(Vector4::NearEqual(Vector4::Zero, FloatR10G10B10A2(Vector4::Zero).ToVector4()));
|
|
CHECK(Vector4::NearEqual(Vector4::One, FloatR10G10B10A2(Vector4::One).ToVector4()));
|
|
CHECK(Vector4::NearEqual(Vector4(0.5004888f, 0.5004888f, 0.5004888f, 0.666667f), FloatR10G10B10A2(Vector4(0.5f)).ToVector4()));
|
|
CHECK(Vector4::NearEqual(Vector4(1, 0, 0, 0), FloatR10G10B10A2(Vector4(1, 0, 0, 0)).ToVector4()));
|
|
CHECK(Vector4::NearEqual(Vector4(0, 1, 0, 0), FloatR10G10B10A2(Vector4(0, 1, 0, 0)).ToVector4()));
|
|
CHECK(Vector4::NearEqual(Vector4(0, 0, 1, 0), FloatR10G10B10A2(Vector4(0, 0, 1, 0)).ToVector4()));
|
|
CHECK(Vector4::NearEqual(Vector4(0, 0, 0, 1), FloatR10G10B10A2(Vector4(0, 0, 0, 1)).ToVector4()));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("FloatR11G11B10")
|
|
{
|
|
SECTION("Test Conversion")
|
|
{
|
|
CHECK(Vector3::NearEqual(Vector3::Zero, FloatR11G11B10(Vector3::Zero).ToVector3()));
|
|
CHECK(Vector3::NearEqual(Vector3::One, FloatR11G11B10(Vector3::One).ToVector3()));
|
|
CHECK(Vector3::NearEqual(Vector3(0.5f, 0.5f, 0.5f), FloatR11G11B10(Vector3(0.5f)).ToVector3()));
|
|
CHECK(Vector3::NearEqual(Vector3(1, 0, 0), FloatR11G11B10(Vector3(1, 0, 0)).ToVector3()));
|
|
CHECK(Vector3::NearEqual(Vector3(0, 1, 0), FloatR11G11B10(Vector3(0, 1, 0)).ToVector3()));
|
|
CHECK(Vector3::NearEqual(Vector3(0, 0, 1), FloatR11G11B10(Vector3(0, 0, 1)).ToVector3()));
|
|
CHECK(Vector3::NearEqual(Vector3(10, 11, 12), FloatR11G11B10(Vector3(10, 11, 12)).ToVector3()));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Quaternion")
|
|
{
|
|
SECTION("Test Euler")
|
|
{
|
|
CHECK(Quaternion::NearEqual(Quaternion::Euler(90, 0, 0), Quaternion(0.7071068f, 0, 0, 0.7071068f)));
|
|
CHECK(Quaternion::NearEqual(Quaternion::Euler(25, 0, 10), Quaternion(0.215616f, -0.018864f, 0.0850898f, 0.9725809f)));
|
|
CHECK(Vector3::NearEqual(Vector3(25, 0, 10), Quaternion::Euler(25, 0, 10).GetEuler()));
|
|
CHECK(Vector3::NearEqual(Vector3(25, -5, 10), Quaternion::Euler(25, -5, 10).GetEuler()));
|
|
}
|
|
SECTION("Test Multiply")
|
|
{
|
|
auto q = Quaternion::Identity;
|
|
auto delta = Quaternion::Euler(0, 10, 0);
|
|
for (int i = 0; i < 9; i++)
|
|
q *= delta;
|
|
CHECK(Quaternion::NearEqual(Quaternion::Euler(0, 90, 0), q, 0.00001f));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("Transform")
|
|
{
|
|
SECTION("Test World Matrix")
|
|
{
|
|
Transform t1(Vector3(10, 1, 10), Quaternion::Euler(45, 0, -15), Vector3(1.5f, 0.5f, 0.1f));
|
|
|
|
Matrix a1 = t1.GetWorld();
|
|
|
|
Matrix a2;
|
|
{
|
|
Matrix m1, m2;
|
|
Matrix::Scaling(t1.Scale, a2);
|
|
Matrix::RotationQuaternion(t1.Orientation, m2);
|
|
Matrix::Multiply(a2, m2, m1);
|
|
Matrix::Translation(t1.Translation, m2);
|
|
Matrix::Multiply(m1, m2, a2);
|
|
}
|
|
|
|
Matrix a3;
|
|
Matrix::Transformation(t1.Scale, t1.Orientation, t1.Translation, a3);
|
|
|
|
CHECK(a1 == a2);
|
|
CHECK(a1 == a3);
|
|
}
|
|
SECTION("Test Local To World")
|
|
{
|
|
Transform t1(Vector3(10, 1, 10), Quaternion::Euler(45, 0, -15), Vector3(1.5f, 0.5f, 0.1f));
|
|
Transform t2(Vector3(0, 20, 0), Quaternion::Euler(0, 0, 15), Vector3(1.0f, 2.0f, 1.0f));
|
|
|
|
Transform a1 = t1.LocalToWorld(t2);
|
|
Vector3 a2 = t1.LocalToWorld(t2.Translation);
|
|
|
|
Vector3 a3;
|
|
{
|
|
Vector3 result;
|
|
Matrix scale, rotation, scaleRotation;
|
|
Matrix::Scaling(t1.Scale, scale);
|
|
Matrix::RotationQuaternion(t1.Orientation, rotation);
|
|
Matrix::Multiply(scale, rotation, scaleRotation);
|
|
Vector3::Transform(t2.Translation, scaleRotation, result);
|
|
a3 = result + t1.Translation;
|
|
}
|
|
|
|
Vector3 a4T[1];
|
|
Vector3 a4Ta[1] = { t2.Translation };
|
|
for (int32 i = 0; i < ARRAY_COUNT(a4Ta); i++)
|
|
a4T[i] = t1.LocalToWorld(a4Ta[i]);
|
|
Vector3 a4 = a4T[0];
|
|
|
|
CHECK(Vector3::NearEqual(a1.Translation, a2));
|
|
CHECK(Vector3::NearEqual(a2, a3));
|
|
CHECK(Vector3::NearEqual(a2, a4));
|
|
}
|
|
SECTION("Test World To Local")
|
|
{
|
|
Transform t1 = Transform(Vector3(10, 1, 10), Quaternion::Euler(45, 0, -15), Vector3(1.5f, 0.5f, 0.1f));
|
|
Transform t2 = Transform(Vector3(0, 20, 0), Quaternion::Euler(0, 0, 15), Vector3(1.0f, 2.0f, 1.0f));
|
|
|
|
Transform a1 = t1.WorldToLocal(t2);
|
|
Vector3 a2 = t1.WorldToLocal(t2.Translation);
|
|
|
|
Vector3 a3;
|
|
{
|
|
Matrix scale, rotation, scaleRotation;
|
|
Matrix::Scaling(t1.Scale, scale);
|
|
Matrix::RotationQuaternion(t1.Orientation, rotation);
|
|
Matrix::Multiply(scale, rotation, scaleRotation);
|
|
Matrix::Invert(scaleRotation, scale);
|
|
a3 = t2.Translation - t1.Translation;
|
|
Vector3::Transform(a3, scale, a3);
|
|
}
|
|
|
|
Vector3 a4T[1];
|
|
Vector3 a4Ta[1] = { t2.Translation };
|
|
for (int32 i = 0; i < ARRAY_COUNT(a4Ta); i++)
|
|
a4T[i] = t1.WorldToLocal(a4Ta[i]);
|
|
Vector3 a4 = a4T[0];
|
|
|
|
CHECK(Vector3::NearEqual(a1.Translation, a2));
|
|
CHECK(Vector3::NearEqual(a2, a3, 0.0001f));
|
|
CHECK(Vector3::NearEqual(a2, a4));
|
|
}
|
|
SECTION("Test World Local Space")
|
|
{
|
|
Transform trans = Transform(Vector3(1, 2, 3));
|
|
|
|
CHECK(Vector3::NearEqual(Vector3(1, 2, 3), trans.LocalToWorld(Vector3(0, 0, 0))));
|
|
CHECK(Vector3::NearEqual(Vector3(4, 4, 4), trans.LocalToWorld(Vector3(3, 2, 1))));
|
|
CHECK(Vector3::NearEqual(Vector3(-1, -2, -3), trans.WorldToLocal(Vector3(0, 0, 0))));
|
|
CHECK(Vector3::NearEqual(Vector3(0, 0, 0), trans.WorldToLocal(Vector3(1, 2, 3))));
|
|
|
|
trans = Transform(Vector3::Zero, Quaternion::Euler(0, 90, 0));
|
|
CHECK(Vector3::NearEqual(Vector3(0, 2, -1), trans.LocalToWorld(Vector3(1, 2, 0))));
|
|
|
|
trans.Translation = Vector3(1, 0, 0);
|
|
trans.Orientation = RotationX(PI * 0.5f);
|
|
trans.Scale = Vector3(2, 2, 2);
|
|
CHECK(Vector3::NearEqual(Vector3(1, 0, 2), trans.LocalToWorld(Vector3(0, 1, 0))));
|
|
|
|
Transform t1 = trans.LocalToWorld(Transform::Identity);
|
|
CHECK(Vector3::NearEqual(Vector3(1.0f, 0, 0), t1.Translation));
|
|
CHECK(Quaternion::NearEqual(RotationX(PI * 0.5f), t1.Orientation));
|
|
CHECK(Vector3::NearEqual(Vector3(2.0f, 2.0f, 2.0f), t1.Scale));
|
|
|
|
Transform t2 = trans.WorldToLocal(Transform::Identity);
|
|
CHECK(Vector3::NearEqual(Vector3(-0.5f, 0, 0), t2.Translation));
|
|
CHECK(Quaternion::NearEqual(RotationX(PI * -0.5f), t2.Orientation));
|
|
CHECK(Vector3::NearEqual(Vector3(0.5f, 0.5f, 0.5f), t2.Scale));
|
|
|
|
RandomStream rand(10);
|
|
for (int32 i = 0; i < 10; i++)
|
|
{
|
|
Transform a = Transform(rand.GetVector3(), Quaternion::Euler((float)i * 10, 0, (float)i), rand.GetVector3() * 10.0f);
|
|
Transform b = Transform(rand.GetVector3(), Quaternion::Euler((float)i, 1, 22), rand.GetVector3() * 0.3f);
|
|
|
|
Transform ab = a.LocalToWorld(b);
|
|
Transform ba = a.WorldToLocal(ab);
|
|
|
|
CHECK(Transform::NearEqual(b, ba, 0.00001f));
|
|
}
|
|
}
|
|
SECTION("Test Add Subtract")
|
|
{
|
|
RandomStream rand(10);
|
|
for (int32 i = 0; i < 10; i++)
|
|
{
|
|
Transform a = Transform(rand.GetVector3(), Quaternion::Euler((float)i * 10, 0, (float)i), rand.GetVector3() * 10.0f);
|
|
Transform b = Transform(rand.GetVector3(), Quaternion::Euler((float)i, 1, 22), rand.GetVector3() * 0.3f);
|
|
|
|
Transform ab = a + b;
|
|
Transform newA = ab - b;
|
|
CHECK(Transform::NearEqual(a, newA, 0.00001f));
|
|
|
|
Transform ba = b + a;
|
|
Transform newB = ba - a;
|
|
CHECK(Transform::NearEqual(b, newB, 0.00001f));
|
|
}
|
|
}
|
|
}
|