/* * 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 #include #include #include #include #include #include #include #include namespace UnitTest { class AxisAlignedBoxShapeTest : public AllocatorsFixture { AZStd::unique_ptr m_serializeContext; AZStd::unique_ptr m_transformComponentDescriptor; AZStd::unique_ptr m_axisAlignedBoxShapeComponentDescriptor; AZStd::unique_ptr m_axisAlignedBoxShapeDebugDisplayComponentDescriptor; public: void SetUp() override { AllocatorsFixture::SetUp(); m_serializeContext = AZStd::make_unique(); m_transformComponentDescriptor = AZStd::unique_ptr(AzFramework::TransformComponent::CreateDescriptor()); m_transformComponentDescriptor->Reflect(&(*m_serializeContext)); m_axisAlignedBoxShapeComponentDescriptor = AZStd::unique_ptr(LmbrCentral::AxisAlignedBoxShapeComponent::CreateDescriptor()); m_axisAlignedBoxShapeComponentDescriptor->Reflect(&(*m_serializeContext)); m_axisAlignedBoxShapeDebugDisplayComponentDescriptor = AZStd::unique_ptr(LmbrCentral::AxisAlignedBoxShapeDebugDisplayComponent::CreateDescriptor()); m_axisAlignedBoxShapeDebugDisplayComponentDescriptor->Reflect(&(*m_serializeContext)); } void TearDown() override { m_transformComponentDescriptor.reset(); m_axisAlignedBoxShapeComponentDescriptor.reset(); m_axisAlignedBoxShapeDebugDisplayComponentDescriptor.reset(); m_serializeContext.reset(); AllocatorsFixture::TearDown(); } }; void CreateAxisAlignedBox(const AZ::Transform& transform, const AZ::Vector3& dimensions, AZ::Entity& entity) { entity.CreateComponent(); entity.CreateComponent(); entity.CreateComponent(); entity.Init(); entity.Activate(); AZ::TransformBus::Event(entity.GetId(), &AZ::TransformBus::Events::SetWorldTM, transform); LmbrCentral::BoxShapeComponentRequestsBus::Event( entity.GetId(), &LmbrCentral::BoxShapeComponentRequestsBus::Events::SetBoxDimensions, dimensions); } void CreateDefaultAxisAlignedBox(const AZ::Transform& transform, AZ::Entity& entity) { CreateAxisAlignedBox(transform, AZ::Vector3(10.0f, 10.0f, 10.0f), entity); } TEST_F(AxisAlignedBoxShapeTest, EntityTransformIsCorrect) { AZ::Entity entity; CreateAxisAlignedBox( AZ::Transform::CreateTranslation(AZ::Vector3(0.0f, 0.0f, 0.0f)) * AZ::Transform::CreateRotationZ(AZ::Constants::QuarterPi), AZ::Vector3(1.0f), entity); AZ::Transform transform; AZ::TransformBus::EventResult(transform, entity.GetId(), &AZ::TransformBus::Events::GetWorldTM); EXPECT_EQ(transform, AZ::Transform::CreateRotationZ(AZ::Constants::QuarterPi)); } TEST_F(AxisAlignedBoxShapeTest, BoxWithZRotationHasCorrectRayIntersection) { AZ::Entity entity; CreateAxisAlignedBox( AZ::Transform::CreateRotationZ(AZ::Constants::QuarterPi), AZ::Vector3(1.0f), entity); bool rayHit = false; float distance; LmbrCentral::ShapeComponentRequestsBus::EventResult( rayHit, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay, AZ::Vector3(5.0f, 0.0f, 0.0f), AZ::Vector3(-1.0f, 0.0f, 0.0f), distance); // This test creates a unit box centered on (0, 0, 0) and rotated by 45 degrees. The distance to the box should // be 4.5 if it isn't rotated but less if there is any rotation. EXPECT_TRUE(rayHit); EXPECT_NEAR(distance, 4.5f, 1e-2f); } TEST_F(AxisAlignedBoxShapeTest, BoxWithTranslationAndRotationsHasCorrectRayIntersection) { AZ::Entity entity; CreateAxisAlignedBox( AZ::Transform::CreateFromQuaternionAndTranslation( AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisX(), AZ::Constants::HalfPi) * AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisZ(), AZ::Constants::QuarterPi), AZ::Vector3(-10.0f, -10.0f, -10.0f)), AZ::Vector3(4.0f, 4.0f, 2.0f), entity); bool rayHit = false; float distance; LmbrCentral::ShapeComponentRequestsBus::EventResult( rayHit, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay, AZ::Vector3(-10.0f, -10.0f, 0.0f), AZ::Vector3(0.0f, 0.0f, -1.0f), distance); // This test creates a box of dimensions (4.0, 4.0, 2.0) centered on (-10, -10, 0) and rotated in X and Z. The distance to the box should // be 9.0 if it isn't rotated but less if there is any rotation. EXPECT_TRUE(rayHit); EXPECT_NEAR(distance, 9.00f, 1e-2f); } TEST_F(AxisAlignedBoxShapeTest, BoxWithTranslationHasCorrectRayIntersection) { AZ::Entity entity; CreateAxisAlignedBox( AZ::Transform::CreateTranslation(AZ::Vector3(100.0f, 100.0f, 0.0f)), AZ::Vector3(5.0f, 5.0f, 5.0f), entity); bool rayHit = false; float distance; LmbrCentral::ShapeComponentRequestsBus::EventResult( rayHit, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay, AZ::Vector3(100.0f, 100.0f, -100.0f), AZ::Vector3(0.0f, 0.0f, 1.0f), distance); // This test creates a box of dimensions (5.0, 5.0, 5.0) centered on (100, 100, 0) and not rotated. The distance to the box // should be 97.5. EXPECT_TRUE(rayHit); EXPECT_NEAR(distance, 97.5f, 1e-2f); } TEST_F(AxisAlignedBoxShapeTest, BoxWithTranslationRotationAndScaleHasCorrectRayIntersection) { AZ::Entity entity; CreateAxisAlignedBox( AZ::Transform( AZ::Vector3(0.0f, 0.0f, 5.0f), AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisY(), AZ::Constants::QuarterPi), 3.0f), AZ::Vector3(2.0f, 4.0f, 1.0f), entity); bool rayHit = false; float distance; LmbrCentral::ShapeComponentRequestsBus::EventResult( rayHit, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay, AZ::Vector3(1.0f, -10.0f, 4.0f), AZ::Vector3(0.0f, 1.0f, 0.0f), distance); // This test creates a box of dimensions (2.0, 4.0, 1.0) centered on (0, 0, 5) and rotated about the Y axis by 45 degrees. // The distance to the box should be 4.0 if not rotated but scaled and less if it is. EXPECT_TRUE(rayHit); EXPECT_NEAR(distance, 4.0f, 1e-2f); } } // namespace UnitTest