You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
186 lines
7.0 KiB
C++
186 lines
7.0 KiB
C++
/*
|
|
* 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 <AzCore/UnitTest/TestTypes.h>
|
|
#include <AzCore/Math/Transform.h>
|
|
#include <AzFramework/Viewport/CameraState.h>
|
|
#include <AZTestShared/Math/MathTestHelpers.h>
|
|
#include <AzCore/Math/SimdMath.h>
|
|
#include <AzCore/Math/MatrixUtils.h>
|
|
#include <AzCore/Math/Matrix4x4.h>
|
|
|
|
namespace UnitTest
|
|
{
|
|
class CameraStateFixture
|
|
: public ::testing::Test
|
|
{
|
|
public:
|
|
void SetUp() override
|
|
{
|
|
m_cameraState = AzFramework::CreateDefaultCamera(AZ::Transform::CreateIdentity(), AZ::Vector2(1024, 768));
|
|
}
|
|
|
|
AzFramework::CameraState m_cameraState;
|
|
};
|
|
|
|
class Translation
|
|
: public CameraStateFixture
|
|
, public ::testing::WithParamInterface<AZStd::tuple<float, float, float>>
|
|
{
|
|
};
|
|
|
|
class Rotation
|
|
: public CameraStateFixture
|
|
, public ::testing::WithParamInterface<AZStd::tuple<float, float, float>>
|
|
{
|
|
};
|
|
|
|
class WorldFromViewMatrix
|
|
: public CameraStateFixture
|
|
, public ::testing::WithParamInterface<AZStd::tuple<AZ::Vector3, AZ::Vector3, AZ::Vector2>>
|
|
{
|
|
};
|
|
|
|
class PerspectiveMatrix
|
|
: public CameraStateFixture
|
|
, public ::testing::WithParamInterface<AZStd::tuple<float, float, float, float>>
|
|
{
|
|
};
|
|
|
|
TEST_P(Translation, Permutation)
|
|
{
|
|
// Given a position
|
|
const auto [x, y, z] = GetParam();
|
|
const AZ::Vector3 expectedPosition(x, y, z);
|
|
|
|
// Set the camera state's transform to the expected position
|
|
AzFramework::SetCameraTransform(m_cameraState, AZ::Transform::CreateTranslation(expectedPosition));
|
|
|
|
// Expect the camera state transform's position to be expected position
|
|
EXPECT_THAT(m_cameraState.m_position, IsCloseTolerance(expectedPosition, 0.01f));
|
|
|
|
// Expect the camera state transform's orientation to be identity
|
|
EXPECT_THAT(m_cameraState.m_forward, IsCloseTolerance(AZ::Vector3::CreateAxisY(), 0.01f));
|
|
EXPECT_THAT(m_cameraState.m_up, IsCloseTolerance(AZ::Vector3::CreateAxisZ(), 0.01f));
|
|
EXPECT_THAT(m_cameraState.m_side, IsCloseTolerance(AZ::Vector3::CreateAxisX(), 0.01f));
|
|
}
|
|
|
|
INSTANTIATE_TEST_CASE_P(
|
|
CameraState,
|
|
Translation,
|
|
testing::Combine(
|
|
testing::Values(0.0f, 1.0f),
|
|
testing::Values(0.0f, 1.0f),
|
|
testing::Values(0.0f, 1.0f))
|
|
);
|
|
|
|
TEST_P(Rotation, Permutation)
|
|
{
|
|
[[maybe_unused]] int expectedErrors = -1;
|
|
AZ_TEST_START_TRACE_SUPPRESSION;
|
|
|
|
// Given an orientation derived from the look at points
|
|
const auto [x, y, z] = GetParam();
|
|
const AZ::Vector3 from = AZ::Vector3::CreateZero();
|
|
const AZ::Vector3 to = AZ::Vector3(x, y, z);
|
|
const AZ::Transform expectedTransform = AZ::Transform::CreateLookAt(from, AZ::Vector3(x, y, z));
|
|
|
|
// Set the camera's rotation to the expected orientation
|
|
AzFramework::SetCameraTransform(m_cameraState, expectedTransform);
|
|
|
|
// Expect the camera state transform's position to be identity
|
|
EXPECT_THAT(m_cameraState.m_position, IsCloseTolerance(AZ::Vector3::CreateZero(), 0.01f));
|
|
|
|
if (from.IsClose(to, 0.001f))
|
|
{
|
|
// Expect one error to be generated by AZ::Transform::CreateLookAt() due to from and to being the same position
|
|
expectedErrors = 1;
|
|
|
|
// If the look at points yield an invalid orientation, expect identity rotation basis vectors
|
|
EXPECT_THAT(m_cameraState.m_forward, IsCloseTolerance(AZ::Vector3::CreateAxisY(), 0.01f));
|
|
EXPECT_THAT(m_cameraState.m_up, IsCloseTolerance(AZ::Vector3::CreateAxisZ(), 0.01f));
|
|
EXPECT_THAT(m_cameraState.m_side, IsCloseTolerance(AZ::Vector3::CreateAxisX(), 0.01f));
|
|
}
|
|
else
|
|
{
|
|
// Expect no errors to be generated by AZ::Transform::CreateLookAt()
|
|
expectedErrors = 0;
|
|
|
|
// If the look at points yield a valid orientation, expect the rotation basis vectors to be that of the orientation
|
|
EXPECT_THAT(m_cameraState.m_forward, IsCloseTolerance(expectedTransform.GetBasisY(), 0.01f));
|
|
EXPECT_THAT(m_cameraState.m_up, IsCloseTolerance(expectedTransform.GetBasisZ(), 0.01f));
|
|
EXPECT_THAT(m_cameraState.m_side, IsCloseTolerance(expectedTransform.GetBasisX(), 0.01f));
|
|
}
|
|
|
|
AZ_TEST_STOP_TRACE_SUPPRESSION(expectedErrors);
|
|
}
|
|
|
|
INSTANTIATE_TEST_CASE_P(
|
|
CameraState,
|
|
Rotation,
|
|
testing::Combine(
|
|
testing::Values(0.0f, 1.0f),
|
|
testing::Values(0.0f, 1.0f),
|
|
testing::Values(0.0f, 1.0f))
|
|
);
|
|
|
|
TEST_P(WorldFromViewMatrix, Permutation)
|
|
{
|
|
auto [translation, eulerRotation, viewportSize] = GetParam();
|
|
// Quaternion::CreateFromEulerAnglesDegrees takes a non-const Vector3&
|
|
AZ::Vector3 eulerRotationCopy = eulerRotation;
|
|
AZ::Quaternion rotation = AZ::Quaternion::CreateFromEulerAnglesDegrees(eulerRotationCopy);
|
|
AZ::Matrix4x4 worldFromView = AZ::Matrix4x4::CreateFromQuaternionAndTranslation(rotation, translation);
|
|
|
|
m_cameraState = AzFramework::CreateCameraFromWorldFromViewMatrix(worldFromView, viewportSize);
|
|
|
|
EXPECT_EQ(m_cameraState.m_viewportSize, viewportSize);
|
|
EXPECT_THAT(m_cameraState.m_position, IsCloseTolerance(translation, 0.01f));
|
|
// Translate back into a quaternion to safely compare rotations
|
|
auto decomposedCameraStateRotation = AZ::Quaternion::CreateFromBasis(m_cameraState.m_side, m_cameraState.m_forward, m_cameraState.m_up);
|
|
auto rotationDelta = 1.f - decomposedCameraStateRotation.Dot(decomposedCameraStateRotation);
|
|
EXPECT_NEAR(rotationDelta, 0.f, 0.01f);
|
|
}
|
|
|
|
INSTANTIATE_TEST_CASE_P(
|
|
CameraState,
|
|
WorldFromViewMatrix,
|
|
testing::Combine(
|
|
testing::Values(AZ::Vector3{0.f, 0.f, 0.f}, AZ::Vector3{100.f, 0.f, 0.f}, AZ::Vector3{-5.f,10.f,-1.f}),
|
|
testing::Values(AZ::Vector3{0.f, 0.f, 0.f}, AZ::Vector3{90.f, 0.f, 0.f}, AZ::Vector3{-45.f, -45.f, -45.f}),
|
|
testing::Values(AZ::Vector2{100.f, 100.f})
|
|
)
|
|
);
|
|
|
|
TEST_P(PerspectiveMatrix, Permutation)
|
|
{
|
|
auto [fovY, aspectRatio, nearClip, farClip] = GetParam();
|
|
|
|
AZ::Matrix4x4 clipFromView;
|
|
MakePerspectiveFovMatrixRH(clipFromView, fovY, aspectRatio, nearClip, farClip);
|
|
|
|
AzFramework::SetCameraClippingVolumeFromPerspectiveFovMatrixRH(m_cameraState, clipFromView);
|
|
|
|
EXPECT_NEAR(m_cameraState.m_nearClip, nearClip, 0.01f);
|
|
EXPECT_NEAR(m_cameraState.m_farClip, farClip, 1.f);
|
|
EXPECT_NEAR(m_cameraState.m_fovOrZoom, fovY, 0.01f);
|
|
}
|
|
|
|
INSTANTIATE_TEST_CASE_P(
|
|
CameraState,
|
|
PerspectiveMatrix,
|
|
testing::Combine(
|
|
testing::Values(1.f, 0.5f, 2.f),
|
|
testing::Values(1.f, 16.f / 9.f),
|
|
testing::Values(1.f, 50.f),
|
|
testing::Values(100.f, 10000.f)
|
|
)
|
|
);
|
|
|
|
} // namespace UnitTest
|