Terrain/jjjoness/3172 axis aligned box shape component (#3981)
* CHanges to Push/Pop Matrix Signed-off-by: John Jones-Steele <jjjoness@amazon.com> * Fixed bad commit Signed-off-by: John Jones-Steele <jjjoness@amazon.com> * REmoved the AxisAlignedBoxShapeComponentBux and AxisAlignedBoxShapeConfig Signed-off-by: John Jones-Steele <jjjoness@amazon.com> * Fixed derivation of AxisAlignedBoxShape Signed-off-by: John Jones-Steele <jjjoness@amazon.com> * Added ShowChildrenOnly to Component Signed-off-by: John Jones-Steele <jjjoness@amazon.com> * Fixed cmake file Signed-off-by: John Jones-Steele <jjjoness@amazon.com> * Changes from review Signed-off-by: John Jones-Steele <jjjoness@amazon.com> * Added tests for AxisAlignedBoxShape Signed-off-by: John Jones-Steele <jjjoness@amazon.com> * Addressed PR comments and added one further test. Signed-off-by: John Jones-Steele <jjjoness@amazon.com> * Removed dead code. Signed-off-by: John Jones-Steele <jjjoness@amazon.com> * Changes from review Signed-off-by: John Jones-Steele <jjjoness@amazon.com> * Spelling fix and changed link to docs Signed-off-by: John Jones-Steele <jjjoness@amazon.com> * Fixed profile bug in Linux Signed-off-by: John Jones-Steele <jjjoness@amazon.com> * Fixed problem with Unity Profile Build in Tests Signed-off-by: John Jones-Steele <jjjoness@amazon.com>monroegm-disable-blank-issue-2
parent
6863e9cf9e
commit
817f8ce4c1
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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 "AxisAlignedBoxShape.h"
|
||||
|
||||
#include <AzCore/Math/Color.h>
|
||||
#include <AzCore/Math/IntersectSegment.h>
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzCore/Math/Matrix3x3.h>
|
||||
#include <AzCore/Math/Random.h>
|
||||
#include <AzCore/Math/Sfmt.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/std/algorithm.h>
|
||||
#include <AzCore/std/containers/array.h>
|
||||
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
|
||||
#include <Shape/ShapeDisplay.h>
|
||||
#include <random>
|
||||
|
||||
namespace LmbrCentral
|
||||
{
|
||||
AxisAlignedBoxShape::AxisAlignedBoxShape()
|
||||
: BoxShape()
|
||||
{
|
||||
}
|
||||
|
||||
void AxisAlignedBoxShape::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<AxisAlignedBoxShape, BoxShape>()
|
||||
->Version(1)
|
||||
;
|
||||
|
||||
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<AxisAlignedBoxShape>("Axis Aligned Box Shape", "Axis Aligned Box shape configuration parameters")
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AxisAlignedBoxShape::Activate(AZ::EntityId entityId)
|
||||
{
|
||||
BoxShape::Activate(entityId);
|
||||
m_currentTransform.SetRotation(AZ::Quaternion::CreateIdentity());
|
||||
}
|
||||
|
||||
void AxisAlignedBoxShape::OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world)
|
||||
{
|
||||
AZ::Transform worldNoRotation(world.GetTranslation(), AZ::Quaternion::CreateIdentity(), world.GetUniformScale());
|
||||
BoxShape::OnTransformChanged(local, worldNoRotation);
|
||||
}
|
||||
} // namespace LmbrCentral
|
||||
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/Math/Aabb.h>
|
||||
#include <AzCore/Math/Obb.h>
|
||||
#include <AzCore/Component/NonUniformScaleBus.h>
|
||||
#include <LmbrCentral/Shape/ShapeComponentBus.h>
|
||||
#include <LmbrCentral/Shape/BoxShapeComponentBus.h>
|
||||
#include "BoxShape.h"
|
||||
|
||||
namespace AzFramework
|
||||
{
|
||||
class DebugDisplayRequests;
|
||||
}
|
||||
|
||||
namespace LmbrCentral
|
||||
{
|
||||
struct ShapeDrawParams;
|
||||
|
||||
class AxisAlignedBoxShape
|
||||
: public BoxShape
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(AxisAlignedBoxShape, AZ::SystemAllocator, 0)
|
||||
AZ_RTTI(AxisAlignedBoxShape, "{CFDC96C5-287A-4033-8D7D-BA9331C13F25}", BoxShape)
|
||||
|
||||
AxisAlignedBoxShape();
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
void Activate(AZ::EntityId entityId) override;
|
||||
|
||||
// AZ::TransformNotificationBus::Handler
|
||||
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
|
||||
};
|
||||
} // namespace LmbrCentral
|
||||
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* 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 "AxisAlignedBoxShapeComponent.h"
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
|
||||
#include <Shape/ShapeComponentConverters.h>
|
||||
#include <Shape/ShapeDisplay.h>
|
||||
|
||||
namespace LmbrCentral
|
||||
{
|
||||
void AxisAlignedBoxShapeComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC_CE("ShapeService"));
|
||||
provided.push_back(AZ_CRC_CE("BoxShapeService"));
|
||||
provided.push_back(AZ_CRC_CE("AxisAlignedBoxShapeService"));
|
||||
}
|
||||
|
||||
void AxisAlignedBoxShapeComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC_CE("ShapeService"));
|
||||
incompatible.push_back(AZ_CRC_CE("AxisAlignedBoxShapeService"));
|
||||
}
|
||||
|
||||
void AxisAlignedBoxShapeComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
|
||||
{
|
||||
required.push_back(AZ_CRC_CE("TransformService"));
|
||||
}
|
||||
|
||||
void AxisAlignedBoxShapeComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
|
||||
{
|
||||
dependent.push_back(AZ_CRC_CE("NonUniformScaleService"));
|
||||
}
|
||||
|
||||
void AxisAlignedBoxShapeDebugDisplayComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<AxisAlignedBoxShapeDebugDisplayComponent, EntityDebugDisplayComponent>()
|
||||
->Version(1)->Field(
|
||||
"Configuration", &AxisAlignedBoxShapeDebugDisplayComponent::m_boxShapeConfig)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void AxisAlignedBoxShapeDebugDisplayComponent::Activate()
|
||||
{
|
||||
EntityDebugDisplayComponent::Activate();
|
||||
ShapeComponentNotificationsBus::Handler::BusConnect(GetEntityId());
|
||||
m_nonUniformScale = AZ::Vector3::CreateOne();
|
||||
AZ::NonUniformScaleRequestBus::EventResult(m_nonUniformScale, GetEntityId(), &AZ::NonUniformScaleRequests::GetScale);
|
||||
}
|
||||
|
||||
void AxisAlignedBoxShapeDebugDisplayComponent::Deactivate()
|
||||
{
|
||||
ShapeComponentNotificationsBus::Handler::BusDisconnect();
|
||||
EntityDebugDisplayComponent::Deactivate();
|
||||
}
|
||||
|
||||
void AxisAlignedBoxShapeDebugDisplayComponent::Draw(AzFramework::DebugDisplayRequests& debugDisplay)
|
||||
{
|
||||
AZ::Matrix3x4 saveMatrix;
|
||||
ShapeDrawParams drawParams = g_defaultShapeDrawParams;
|
||||
drawParams.m_shapeColor = m_boxShapeConfig.GetDrawColor();
|
||||
drawParams.m_filled = m_boxShapeConfig.IsFilled();
|
||||
AZ::Transform transform = GetCurrentTransform();
|
||||
transform.SetRotation(AZ::Quaternion::CreateIdentity());
|
||||
saveMatrix = debugDisplay.PopPremultipliedMatrix();
|
||||
debugDisplay.PushMatrix(transform);
|
||||
DrawBoxShape(drawParams, m_boxShapeConfig, debugDisplay, m_nonUniformScale);
|
||||
debugDisplay.PopMatrix();
|
||||
debugDisplay.PushPremultipliedMatrix(saveMatrix);
|
||||
}
|
||||
|
||||
bool AxisAlignedBoxShapeDebugDisplayComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
|
||||
{
|
||||
if (const auto config = azrtti_cast<const BoxShapeConfig*>(baseConfig))
|
||||
{
|
||||
m_boxShapeConfig = *config;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AxisAlignedBoxShapeDebugDisplayComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
|
||||
{
|
||||
if (auto outConfig = azrtti_cast<BoxShapeConfig*>(outBaseConfig))
|
||||
{
|
||||
*outConfig = m_boxShapeConfig;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AxisAlignedBoxShapeDebugDisplayComponent::OnShapeChanged(ShapeChangeReasons changeReason)
|
||||
{
|
||||
if (changeReason == ShapeChangeReasons::ShapeChanged)
|
||||
{
|
||||
BoxShapeComponentRequestsBus::EventResult(m_boxShapeConfig, GetEntityId(), &BoxShapeComponentRequests::GetBoxConfiguration);
|
||||
AZ::NonUniformScaleRequestBus::EventResult(m_nonUniformScale, GetEntityId(), &AZ::NonUniformScaleRequests::GetScale);
|
||||
}
|
||||
}
|
||||
|
||||
void AxisAlignedBoxShapeComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AxisAlignedBoxShape::Reflect(context);
|
||||
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<AxisAlignedBoxShapeComponent, Component>()
|
||||
->Version(1)
|
||||
->Field("AxisAlignedBoxShape", &AxisAlignedBoxShapeComponent::m_aaboxShape)
|
||||
;
|
||||
}
|
||||
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->Constant("AxisAlignedBoxShapeComponentTypeId", BehaviorConstant(AxisAlignedBoxShapeComponentTypeId));
|
||||
}
|
||||
}
|
||||
|
||||
void AxisAlignedBoxShapeComponent::Activate()
|
||||
{
|
||||
m_aaboxShape.Activate(GetEntityId());
|
||||
}
|
||||
|
||||
void AxisAlignedBoxShapeComponent::Deactivate()
|
||||
{
|
||||
m_aaboxShape.Deactivate();
|
||||
}
|
||||
|
||||
bool AxisAlignedBoxShapeComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
|
||||
{
|
||||
if (const auto config = azrtti_cast<const BoxShapeConfig*>(baseConfig))
|
||||
{
|
||||
m_aaboxShape.SetBoxConfiguration(*config);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AxisAlignedBoxShapeComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
|
||||
{
|
||||
if (auto config = azrtti_cast<BoxShapeConfig*>(outBaseConfig))
|
||||
{
|
||||
*config = m_aaboxShape.GetBoxConfiguration();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace LmbrCentral
|
||||
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 <AzCore/Component/Component.h>
|
||||
|
||||
#include "Rendering/EntityDebugDisplayComponent.h"
|
||||
#include "AxisAlignedBoxShape.h"
|
||||
|
||||
namespace LmbrCentral
|
||||
{
|
||||
/// Type ID for the AxisAlignedBoxShapeComponent
|
||||
static const AZ::Uuid AxisAlignedBoxShapeComponentTypeId = "{641D817E-1BC6-406A-BBB2-218541808E45}";
|
||||
|
||||
/// Type ID for the EditorAxisAlignedBoxShapeComponent
|
||||
static const AZ::Uuid EditorAxisAlignedBoxShapeComponentTypeId = "{8C027DF6-E157-4159-9BF8-F1B925466F1F}";
|
||||
|
||||
/// Provide a Component interface for AxisAlignedBoxShape functionality.
|
||||
class AxisAlignedBoxShapeComponent
|
||||
: public AZ::Component
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(AxisAlignedBoxShapeComponent, AxisAlignedBoxShapeComponentTypeId)
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
// AZ::Component
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
|
||||
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
|
||||
|
||||
private:
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
|
||||
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
|
||||
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
|
||||
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
|
||||
|
||||
AxisAlignedBoxShape m_aaboxShape; ///< Stores underlying box type for this component.
|
||||
};
|
||||
|
||||
/// Concrete EntityDebugDisplay implementation for BoxShape.
|
||||
class AxisAlignedBoxShapeDebugDisplayComponent
|
||||
: public EntityDebugDisplayComponent
|
||||
, public ShapeComponentNotificationsBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(AxisAlignedBoxShapeDebugDisplayComponent, "{BA93F933-1DC9-4E0E-B930-A7E3968D5DD1}", EntityDebugDisplayComponent)
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
AxisAlignedBoxShapeDebugDisplayComponent() = default;
|
||||
|
||||
// AZ::Component
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
|
||||
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
|
||||
|
||||
// EntityDebugDisplayComponent
|
||||
void Draw(AzFramework::DebugDisplayRequests& debugDisplay) override;
|
||||
|
||||
private:
|
||||
AZ_DISABLE_COPY_MOVE(AxisAlignedBoxShapeDebugDisplayComponent)
|
||||
|
||||
// ShapeComponentNotificationsBus
|
||||
void OnShapeChanged(ShapeChangeReasons changeReason) override;
|
||||
|
||||
BoxShapeConfig m_boxShapeConfig; ///< Stores configuration data for box shape.
|
||||
AZ::Vector3 m_nonUniformScale = AZ::Vector3::CreateOne(); ///< Caches non-uniform scale for this entity.
|
||||
};
|
||||
} // namespace LmbrCentral
|
||||
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* 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/Math/Transform.h>
|
||||
#include <AzCore/RTTI/ReflectContext.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzToolsFramework/ComponentModes/BoxComponentMode.h>
|
||||
#include <AzToolsFramework/Maths/TransformUtils.h>
|
||||
|
||||
#include "AxisAlignedBoxShapeComponent.h"
|
||||
#include "EditorAxisAlignedBoxShapeComponent.h"
|
||||
#include "EditorShapeComponentConverters.h"
|
||||
#include "ShapeDisplay.h"
|
||||
|
||||
namespace LmbrCentral
|
||||
{
|
||||
void EditorAxisAlignedBoxShapeComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<EditorAxisAlignedBoxShapeComponent, EditorBaseShapeComponent>()
|
||||
->Version(1)
|
||||
->Field("AxisAlignedBoxShape", &EditorAxisAlignedBoxShapeComponent::m_aaboxShape)
|
||||
->Field("ComponentMode", &EditorAxisAlignedBoxShapeComponent::m_componentModeDelegate)
|
||||
;
|
||||
|
||||
if (auto editContext = serializeContext->GetEditContext())
|
||||
{
|
||||
editContext->Class<EditorAxisAlignedBoxShapeComponent>(
|
||||
"Axis Aligned Box Shape", "The Axis Aligned Box Shape component creates a box around the associated entity")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "Shape")
|
||||
->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Box_Shape.svg")
|
||||
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Box_Shape.svg")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/shape/axis-aligned-box-shape/")
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorAxisAlignedBoxShapeComponent::m_aaboxShape, "Axis Aligned Box Shape", "Axis Aligned Box Shape Configuration")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorAxisAlignedBoxShapeComponent::ConfigurationChanged)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorAxisAlignedBoxShapeComponent::m_componentModeDelegate, "Component Mode", "Axis Aligned Box Shape Component Mode")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EditorAxisAlignedBoxShapeComponent::Init()
|
||||
{
|
||||
EditorBaseShapeComponent::Init();
|
||||
|
||||
SetShapeComponentConfig(&m_aaboxShape.ModifyConfiguration());
|
||||
}
|
||||
|
||||
void EditorAxisAlignedBoxShapeComponent::Activate()
|
||||
{
|
||||
EditorBaseShapeComponent::Activate();
|
||||
m_aaboxShape.Activate(GetEntityId());
|
||||
AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(GetEntityId());
|
||||
AzToolsFramework::BoxManipulatorRequestBus::Handler::BusConnect(
|
||||
AZ::EntityComponentIdPair(GetEntityId(), GetId()));
|
||||
|
||||
// ComponentMode
|
||||
m_componentModeDelegate.ConnectWithSingleComponentMode<
|
||||
EditorAxisAlignedBoxShapeComponent, AzToolsFramework::BoxComponentMode>(
|
||||
AZ::EntityComponentIdPair(GetEntityId(), GetId()), this);
|
||||
}
|
||||
|
||||
void EditorAxisAlignedBoxShapeComponent::Deactivate()
|
||||
{
|
||||
m_componentModeDelegate.Disconnect();
|
||||
|
||||
AzToolsFramework::BoxManipulatorRequestBus::Handler::BusDisconnect();
|
||||
AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect();
|
||||
m_aaboxShape.Deactivate();
|
||||
EditorBaseShapeComponent::Deactivate();
|
||||
}
|
||||
|
||||
void EditorAxisAlignedBoxShapeComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
EditorBaseShapeComponent::GetProvidedServices(provided);
|
||||
provided.push_back(AZ_CRC_CE("BoxShapeService"));
|
||||
provided.push_back(AZ_CRC_CE("AxisAlignedBoxShapeService"));
|
||||
}
|
||||
|
||||
void EditorAxisAlignedBoxShapeComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
|
||||
{
|
||||
dependent.push_back(AZ_CRC_CE("NonUniformScaleService"));
|
||||
}
|
||||
|
||||
void EditorAxisAlignedBoxShapeComponent::DisplayEntityViewport(
|
||||
[[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo,
|
||||
AzFramework::DebugDisplayRequests& debugDisplay)
|
||||
{
|
||||
DisplayShape(
|
||||
debugDisplay, [this]() { return CanDraw(); },
|
||||
[this](AzFramework::DebugDisplayRequests& debugDisplay)
|
||||
{
|
||||
DrawBoxShape(
|
||||
{ m_aaboxShape.GetBoxConfiguration().GetDrawColor(), m_shapeWireColor, m_aaboxShape.GetBoxConfiguration().IsFilled() },
|
||||
m_aaboxShape.GetBoxConfiguration(), debugDisplay, m_aaboxShape.GetCurrentNonUniformScale());
|
||||
},
|
||||
m_aaboxShape.GetCurrentTransform());
|
||||
}
|
||||
|
||||
void EditorAxisAlignedBoxShapeComponent::ConfigurationChanged()
|
||||
{
|
||||
m_aaboxShape.InvalidateCache(InvalidateShapeCacheReason::ShapeChange);
|
||||
|
||||
ShapeComponentNotificationsBus::Event(GetEntityId(),
|
||||
&ShapeComponentNotificationsBus::Events::OnShapeChanged,
|
||||
ShapeComponentNotifications::ShapeChangeReasons::ShapeChanged);
|
||||
|
||||
AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast(
|
||||
&AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::Refresh,
|
||||
AZ::EntityComponentIdPair(GetEntityId(), GetId()));
|
||||
}
|
||||
|
||||
void EditorAxisAlignedBoxShapeComponent::BuildGameEntity(AZ::Entity* gameEntity)
|
||||
{
|
||||
if (AxisAlignedBoxShapeComponent* boxShapeComponent = gameEntity->CreateComponent<AxisAlignedBoxShapeComponent>())
|
||||
{
|
||||
boxShapeComponent->SetConfiguration(m_aaboxShape.GetBoxConfiguration());
|
||||
}
|
||||
|
||||
if (m_visibleInGameView)
|
||||
{
|
||||
if (auto component = gameEntity->CreateComponent<AxisAlignedBoxShapeDebugDisplayComponent>())
|
||||
{
|
||||
component->SetConfiguration(m_aaboxShape.GetBoxConfiguration());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EditorAxisAlignedBoxShapeComponent::OnTransformChanged(
|
||||
const AZ::Transform& /*local*/, const AZ::Transform& /*world*/)
|
||||
{
|
||||
AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast(
|
||||
&AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequests::Refresh,
|
||||
AZ::EntityComponentIdPair(GetEntityId(), GetId()));
|
||||
}
|
||||
|
||||
AZ::Vector3 EditorAxisAlignedBoxShapeComponent::GetDimensions()
|
||||
{
|
||||
return m_aaboxShape.GetBoxDimensions();
|
||||
}
|
||||
|
||||
void EditorAxisAlignedBoxShapeComponent::SetDimensions(const AZ::Vector3& dimensions)
|
||||
{
|
||||
return m_aaboxShape.SetBoxDimensions(dimensions);
|
||||
}
|
||||
|
||||
AZ::Transform EditorAxisAlignedBoxShapeComponent::GetCurrentTransform()
|
||||
{
|
||||
return AzToolsFramework::TransformNormalizedScale(m_aaboxShape.GetCurrentTransform());
|
||||
}
|
||||
|
||||
AZ::Vector3 EditorAxisAlignedBoxShapeComponent::GetBoxScale()
|
||||
{
|
||||
return AZ::Vector3(m_aaboxShape.GetCurrentTransform().GetUniformScale() * m_aaboxShape.GetCurrentNonUniformScale());
|
||||
}
|
||||
} // namespace LmbrCentral
|
||||
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 "AxisAlignedBoxShape.h"
|
||||
#include "AxisAlignedBoxShapeComponent.h"
|
||||
#include "EditorBaseShapeComponent.h"
|
||||
|
||||
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
|
||||
#include <AzToolsFramework/ComponentMode/ComponentModeDelegate.h>
|
||||
#include <AzToolsFramework/Manipulators/BoxManipulatorRequestBus.h>
|
||||
|
||||
|
||||
namespace LmbrCentral
|
||||
{
|
||||
/// Editor representation of Box Shape Component.
|
||||
class EditorAxisAlignedBoxShapeComponent
|
||||
: public EditorBaseShapeComponent
|
||||
, private AzFramework::EntityDebugDisplayEventBus::Handler
|
||||
, private AzToolsFramework::BoxManipulatorRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_EDITOR_COMPONENT(EditorAxisAlignedBoxShapeComponent, EditorAxisAlignedBoxShapeComponentTypeId, EditorBaseShapeComponent);
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
EditorAxisAlignedBoxShapeComponent() = default;
|
||||
|
||||
// AZ::Component
|
||||
void Init() override;
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
|
||||
protected:
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
|
||||
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
|
||||
|
||||
// EditorComponentBase
|
||||
void BuildGameEntity(AZ::Entity* gameEntity) override;
|
||||
|
||||
// AZ::TransformNotificationBus::Handler
|
||||
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
|
||||
|
||||
private:
|
||||
AZ_DISABLE_COPY_MOVE(EditorAxisAlignedBoxShapeComponent)
|
||||
|
||||
// AzFramework::EntityDebugDisplayEventBus
|
||||
void DisplayEntityViewport(
|
||||
const AzFramework::ViewportInfo& viewportInfo,
|
||||
AzFramework::DebugDisplayRequests& debugDisplay) override;
|
||||
|
||||
// AzToolsFramework::BoxManipulatorRequestBus
|
||||
AZ::Vector3 GetDimensions() override;
|
||||
void SetDimensions(const AZ::Vector3& dimensions) override;
|
||||
AZ::Transform GetCurrentTransform() override;
|
||||
AZ::Vector3 GetBoxScale() override;
|
||||
|
||||
void ConfigurationChanged();
|
||||
|
||||
AxisAlignedBoxShape m_aaboxShape; ///< Stores underlying box representation for this component.
|
||||
|
||||
using ComponentModeDelegate = AzToolsFramework::ComponentModeFramework::ComponentModeDelegate;
|
||||
ComponentModeDelegate m_componentModeDelegate; /**< Responsible for detecting ComponentMode activation
|
||||
* and creating a concrete ComponentMode.*/
|
||||
};
|
||||
} // namespace LmbrCentral
|
||||
@ -0,0 +1,238 @@
|
||||
/*
|
||||
* 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 <AzTest/AzTest.h>
|
||||
|
||||
#include <AZTestShared/Math/MathTestHelpers.h>
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzCore/Math/Matrix3x3.h>
|
||||
#include <AzCore/Math/Random.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzFramework/Components/NonUniformScaleComponent.h>
|
||||
#include <AzFramework/Components/TransformComponent.h>
|
||||
#include <AzFramework/UnitTest/TestDebugDisplayRequests.h>
|
||||
#include <Shape/AxisAlignedBoxShapeComponent.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class AxisAlignedBoxShapeTest : public AllocatorsFixture
|
||||
{
|
||||
AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
|
||||
AZStd::unique_ptr<AZ::ComponentDescriptor> m_transformComponentDescriptor;
|
||||
AZStd::unique_ptr<AZ::ComponentDescriptor> m_axisAlignedBoxShapeComponentDescriptor;
|
||||
AZStd::unique_ptr<AZ::ComponentDescriptor> m_axisAlignedBoxShapeDebugDisplayComponentDescriptor;
|
||||
AZStd::unique_ptr<AZ::ComponentDescriptor> m_nonUniformScaleComponentDescriptor;
|
||||
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
AllocatorsFixture::SetUp();
|
||||
m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
|
||||
|
||||
m_transformComponentDescriptor =
|
||||
AZStd::unique_ptr<AZ::ComponentDescriptor>(AzFramework::TransformComponent::CreateDescriptor());
|
||||
m_transformComponentDescriptor->Reflect(&(*m_serializeContext));
|
||||
m_axisAlignedBoxShapeComponentDescriptor =
|
||||
AZStd::unique_ptr<AZ::ComponentDescriptor>(LmbrCentral::AxisAlignedBoxShapeComponent::CreateDescriptor());
|
||||
m_axisAlignedBoxShapeComponentDescriptor->Reflect(&(*m_serializeContext));
|
||||
m_axisAlignedBoxShapeDebugDisplayComponentDescriptor =
|
||||
AZStd::unique_ptr<AZ::ComponentDescriptor>(LmbrCentral::AxisAlignedBoxShapeDebugDisplayComponent::CreateDescriptor());
|
||||
m_axisAlignedBoxShapeDebugDisplayComponentDescriptor->Reflect(&(*m_serializeContext));
|
||||
m_nonUniformScaleComponentDescriptor =
|
||||
AZStd::unique_ptr<AZ::ComponentDescriptor>(AzFramework::NonUniformScaleComponent::CreateDescriptor());
|
||||
m_nonUniformScaleComponentDescriptor->Reflect(&(*m_serializeContext));
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_transformComponentDescriptor.reset();
|
||||
m_axisAlignedBoxShapeComponentDescriptor.reset();
|
||||
m_axisAlignedBoxShapeDebugDisplayComponentDescriptor.reset();
|
||||
m_nonUniformScaleComponentDescriptor.reset();
|
||||
m_serializeContext.reset();
|
||||
AllocatorsFixture::TearDown();
|
||||
}
|
||||
};
|
||||
|
||||
void CreateAxisAlignedBox(const AZ::Transform& transform, const AZ::Vector3& dimensions, AZ::Entity& entity)
|
||||
{
|
||||
entity.CreateComponent<LmbrCentral::AxisAlignedBoxShapeComponent>();
|
||||
entity.CreateComponent<LmbrCentral::AxisAlignedBoxShapeDebugDisplayComponent>();
|
||||
entity.CreateComponent<AzFramework::TransformComponent>();
|
||||
|
||||
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 CreateAxisAlignedBoxWithNonUniformScale(
|
||||
const AZ::Transform& transform, const AZ::Vector3& nonUniformScale, const AZ::Vector3& dimensions, AZ::Entity& entity)
|
||||
{
|
||||
entity.CreateComponent<LmbrCentral::AxisAlignedBoxShapeComponent>();
|
||||
entity.CreateComponent<LmbrCentral::AxisAlignedBoxShapeDebugDisplayComponent>();
|
||||
entity.CreateComponent<AzFramework::TransformComponent>();
|
||||
entity.CreateComponent<AzFramework::NonUniformScaleComponent>();
|
||||
|
||||
entity.Init();
|
||||
entity.Activate();
|
||||
|
||||
AZ::TransformBus::Event(entity.GetId(), &AZ::TransformBus::Events::SetWorldTM, transform);
|
||||
LmbrCentral::BoxShapeComponentRequestsBus::Event(
|
||||
entity.GetId(), &LmbrCentral::BoxShapeComponentRequestsBus::Events::SetBoxDimensions, dimensions);
|
||||
AZ::NonUniformScaleRequestBus::Event(entity.GetId(), &AZ::NonUniformScaleRequests::SetScale, nonUniformScale);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
TEST_F(AxisAlignedBoxShapeTest, RayIntersectWithBoxRotatedNonUniformScale)
|
||||
{
|
||||
AZ::Entity entity;
|
||||
CreateAxisAlignedBoxWithNonUniformScale(
|
||||
AZ::Transform(
|
||||
AZ::Vector3(2.0f, -5.0f, 3.0f), AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisY(), AZ::Constants::QuarterPi),
|
||||
0.5f),
|
||||
AZ::Vector3(2.2f, 1.8f, 0.4f), AZ::Vector3(0.2f, 2.6f, 1.2f), entity);
|
||||
|
||||
// This test creates a box of dimensions (2.2, 1.8, 0.4) centered on (2.0, -5, 3) and rotated about the Y axis by 45 degrees.
|
||||
// The box is tested for axis-alignment by firing various rays and ensuring they either hit or miss the box. Any failure here
|
||||
// would show the box has been rotated.
|
||||
|
||||
// Ray should just miss the box
|
||||
bool rayHit = false;
|
||||
float distance = AZ::Constants::FloatMax;
|
||||
LmbrCentral::ShapeComponentRequestsBus::EventResult(
|
||||
rayHit, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay, AZ::Vector3(1.8f, -6.2f, 3.0f),
|
||||
AZ::Vector3(1.0f, 0.0f, 0.0f), distance);
|
||||
EXPECT_FALSE(rayHit);
|
||||
|
||||
// Ray should just hit the box
|
||||
rayHit = false;
|
||||
distance = AZ::Constants::FloatMax;
|
||||
LmbrCentral::ShapeComponentRequestsBus::EventResult(
|
||||
rayHit, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay, AZ::Vector3(1.8f, -6.1f, 3.0f),
|
||||
AZ::Vector3(1.0f, 0.0f, 0.0f), distance);
|
||||
EXPECT_TRUE(rayHit);
|
||||
EXPECT_NEAR(distance, 0.09f, 1e-3f);
|
||||
|
||||
// Ray should just miss the box
|
||||
rayHit = false;
|
||||
distance = AZ::Constants::FloatMax;
|
||||
LmbrCentral::ShapeComponentRequestsBus::EventResult(
|
||||
rayHit, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay, AZ::Vector3(2.2f, -6.2f, 3.0f),
|
||||
AZ::Vector3(0.0f, 1.0f, 0.0f), distance);
|
||||
EXPECT_FALSE(rayHit);
|
||||
|
||||
// Ray should just hit the box
|
||||
rayHit = false;
|
||||
distance = AZ::Constants::FloatMax;
|
||||
LmbrCentral::ShapeComponentRequestsBus::EventResult(
|
||||
rayHit, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay, AZ::Vector3(2.1f, -6.2f, 3.0f),
|
||||
AZ::Vector3(0.0f, 1.0f, 0.0f), distance);
|
||||
EXPECT_TRUE(rayHit);
|
||||
EXPECT_NEAR(distance, 0.03f, 1e-3f);
|
||||
}
|
||||
} // namespace UnitTest
|
||||
Loading…
Reference in New Issue