Merge pull request #7463 from aws-lumberyard-dev/box-manipulators-nus

Fixing various bugs with collider and box shape manipulators with non-uniform scale
monroegm-disable-blank-issue-2
greerdv 4 years ago committed by GitHub
commit 645dde9da0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -14,6 +14,8 @@
#include <AzToolsFramework/Manipulators/ManipulatorSnapping.h> #include <AzToolsFramework/Manipulators/ManipulatorSnapping.h>
#include <AzFramework/Viewport/ViewportColors.h> #include <AzFramework/Viewport/ViewportColors.h>
#include <AzFramework/Viewport/ViewportConstants.h> #include <AzFramework/Viewport/ViewportConstants.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Component/NonUniformScaleBus.h>
namespace AzToolsFramework namespace AzToolsFramework
{ {
@ -37,20 +39,20 @@ namespace AzToolsFramework
void BoxViewportEdit::UpdateManipulators() void BoxViewportEdit::UpdateManipulators()
{ {
AZ::Transform boxWorldFromLocal = AZ::Transform::CreateIdentity(); AZ::Transform boxWorldFromLocal = AZ::Transform::CreateIdentity();
BoxManipulatorRequestBus::EventResult( AZ::TransformBus::EventResult(
boxWorldFromLocal, m_entityComponentIdPair, &BoxManipulatorRequests::GetCurrentTransform); boxWorldFromLocal, m_entityComponentIdPair.GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
AZ::Vector3 boxScale = AZ::Vector3::CreateOne(); AZ::Vector3 nonUniformScale = AZ::Vector3::CreateOne();
BoxManipulatorRequestBus::EventResult( AZ::NonUniformScaleRequestBus::EventResult(
boxScale, m_entityComponentIdPair, &BoxManipulatorRequests::GetBoxScale); nonUniformScale, m_entityComponentIdPair.GetEntityId(), &AZ::NonUniformScaleRequestBus::Events::GetScale);
AZ::Vector3 boxDimensions = AZ::Vector3::CreateZero(); AZ::Vector3 boxDimensions = AZ::Vector3::CreateZero();
BoxManipulatorRequestBus::EventResult( BoxManipulatorRequestBus::EventResult(
boxDimensions, m_entityComponentIdPair, &BoxManipulatorRequests::GetDimensions); boxDimensions, m_entityComponentIdPair, &BoxManipulatorRequestBus::Events::GetDimensions);
// ensure we apply the entity scale to the box dimensions so AZ::Transform boxLocalTransform = AZ::Transform::CreateIdentity();
// the manipulators appear in the correct location BoxManipulatorRequestBus::EventResult(
boxDimensions *= boxScale; boxLocalTransform, m_entityComponentIdPair, &BoxManipulatorRequestBus::Events::GetCurrentLocalTransform);
for (size_t manipulatorIndex = 0; manipulatorIndex < m_linearManipulators.size(); ++manipulatorIndex) for (size_t manipulatorIndex = 0; manipulatorIndex < m_linearManipulators.size(); ++manipulatorIndex)
{ {
@ -58,7 +60,8 @@ namespace AzToolsFramework
{ {
linearManipulator->SetSpace(boxWorldFromLocal); linearManipulator->SetSpace(boxWorldFromLocal);
linearManipulator->SetLocalTransform( linearManipulator->SetLocalTransform(
AZ::Transform::CreateTranslation(s_boxAxes[manipulatorIndex] * 0.5f * boxDimensions)); boxLocalTransform * AZ::Transform::CreateTranslation(s_boxAxes[manipulatorIndex] * 0.5f * boxDimensions));
linearManipulator->SetNonUniformScale(nonUniformScale);
linearManipulator->SetBoundsDirty(); linearManipulator->SetBoundsDirty();
} }
} }
@ -69,8 +72,8 @@ namespace AzToolsFramework
m_entityComponentIdPair = entityComponentIdPair; m_entityComponentIdPair = entityComponentIdPair;
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity(); AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
BoxManipulatorRequestBus::EventResult( AZ::TransformBus::EventResult(
worldFromLocal, entityComponentIdPair, &BoxManipulatorRequests::GetCurrentTransform); worldFromLocal, entityComponentIdPair.GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
for (size_t manipulatorIndex = 0; manipulatorIndex < m_linearManipulators.size(); ++manipulatorIndex) for (size_t manipulatorIndex = 0; manipulatorIndex < m_linearManipulators.size(); ++manipulatorIndex)
{ {
@ -85,36 +88,35 @@ namespace AzToolsFramework
ManipulatorViews views; ManipulatorViews views;
views.emplace_back(CreateManipulatorViewQuadBillboard( views.emplace_back(CreateManipulatorViewQuadBillboard(
AzFramework::ViewportColors::DefaultManipulatorHandleColor, AzFramework::ViewportConstants::DefaultManipulatorHandleSize)); AzFramework::ViewportColors::DefaultManipulatorHandleColor,
AzFramework::ViewportConstants::DefaultManipulatorHandleSize));
linearManipulator->SetViews(AZStd::move(views)); linearManipulator->SetViews(AZStd::move(views));
linearManipulator->InstallMouseMoveCallback( linearManipulator->InstallMouseMoveCallback(
[this, entityComponentIdPair]( [this, entityComponentIdPair,
const LinearManipulator::Action& action) transformScale{ linearManipulator->GetSpace().GetUniformScale() }](const LinearManipulator::Action& action)
{ {
AZ::Transform boxLocalTransform = AZ::Transform::CreateIdentity();
BoxManipulatorRequestBus::EventResult(
boxLocalTransform, entityComponentIdPair, &BoxManipulatorRequestBus::Events::GetCurrentLocalTransform);
const AZ::Vector3 manipulatorPosition = GetPositionInManipulatorFrame(transformScale, boxLocalTransform, action);
// calculate the amount of displacement along an axis this manipulator has moved // calculate the amount of displacement along an axis this manipulator has moved
// clamp movement so it cannot go negative based on axis direction // clamp movement so it cannot go negative based on axis direction
const AZ::Vector3 axisDisplacement = const AZ::Vector3 axisDisplacement =
action.LocalPosition().GetAbs() * 2.0f manipulatorPosition.GetAbs() * 2.0f
* AZ::GetMax<float>(0.0f, action.LocalPosition().GetNormalized().Dot(action.m_fixed.m_axis)); * AZ::GetMax(0.0f, manipulatorPosition.GetNormalized().Dot(action.m_fixed.m_axis));
AZ::Vector3 boxScale = AZ::Vector3::CreateOne();
BoxManipulatorRequestBus::EventResult(
boxScale, entityComponentIdPair, &BoxManipulatorRequests::GetBoxScale);
AZ::Vector3 boxDimensions = AZ::Vector3::CreateZero(); AZ::Vector3 boxDimensions = AZ::Vector3::CreateZero();
BoxManipulatorRequestBus::EventResult( BoxManipulatorRequestBus::EventResult(
boxDimensions, entityComponentIdPair, &BoxManipulatorRequests::GetDimensions); boxDimensions, entityComponentIdPair, &BoxManipulatorRequestBus::Events::GetDimensions);
// ensure we take into account the entity scale using the axis displacement
const AZ::Vector3 scaledAxisDisplacement =
axisDisplacement / boxScale;
// update dimensions - preserve dimensions not effected by this // update dimensions - preserve dimensions not effected by this
// axis, and update current axis displacement // axis, and update current axis displacement
BoxManipulatorRequestBus::Event( BoxManipulatorRequestBus::Event(
entityComponentIdPair, &BoxManipulatorRequests::SetDimensions, entityComponentIdPair, &BoxManipulatorRequestBus::Events::SetDimensions,
(NotAxis(action.m_fixed.m_axis) * boxDimensions).GetMax(scaledAxisDisplacement)); (NotAxis(action.m_fixed.m_axis) * boxDimensions).GetMax(axisDisplacement));
UpdateManipulators(); UpdateManipulators();
}); });
@ -137,4 +139,12 @@ namespace AzToolsFramework
} }
} }
} }
AZ::Vector3 GetPositionInManipulatorFrame(float worldUniformScale, const AZ::Transform& manipulatorLocalTransform,
const LinearManipulator::Action& action)
{
return manipulatorLocalTransform.GetInverse().TransformPoint(
action.m_start.m_localPosition +
action.m_current.m_localPositionOffset / AZ::GetClamp(worldUniformScale, AZ::MinTransformScale, AZ::MaxTransformScale));
}
} // namespace AzToolsFramework } // namespace AzToolsFramework

@ -31,4 +31,10 @@ namespace AzToolsFramework
using BoxManipulators = AZStd::array<AZStd::shared_ptr<LinearManipulator>, 6>; using BoxManipulators = AZStd::array<AZStd::shared_ptr<LinearManipulator>, 6>;
BoxManipulators m_linearManipulators; ///< Manipulators for editing box size. BoxManipulators m_linearManipulators; ///< Manipulators for editing box size.
}; };
/// Calculates the position of the manipulator in its own reference frame.
/// Removes the effects of the manipulator local transform, and accounts for world transform scale in
/// the action local offset.
AZ::Vector3 GetPositionInManipulatorFrame(float worldUniformScale, const AZ::Transform& manipulatorLocalTransform,
const LinearManipulator::Action& action);
} // namespace AzToolsFramework } // namespace AzToolsFramework

@ -26,11 +26,21 @@ namespace AzToolsFramework
virtual AZ::Vector3 GetDimensions() = 0; virtual AZ::Vector3 GetDimensions() = 0;
//! Set the X/Y/Z dimensions of the box shape/collider. //! Set the X/Y/Z dimensions of the box shape/collider.
virtual void SetDimensions(const AZ::Vector3& dimensions) = 0; virtual void SetDimensions(const AZ::Vector3& dimensions) = 0;
// O3DE_DEPRECATION_NOTICE(GHI-7572)
//! @deprecated Because non-uniform scale effects can be complex, it is recommended to separately use
//! AZ::TransformBus::Events::GetWorldTM, AZ::NonUniformScaleRequests::GetScale and GetCurrentLocalTransform
//! and combine their effects.
//! Get the transform of the box shape/collider. //! Get the transform of the box shape/collider.
//! This is used by \ref BoxComponentMode instead of the \ref \AZ::TransformBus //! This is used by \ref BoxComponentMode instead of the \ref \AZ::TransformBus
//! because a collider may have an additional translation/orientation offset from //! because a collider may have an additional translation/orientation offset from
//! the Entity transform. //! the Entity transform.
virtual AZ::Transform GetCurrentTransform() = 0; virtual AZ::Transform GetCurrentTransform() = 0;
//! Get the transform of the box relative to the entity.
virtual AZ::Transform GetCurrentLocalTransform() = 0;
// O3DE_DEPRECATION_NOTICE(GHI-7572)
//! @deprecated Because non-uniform scale effects can be complex, it is recommended to separately use
//! AZ::TransformBus::Events::GetWorldTM, AZ::NonUniformScaleRequests::GetScale and GetCurrentLocalTransform
//! and combine their effects.
//! Get the scale currently applied to the box. //! Get the scale currently applied to the box.
//! With the Box Shape, the largest x/y/z component is taken //! With the Box Shape, the largest x/y/z component is taken
//! so scale is always uniform, with colliders the scale may //! so scale is always uniform, with colliders the scale may

@ -161,6 +161,11 @@ namespace LmbrCentral
return AzToolsFramework::TransformNormalizedScale(m_aaboxShape.GetCurrentTransform()); return AzToolsFramework::TransformNormalizedScale(m_aaboxShape.GetCurrentTransform());
} }
AZ::Transform EditorAxisAlignedBoxShapeComponent::GetCurrentLocalTransform()
{
return AZ::Transform::CreateIdentity();
}
AZ::Vector3 EditorAxisAlignedBoxShapeComponent::GetBoxScale() AZ::Vector3 EditorAxisAlignedBoxShapeComponent::GetBoxScale()
{ {
return AZ::Vector3(m_aaboxShape.GetCurrentTransform().GetUniformScale() * m_aaboxShape.GetCurrentNonUniformScale()); return AZ::Vector3(m_aaboxShape.GetCurrentTransform().GetUniformScale() * m_aaboxShape.GetCurrentNonUniformScale());

@ -58,6 +58,7 @@ namespace LmbrCentral
AZ::Vector3 GetDimensions() override; AZ::Vector3 GetDimensions() override;
void SetDimensions(const AZ::Vector3& dimensions) override; void SetDimensions(const AZ::Vector3& dimensions) override;
AZ::Transform GetCurrentTransform() override; AZ::Transform GetCurrentTransform() override;
AZ::Transform GetCurrentLocalTransform() override;
AZ::Vector3 GetBoxScale() override; AZ::Vector3 GetBoxScale() override;
void ConfigurationChanged(); void ConfigurationChanged();

@ -167,6 +167,11 @@ namespace LmbrCentral
return AzToolsFramework::TransformNormalizedScale(m_boxShape.GetCurrentTransform()); return AzToolsFramework::TransformNormalizedScale(m_boxShape.GetCurrentTransform());
} }
AZ::Transform EditorBoxShapeComponent::GetCurrentLocalTransform()
{
return AZ::Transform::CreateIdentity();
}
AZ::Vector3 EditorBoxShapeComponent::GetBoxScale() AZ::Vector3 EditorBoxShapeComponent::GetBoxScale()
{ {
return AZ::Vector3(m_boxShape.GetCurrentTransform().GetUniformScale() * m_boxShape.GetCurrentNonUniformScale()); return AZ::Vector3(m_boxShape.GetCurrentTransform().GetUniformScale() * m_boxShape.GetCurrentNonUniformScale());

@ -57,6 +57,7 @@ namespace LmbrCentral
AZ::Vector3 GetDimensions() override; AZ::Vector3 GetDimensions() override;
void SetDimensions(const AZ::Vector3& dimensions) override; void SetDimensions(const AZ::Vector3& dimensions) override;
AZ::Transform GetCurrentTransform() override; AZ::Transform GetCurrentTransform() override;
AZ::Transform GetCurrentLocalTransform() override;
AZ::Vector3 GetBoxScale() override; AZ::Vector3 GetBoxScale() override;
void ConfigurationChanged(); void ConfigurationChanged();

@ -7,6 +7,17 @@
*/ */
#include "LmbrCentralReflectionTest.h" #include "LmbrCentralReflectionTest.h"
#include "Shape/EditorBoxShapeComponent.h" #include "Shape/EditorBoxShapeComponent.h"
#include "Shape/EditorSphereShapeComponent.h"
#include <AzCore/Component/NonUniformScaleBus.h>
#include <AzFramework/Viewport/ViewportScreen.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFramework.h>
#include <AzManipulatorTestFramework/AzManipulatorTestFrameworkTestHelpers.h>
#include <AzManipulatorTestFramework/ImmediateModeActionDispatcher.h>
#include <AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h>
#include <AzManipulatorTestFramework/ViewportInteraction.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
#include <AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.h>
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
namespace LmbrCentral namespace LmbrCentral
{ {
@ -56,5 +67,110 @@ namespace LmbrCentral
EXPECT_EQ(dimensions, AZ::Vector3(0.37f, 0.57f, 0.66f)); EXPECT_EQ(dimensions, AZ::Vector3(0.37f, 0.57f, 0.66f));
} }
class EditorBoxShapeComponentFixture : public UnitTest::ToolsApplicationFixture
{
public:
void SetUpEditorFixtureImpl() override;
void TearDownEditorFixtureImpl() override;
AZStd::unique_ptr<AZ::ComponentDescriptor> m_editorBoxShapeComponentDescriptor;
AZStd::unique_ptr<AZ::ComponentDescriptor> m_editorSphereShapeComponentDescriptor;
AZ::Entity* m_entity = nullptr;
};
void EditorBoxShapeComponentFixture::SetUpEditorFixtureImpl()
{
AZ::SerializeContext* serializeContext = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
// need to reflect EditorSphereShapeComponent in order for EditorBaseShapeComponent to be reflected
m_editorSphereShapeComponentDescriptor = AZStd::unique_ptr<AZ::ComponentDescriptor>(EditorSphereShapeComponent::CreateDescriptor());
m_editorBoxShapeComponentDescriptor =
AZStd::unique_ptr<AZ::ComponentDescriptor>(EditorBoxShapeComponent::CreateDescriptor());
ShapeComponentConfig::Reflect(serializeContext);
BoxShape::Reflect(serializeContext);
m_editorSphereShapeComponentDescriptor->Reflect(serializeContext);
m_editorBoxShapeComponentDescriptor->Reflect(serializeContext);
UnitTest::CreateDefaultEditorEntity("BoxShapeComponentEntity", &m_entity);
m_entity->Deactivate();
m_entity->CreateComponent(AzToolsFramework::Components::EditorNonUniformScaleComponent::RTTI_Type());
m_entity->CreateComponent(EditorBoxShapeComponentTypeId);
m_entity->Activate();
}
void EditorBoxShapeComponentFixture::TearDownEditorFixtureImpl()
{
AzToolsFramework::EditorEntityContextRequestBus::Broadcast(
&AzToolsFramework::EditorEntityContextRequestBus::Events::DestroyEditorEntity, m_entity->GetId());
m_entity = nullptr;
m_editorBoxShapeComponentDescriptor.reset();
m_editorSphereShapeComponentDescriptor.reset();
}
using EditorBoxShapeComponentManipulatorFixture =
UnitTest::IndirectCallManipulatorViewportInteractionFixtureMixin<EditorBoxShapeComponentFixture>;
TEST_F(EditorBoxShapeComponentManipulatorFixture, BoxShapeNonUniformScaleManipulatorsScaleCorrectly)
{
// a rotation which rotates the x-axis to (0.8, 0.6, 0)
const AZ::Quaternion boxRotation(0.0f, 0.0f, 0.316228f, 0.948683f);
AZ::Transform boxTransform = AZ::Transform::CreateFromQuaternionAndTranslation(boxRotation, AZ::Vector3(2.0f, 3.0f, 4.0f));
boxTransform.SetUniformScale(1.5f);
AZ::TransformBus::Event(m_entity->GetId(), &AZ::TransformBus::Events::SetWorldTM, boxTransform);
const AZ::Vector3 nonUniformScale(4.0f, 1.5f, 2.0f);
AZ::NonUniformScaleRequestBus::Event(m_entity->GetId(), &AZ::NonUniformScaleRequests::SetScale, nonUniformScale);
const AZ::Vector3 boxDimensions(1.0f, 2.0f, 2.5f);
BoxShapeComponentRequestsBus::Event(m_entity->GetId(), &BoxShapeComponentRequests::SetBoxDimensions, boxDimensions);
// enter the box shape component's component mode
AzToolsFramework::SelectEntity(m_entity->GetId());
AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Broadcast(
&AzToolsFramework::ComponentModeFramework::ComponentModeSystemRequestBus::Events::AddSelectedComponentModesOfType,
EditorBoxShapeComponentTypeId);
// position the camera so it is looking down at the box
AzFramework::SetCameraTransform(
m_cameraState,
AZ::Transform::CreateFromQuaternionAndTranslation(
AZ::Quaternion::CreateRotationX(-AZ::Constants::HalfPi), AZ::Vector3(2.0f, 3.0f, 20.0f)));
// position in world space which should allow grabbing the box's x scale manipulator
// the unscaled position of the x scale manipulator in the box's local frame should be (0.5f, 0.0f, 0.0f)
// after non-uniform scale, the manipulator position should be (2.0f, 0.0f, 0.0f)
// after the scale of the entity transform, the manipulator position should be (3.0f, 0.0f, 0.0f)
// after the rotation of the entity transform, the manipulator position should be (2.4f, 1.8f, 0.0f)
// after the translation of the entity transform, the manipulator position should be (4.4f, 4.8f, 4.0f)
const AZ::Vector3 worldStart(4.4f, 4.8f, 4.0f);
// position in world space to move to
const AZ::Vector3 worldEnd(6.8f, 6.6f, 4.0f);
const auto screenStart = AzFramework::WorldToScreen(worldStart, m_cameraState);
const auto screenEnd = AzFramework::WorldToScreen(worldEnd, m_cameraState);
m_actionDispatcher
->CameraState(m_cameraState)
// move the mouse to the position of the x scale manipulator
->MousePosition(screenStart)
// drag to move the manipulator
->MouseLButtonDown()
->MousePosition(screenEnd)
->MouseLButtonUp();
AZ::Vector3 newBoxDimensions = AZ::Vector3::CreateZero();
BoxShapeComponentRequestsBus::EventResult(newBoxDimensions, m_entity->GetId(), &BoxShapeComponentRequests::GetBoxDimensions);
const AZ::Vector3 expectedBoxDimensions(2.0f, 2.0f, 2.5f);
// allow a reasonably high tolerance because we can't get better accuracy than the resolution of the viewport
EXPECT_THAT(newBoxDimensions, UnitTest::IsCloseTolerance(expectedBoxDimensions, 1e-2f));
}
} }

@ -8,11 +8,14 @@
#include "ColliderCapsuleMode.h" #include "ColliderCapsuleMode.h"
#include <PhysX/EditorColliderComponentRequestBus.h> #include <PhysX/EditorColliderComponentRequestBus.h>
#include <Source/Utils.h>
#include <AzToolsFramework/Manipulators/LinearManipulator.h> #include <AzToolsFramework/Manipulators/LinearManipulator.h>
#include <AzToolsFramework/Manipulators/ManipulatorManager.h> #include <AzToolsFramework/Manipulators/ManipulatorManager.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h> #include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <AzToolsFramework/ComponentModes/BoxViewportEdit.h>
#include <AzCore/Component/TransformBus.h> #include <AzCore/Component/TransformBus.h>
#include <AzCore/Component/NonUniformScaleBus.h>
#include <AzFramework/Viewport/ViewportColors.h> #include <AzFramework/Viewport/ViewportColors.h>
#include <AzFramework/Viewport/ViewportConstants.h> #include <AzFramework/Viewport/ViewportConstants.h>
@ -34,10 +37,15 @@ namespace PhysX
void ColliderCapsuleMode::Setup(const AZ::EntityComponentIdPair& idPair) void ColliderCapsuleMode::Setup(const AZ::EntityComponentIdPair& idPair)
{ {
AZ::Transform colliderWorldTransform = AZ::Transform::Identity(); AZ::Transform colliderWorldTransform = AZ::Transform::Identity();
PhysX::EditorColliderComponentRequestBus::EventResult(colliderWorldTransform, idPair, &PhysX::EditorColliderComponentRequests::GetColliderWorldTransform); AZ::TransformBus::EventResult(colliderWorldTransform, idPair.GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
SetupRadiusManipulator(idPair, colliderWorldTransform); AZ::Vector3 nonUniformScale = AZ::Vector3::CreateOne();
SetupHeightManipulator(idPair, colliderWorldTransform); AZ::NonUniformScaleRequestBus::EventResult(nonUniformScale, idPair.GetEntityId(), &AZ::NonUniformScaleRequests::GetScale);
const AZ::Transform colliderLocalTransform = Utils::GetColliderLocalTransform(idPair);
SetupRadiusManipulator(idPair, colliderWorldTransform, colliderLocalTransform, nonUniformScale);
SetupHeightManipulator(idPair, colliderWorldTransform, colliderLocalTransform, nonUniformScale);
AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(idPair.GetEntityId()); AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(idPair.GetEntityId());
} }
@ -45,7 +53,12 @@ namespace PhysX
void ColliderCapsuleMode::Refresh(const AZ::EntityComponentIdPair& idPair) void ColliderCapsuleMode::Refresh(const AZ::EntityComponentIdPair& idPair)
{ {
AZ::Transform colliderWorldTransform = AZ::Transform::Identity(); AZ::Transform colliderWorldTransform = AZ::Transform::Identity();
PhysX::EditorColliderComponentRequestBus::EventResult(colliderWorldTransform, idPair, &PhysX::EditorColliderComponentRequests::GetColliderWorldTransform); AZ::TransformBus::EventResult(colliderWorldTransform, idPair.GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
AZ::Vector3 nonUniformScale = AZ::Vector3::CreateOne();
AZ::NonUniformScaleRequestBus::EventResult(nonUniformScale, idPair.GetEntityId(), &AZ::NonUniformScaleRequests::GetScale);
AZ::Transform colliderLocalTransform = Utils::GetColliderLocalTransform(idPair);
// Read the state of the capsule into manipulators to support undo/redo // Read the state of the capsule into manipulators to support undo/redo
float capsuleHeight = 0.0f; float capsuleHeight = 0.0f;
@ -55,9 +68,13 @@ namespace PhysX
PhysX::EditorColliderComponentRequestBus::EventResult(capsuleRadius, idPair, &PhysX::EditorColliderComponentRequests::GetCapsuleRadius); PhysX::EditorColliderComponentRequestBus::EventResult(capsuleRadius, idPair, &PhysX::EditorColliderComponentRequests::GetCapsuleRadius);
m_radiusManipulator->SetSpace(colliderWorldTransform); m_radiusManipulator->SetSpace(colliderWorldTransform);
m_radiusManipulator->SetLocalPosition(m_radiusManipulator->GetAxis() * capsuleRadius); m_radiusManipulator->SetLocalTransform(
colliderLocalTransform * AZ::Transform::CreateTranslation(m_radiusManipulator->GetAxis() * capsuleRadius));
m_radiusManipulator->SetNonUniformScale(nonUniformScale);
m_heightManipulator->SetSpace(colliderWorldTransform); m_heightManipulator->SetSpace(colliderWorldTransform);
m_heightManipulator->SetLocalPosition(m_heightManipulator->GetAxis() * capsuleHeight * HalfHeight); m_heightManipulator->SetLocalTransform(
colliderLocalTransform * AZ::Transform::CreateTranslation(m_heightManipulator->GetAxis() * capsuleHeight * HalfHeight));
m_heightManipulator->SetNonUniformScale(nonUniformScale);
} }
void ColliderCapsuleMode::Teardown(const AZ::EntityComponentIdPair& idPair) void ColliderCapsuleMode::Teardown(const AZ::EntityComponentIdPair& idPair)
@ -83,13 +100,23 @@ namespace PhysX
AZ_UNUSED(debugDisplay); AZ_UNUSED(debugDisplay);
const AzFramework::CameraState cameraState = AzToolsFramework::GetCameraState(viewportInfo.m_viewportId); const AzFramework::CameraState cameraState = AzToolsFramework::GetCameraState(viewportInfo.m_viewportId);
float radius = m_radiusManipulator->GetLocalPosition().GetLength();
m_radiusManipulator->SetAxis(cameraState.m_side); if (!m_radiusManipulator->EntityComponentIdPairs().empty())
m_radiusManipulator->SetLocalPosition(cameraState.m_side * radius); {
const AZ::EntityComponentIdPair idPair = *m_radiusManipulator->EntityComponentIdPairs().begin();
float radius = 0.0f;
PhysX::EditorColliderComponentRequestBus::EventResult(radius, idPair, &PhysX::EditorColliderComponentRequests::GetCapsuleRadius);
const AZ::Transform colliderLocalTransform = Utils::GetColliderLocalTransform(idPair);
m_radiusManipulator->SetAxis(cameraState.m_side);
m_radiusManipulator->SetLocalTransform(colliderLocalTransform * AZ::Transform::CreateTranslation(cameraState.m_side * radius));
}
} }
void ColliderCapsuleMode::SetupRadiusManipulator(const AZ::EntityComponentIdPair& idPair, const AZ::Transform& worldTransform) void ColliderCapsuleMode::SetupRadiusManipulator(
const AZ::EntityComponentIdPair& idPair,
const AZ::Transform& worldTransform,
const AZ::Transform& localTransform,
const AZ::Vector3& nonUniformScale)
{ {
// Radius manipulator // Radius manipulator
float capsuleRadius = 0.0f; float capsuleRadius = 0.0f;
@ -99,7 +126,8 @@ namespace PhysX
m_radiusManipulator->AddEntityComponentIdPair(idPair); m_radiusManipulator->AddEntityComponentIdPair(idPair);
m_radiusManipulator->SetAxis(RadiusManipulatorAxis); m_radiusManipulator->SetAxis(RadiusManipulatorAxis);
m_radiusManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); m_radiusManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId);
m_radiusManipulator->SetLocalPosition(RadiusManipulatorAxis * capsuleRadius); m_radiusManipulator->SetLocalTransform(localTransform * AZ::Transform::CreateTranslation(RadiusManipulatorAxis * capsuleRadius));
m_radiusManipulator->SetNonUniformScale(nonUniformScale);
{ {
AzToolsFramework::ManipulatorViews views; AzToolsFramework::ManipulatorViews views;
@ -114,7 +142,11 @@ namespace PhysX
}); });
} }
void ColliderCapsuleMode::SetupHeightManipulator(const AZ::EntityComponentIdPair& idPair, const AZ::Transform& worldTransform) void ColliderCapsuleMode::SetupHeightManipulator(
const AZ::EntityComponentIdPair& idPair,
const AZ::Transform& worldTransform,
const AZ::Transform& localTransform,
const AZ::Vector3& nonUniformScale)
{ {
// Height manipulator // Height manipulator
float capsuleHeight = 0.0f; float capsuleHeight = 0.0f;
@ -124,7 +156,9 @@ namespace PhysX
m_heightManipulator->AddEntityComponentIdPair(idPair); m_heightManipulator->AddEntityComponentIdPair(idPair);
m_heightManipulator->SetAxis(HeightManipulatorAxis); m_heightManipulator->SetAxis(HeightManipulatorAxis);
m_heightManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); m_heightManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId);
m_heightManipulator->SetLocalPosition(HeightManipulatorAxis * capsuleHeight * HalfHeight); // Manipulator positioned at half the capsules height. m_heightManipulator->SetLocalTransform(
localTransform * AZ::Transform::CreateTranslation(HeightManipulatorAxis * capsuleHeight * HalfHeight));
m_heightManipulator->SetNonUniformScale(nonUniformScale);
{ {
AzToolsFramework::ManipulatorViews views; AzToolsFramework::ManipulatorViews views;
@ -137,19 +171,23 @@ namespace PhysX
{ {
OnHeightManipulatorMoved(action, idPair); OnHeightManipulatorMoved(action, idPair);
}); });
} }
void ColliderCapsuleMode::OnRadiusManipulatorMoved(const AzToolsFramework::LinearManipulator::Action& action, const AZ::EntityComponentIdPair& idPair) void ColliderCapsuleMode::OnRadiusManipulatorMoved(const AzToolsFramework::LinearManipulator::Action& action, const AZ::EntityComponentIdPair& idPair)
{ {
// manipulator action offsets do not take entity transform scale into account, so need to apply it here
const AZ::Transform colliderLocalTransform = Utils::GetColliderLocalTransform(idPair);
const AZ::Vector3 manipulatorPosition = AzToolsFramework::GetPositionInManipulatorFrame(
m_radiusManipulator->GetSpace().GetUniformScale(), colliderLocalTransform, action);
// Get the distance the manipulator has moved along the axis. // Get the distance the manipulator has moved along the axis.
float extent = action.LocalPosition().Dot(action.m_fixed.m_axis); float extent = manipulatorPosition.Dot(action.m_fixed.m_axis);
// Clamp radius to a small value. // Clamp radius to a small value.
extent = AZ::GetMax(extent, MinCapsuleRadius); extent = AZ::GetMax(extent, MinCapsuleRadius);
// Update the manipulator and capsule radius. // Update the manipulator and capsule radius.
m_radiusManipulator->SetLocalPosition(extent * action.m_fixed.m_axis); m_radiusManipulator->SetLocalTransform(colliderLocalTransform * AZ::Transform::CreateTranslation(extent * action.m_fixed.m_axis));
// Adjust the height manipulator so it is always clamped to twice the radius. // Adjust the height manipulator so it is always clamped to twice the radius.
AdjustHeightManipulator(idPair, static_cast<float>(extent)); AdjustHeightManipulator(idPair, static_cast<float>(extent));
@ -160,14 +198,19 @@ namespace PhysX
void ColliderCapsuleMode::OnHeightManipulatorMoved(const AzToolsFramework::LinearManipulator::Action& action, const AZ::EntityComponentIdPair& idPair) void ColliderCapsuleMode::OnHeightManipulatorMoved(const AzToolsFramework::LinearManipulator::Action& action, const AZ::EntityComponentIdPair& idPair)
{ {
// manipulator action offsets do not take entity transform scale into account, so need to apply it here
const AZ::Transform colliderLocalTransform = Utils::GetColliderLocalTransform(idPair);
const AZ::Vector3 manipulatorPosition = AzToolsFramework::GetPositionInManipulatorFrame(
m_heightManipulator->GetSpace().GetUniformScale(), colliderLocalTransform, action);
// Get the distance the manipulator has moved along the axis. // Get the distance the manipulator has moved along the axis.
float extent = action.LocalPosition().Dot(action.m_fixed.m_axis); float extent = manipulatorPosition.Dot(action.m_fixed.m_axis);
// Ensure capsule's half height is always greater than the radius. // Ensure capsule's half height is always greater than the radius.
extent = AZ::GetMax(extent, MinCapsuleHeight); extent = AZ::GetMax(extent, MinCapsuleHeight);
// Update the manipulator and capsule height. // Update the manipulator and capsule height.
m_heightManipulator->SetLocalPosition(extent * action.m_fixed.m_axis); m_heightManipulator->SetLocalTransform(colliderLocalTransform * AZ::Transform::CreateTranslation(extent * action.m_fixed.m_axis));
// The final height of the capsule is twice the manipulator's extent. // The final height of the capsule is twice the manipulator's extent.
float capsuleHeight = extent / HalfHeight; float capsuleHeight = extent / HalfHeight;
@ -188,7 +231,9 @@ namespace PhysX
capsuleRadius = AZ::GetMin(capsuleRadius, capsuleHeight * HalfHeight); capsuleRadius = AZ::GetMin(capsuleRadius, capsuleHeight * HalfHeight);
// Update manipulator and the capsule radius. // Update manipulator and the capsule radius.
m_radiusManipulator->SetLocalPosition(capsuleRadius * m_radiusManipulator->GetAxis()); const AZ::Transform colliderLocalTransform = Utils::GetColliderLocalTransform(idPair);
m_radiusManipulator->SetLocalTransform(
colliderLocalTransform * AZ::Transform::CreateTranslation(capsuleRadius * m_radiusManipulator->GetAxis()));
PhysX::EditorColliderComponentRequestBus::Event(idPair, &PhysX::EditorColliderComponentRequests::SetCapsuleRadius, capsuleRadius); PhysX::EditorColliderComponentRequestBus::Event(idPair, &PhysX::EditorColliderComponentRequests::SetCapsuleRadius, capsuleRadius);
} }
@ -201,7 +246,9 @@ namespace PhysX
capsuleHeight = AZ::GetMax(capsuleHeight, capsuleRadius / HalfHeight); capsuleHeight = AZ::GetMax(capsuleHeight, capsuleRadius / HalfHeight);
// Update the manipulator and capsule height. // Update the manipulator and capsule height.
m_heightManipulator->SetLocalPosition(capsuleHeight * HalfHeight * m_heightManipulator->GetAxis()); const AZ::Transform colliderLocalTransform = Utils::GetColliderLocalTransform(idPair);
m_heightManipulator->SetLocalTransform(
colliderLocalTransform * AZ::Transform::CreateTranslation(capsuleHeight * HalfHeight * m_heightManipulator->GetAxis()));
PhysX::EditorColliderComponentRequestBus::Event(idPair, &PhysX::EditorColliderComponentRequests::SetCapsuleHeight, capsuleHeight); PhysX::EditorColliderComponentRequestBus::Event(idPair, &PhysX::EditorColliderComponentRequests::SetCapsuleHeight, capsuleHeight);
} }
} }

@ -34,8 +34,16 @@ namespace PhysX
const AzFramework::ViewportInfo& viewportInfo, const AzFramework::ViewportInfo& viewportInfo,
AzFramework::DebugDisplayRequests& debugDisplay) override; AzFramework::DebugDisplayRequests& debugDisplay) override;
void SetupRadiusManipulator(const AZ::EntityComponentIdPair& idPair, const AZ::Transform& worldTransform); void SetupRadiusManipulator(
void SetupHeightManipulator(const AZ::EntityComponentIdPair& idPair, const AZ::Transform& worldTransform); const AZ::EntityComponentIdPair& idPair,
const AZ::Transform& worldTransform,
const AZ::Transform& localTransform,
const AZ::Vector3& nonUniformScale);
void SetupHeightManipulator(
const AZ::EntityComponentIdPair& idPair,
const AZ::Transform& worldTransform,
const AZ::Transform& localTransform,
const AZ::Vector3& nonUniformScale);
void OnRadiusManipulatorMoved(const AzToolsFramework::LinearManipulator::Action& action, const AZ::EntityComponentIdPair& idPair); void OnRadiusManipulatorMoved(const AzToolsFramework::LinearManipulator::Action& action, const AZ::EntityComponentIdPair& idPair);
void OnHeightManipulatorMoved(const AzToolsFramework::LinearManipulator::Action& action, const AZ::EntityComponentIdPair& idPair); void OnHeightManipulatorMoved(const AzToolsFramework::LinearManipulator::Action& action, const AZ::EntityComponentIdPair& idPair);
void AdjustRadiusManipulator(const AZ::EntityComponentIdPair& idPair, const float capsuleHeight); void AdjustRadiusManipulator(const AZ::EntityComponentIdPair& idPair, const float capsuleHeight);

@ -10,6 +10,7 @@
#include <PhysX/EditorColliderComponentRequestBus.h> #include <PhysX/EditorColliderComponentRequestBus.h>
#include <AzToolsFramework/Manipulators/ManipulatorManager.h> #include <AzToolsFramework/Manipulators/ManipulatorManager.h>
#include <AzCore/Component/NonUniformScaleBus.h>
#include <AzCore/Component/TransformBus.h> #include <AzCore/Component/TransformBus.h>
#include <AzCore/Component/ComponentBus.h> #include <AzCore/Component/ComponentBus.h>
@ -28,10 +29,14 @@ namespace PhysX
AZ::Transform worldTransform; AZ::Transform worldTransform;
AZ::TransformBus::EventResult(worldTransform, idPair.GetEntityId(), &AZ::TransformInterface::GetWorldTM); AZ::TransformBus::EventResult(worldTransform, idPair.GetEntityId(), &AZ::TransformInterface::GetWorldTM);
AZ::Vector3 nonUniformScale = AZ::Vector3::CreateOne();
AZ::NonUniformScaleRequestBus::EventResult(nonUniformScale, idPair.GetEntityId(), &AZ::NonUniformScaleRequests::GetScale);
AZ::Vector3 colliderOffset; AZ::Vector3 colliderOffset;
PhysX::EditorColliderComponentRequestBus::EventResult(colliderOffset, idPair, &PhysX::EditorColliderComponentRequests::GetColliderOffset); PhysX::EditorColliderComponentRequestBus::EventResult(colliderOffset, idPair, &PhysX::EditorColliderComponentRequests::GetColliderOffset);
m_translationManipulators.SetSpace(worldTransform); m_translationManipulators.SetSpace(worldTransform);
m_translationManipulators.SetNonUniformScale(nonUniformScale);
m_translationManipulators.SetLocalPosition(colliderOffset); m_translationManipulators.SetLocalPosition(colliderOffset);
m_translationManipulators.AddEntityComponentIdPair(idPair); m_translationManipulators.AddEntityComponentIdPair(idPair);
m_translationManipulators.Register(AzToolsFramework::g_mainManipulatorManagerId); m_translationManipulators.Register(AzToolsFramework::g_mainManipulatorManagerId);
@ -40,19 +45,19 @@ namespace PhysX
m_translationManipulators.InstallLinearManipulatorMouseMoveCallback([this, idPair]( m_translationManipulators.InstallLinearManipulatorMouseMoveCallback([this, idPair](
const AzToolsFramework::LinearManipulator::Action& action) const AzToolsFramework::LinearManipulator::Action& action)
{ {
OnManipulatorMoved(action.LocalPosition(), idPair); OnManipulatorMoved(action.m_start.m_localPosition, action.m_current.m_localPositionOffset, idPair);
}); });
m_translationManipulators.InstallPlanarManipulatorMouseMoveCallback([this, idPair]( m_translationManipulators.InstallPlanarManipulatorMouseMoveCallback([this, idPair](
const AzToolsFramework::PlanarManipulator::Action& action) const AzToolsFramework::PlanarManipulator::Action& action)
{ {
OnManipulatorMoved(action.LocalPosition(), idPair); OnManipulatorMoved(action.m_start.m_localPosition, action.m_current.m_localOffset, idPair);
}); });
m_translationManipulators.InstallSurfaceManipulatorMouseMoveCallback([this, idPair]( m_translationManipulators.InstallSurfaceManipulatorMouseMoveCallback([this, idPair](
const AzToolsFramework::SurfaceManipulator::Action& action) const AzToolsFramework::SurfaceManipulator::Action& action)
{ {
OnManipulatorMoved(action.LocalPosition(), idPair); OnManipulatorMoved(action.m_start.m_localPosition, action.m_current.m_localOffset, idPair);
}); });
} }
@ -69,10 +74,14 @@ namespace PhysX
m_translationManipulators.Unregister(); m_translationManipulators.Unregister();
} }
void ColliderOffsetMode::OnManipulatorMoved(const AZ::Vector3& position, const AZ::EntityComponentIdPair& idPair) void ColliderOffsetMode::OnManipulatorMoved(const AZ::Vector3& startPosition, const AZ::Vector3& offset, const AZ::EntityComponentIdPair& idPair)
{ {
m_translationManipulators.SetLocalPosition(position); AZ::Transform worldTransform = AZ::Transform::CreateIdentity();
PhysX::EditorColliderComponentRequestBus::Event(idPair, &PhysX::EditorColliderComponentRequests::SetColliderOffset, position); AZ::TransformBus::EventResult(worldTransform, idPair.GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
const float scale = AZ::GetMax(AZ::MinTransformScale, worldTransform.GetUniformScale());
const AZ::Vector3 newPosition = startPosition + offset / scale;
m_translationManipulators.SetLocalPosition(newPosition);
PhysX::EditorColliderComponentRequestBus::Event(idPair, &PhysX::EditorColliderComponentRequests::SetColliderOffset, newPosition);
} }
void ColliderOffsetMode::ResetValues(const AZ::EntityComponentIdPair& idPair) void ColliderOffsetMode::ResetValues(const AZ::EntityComponentIdPair& idPair)

@ -28,7 +28,8 @@ namespace PhysX
void ResetValues(const AZ::EntityComponentIdPair& idPair) override; void ResetValues(const AZ::EntityComponentIdPair& idPair) override;
private: private:
void OnManipulatorMoved(const AZ::Vector3& position, const AZ::EntityComponentIdPair& idPair); void OnManipulatorMoved(
const AZ::Vector3& startPosition, const AZ::Vector3& offset, const AZ::EntityComponentIdPair& idPair);
AzToolsFramework::TranslationManipulators m_translationManipulators; AzToolsFramework::TranslationManipulators m_translationManipulators;
}; };

@ -10,6 +10,7 @@
#include <PhysX/EditorColliderComponentRequestBus.h> #include <PhysX/EditorColliderComponentRequestBus.h>
#include <AzToolsFramework/Manipulators/ManipulatorManager.h> #include <AzToolsFramework/Manipulators/ManipulatorManager.h>
#include <AzCore/Component/TransformBus.h> #include <AzCore/Component/TransformBus.h>
#include <AzCore/Component/NonUniformScaleBus.h>
#include <AzFramework/Viewport/ViewportColors.h> #include <AzFramework/Viewport/ViewportColors.h>
#include <AzToolsFramework/Manipulators/AngularManipulator.h> #include <AzToolsFramework/Manipulators/AngularManipulator.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h> #include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
@ -29,6 +30,9 @@ namespace PhysX
AZ::Transform worldTransform; AZ::Transform worldTransform;
AZ::TransformBus::EventResult(worldTransform, idPair.GetEntityId(), &AZ::TransformInterface::GetWorldTM); AZ::TransformBus::EventResult(worldTransform, idPair.GetEntityId(), &AZ::TransformInterface::GetWorldTM);
AZ::Vector3 nonUniformScale = AZ::Vector3::CreateOne();
AZ::NonUniformScaleRequestBus::EventResult(nonUniformScale, idPair.GetEntityId(), &AZ::NonUniformScaleRequests::GetScale);
AZ::Quaternion colliderRotation; AZ::Quaternion colliderRotation;
PhysX::EditorColliderComponentRequestBus::EventResult(colliderRotation, idPair, &PhysX::EditorColliderComponentRequests::GetColliderRotation); PhysX::EditorColliderComponentRequestBus::EventResult(colliderRotation, idPair, &PhysX::EditorColliderComponentRequests::GetColliderRotation);
@ -36,7 +40,8 @@ namespace PhysX
PhysX::EditorColliderComponentRequestBus::EventResult(colliderOffset, idPair, &PhysX::EditorColliderComponentRequests::GetColliderOffset); PhysX::EditorColliderComponentRequestBus::EventResult(colliderOffset, idPair, &PhysX::EditorColliderComponentRequests::GetColliderOffset);
m_rotationManipulators.SetSpace(worldTransform); m_rotationManipulators.SetSpace(worldTransform);
m_rotationManipulators.SetLocalPosition(colliderOffset); m_rotationManipulators.SetNonUniformScale(nonUniformScale);
m_rotationManipulators.SetLocalPosition(nonUniformScale * colliderOffset);
m_rotationManipulators.SetLocalOrientation(colliderRotation); m_rotationManipulators.SetLocalOrientation(colliderRotation);
m_rotationManipulators.AddEntityComponentIdPair(idPair); m_rotationManipulators.AddEntityComponentIdPair(idPair);
m_rotationManipulators.Register(AzToolsFramework::g_mainManipulatorManagerId); m_rotationManipulators.Register(AzToolsFramework::g_mainManipulatorManagerId);
@ -70,7 +75,11 @@ namespace PhysX
AZ::Vector3 colliderOffset = AZ::Vector3::CreateZero(); AZ::Vector3 colliderOffset = AZ::Vector3::CreateZero();
PhysX::EditorColliderComponentRequestBus::EventResult(colliderOffset, idPair, &PhysX::EditorColliderComponentRequests::GetColliderOffset); PhysX::EditorColliderComponentRequestBus::EventResult(colliderOffset, idPair, &PhysX::EditorColliderComponentRequests::GetColliderOffset);
m_rotationManipulators.SetLocalPosition(colliderOffset);
AZ::Vector3 nonUniformScale = AZ::Vector3::CreateOne();
AZ::NonUniformScaleRequestBus::EventResult(nonUniformScale, idPair.GetEntityId(), &AZ::NonUniformScaleRequests::GetScale);
m_rotationManipulators.SetLocalPosition(nonUniformScale * colliderOffset);
} }
void ColliderRotationMode::Teardown(const AZ::EntityComponentIdPair& idPair) void ColliderRotationMode::Teardown(const AZ::EntityComponentIdPair& idPair)

@ -8,11 +8,14 @@
#include "ColliderSphereMode.h" #include "ColliderSphereMode.h"
#include <PhysX/EditorColliderComponentRequestBus.h> #include <PhysX/EditorColliderComponentRequestBus.h>
#include <Source/Utils.h>
#include <AzToolsFramework/Manipulators/LinearManipulator.h> #include <AzToolsFramework/Manipulators/LinearManipulator.h>
#include <AzToolsFramework/Manipulators/ManipulatorManager.h> #include <AzToolsFramework/Manipulators/ManipulatorManager.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h> #include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <AzToolsFramework/ComponentModes/BoxViewportEdit.h>
#include <AzCore/Component/TransformBus.h> #include <AzCore/Component/TransformBus.h>
#include <AzCore/Component/NonUniformScaleBus.h>
#include <AzCore/Math/ToString.h> #include <AzCore/Math/ToString.h>
#include <AzFramework/Viewport/ViewportColors.h> #include <AzFramework/Viewport/ViewportColors.h>
#include <AzFramework/Viewport/ViewportConstants.h> #include <AzFramework/Viewport/ViewportConstants.h>
@ -27,7 +30,12 @@ namespace PhysX
void ColliderSphereMode::Setup(const AZ::EntityComponentIdPair& idPair) void ColliderSphereMode::Setup(const AZ::EntityComponentIdPair& idPair)
{ {
AZ::Transform colliderWorldTransform = AZ::Transform::Identity(); AZ::Transform colliderWorldTransform = AZ::Transform::Identity();
PhysX::EditorColliderComponentRequestBus::EventResult(colliderWorldTransform, idPair, &PhysX::EditorColliderComponentRequests::GetColliderWorldTransform); AZ::TransformBus::EventResult(colliderWorldTransform, idPair.GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
AZ::Vector3 nonUniformScale = AZ::Vector3::CreateOne();
AZ::NonUniformScaleRequestBus::EventResult(nonUniformScale, idPair.GetEntityId(), &AZ::NonUniformScaleRequests::GetScale);
const AZ::Transform colliderLocalTransform = Utils::GetColliderLocalTransform(idPair);
float sphereRadius = 0.0f; float sphereRadius = 0.0f;
PhysX::EditorColliderComponentRequestBus::EventResult(sphereRadius, idPair, &PhysX::EditorColliderComponentRequests::GetSphereRadius); PhysX::EditorColliderComponentRequestBus::EventResult(sphereRadius, idPair, &PhysX::EditorColliderComponentRequests::GetSphereRadius);
@ -36,7 +44,9 @@ namespace PhysX
m_radiusManipulator->AddEntityComponentIdPair(idPair); m_radiusManipulator->AddEntityComponentIdPair(idPair);
m_radiusManipulator->SetAxis(ManipulatorAxis); m_radiusManipulator->SetAxis(ManipulatorAxis);
m_radiusManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId); m_radiusManipulator->Register(AzToolsFramework::g_mainManipulatorManagerId);
m_radiusManipulator->SetLocalPosition(ManipulatorAxis * sphereRadius); m_radiusManipulator->SetLocalTransform(colliderLocalTransform * AZ::Transform::CreateTranslation(ManipulatorAxis * sphereRadius));
m_radiusManipulator->SetNonUniformScale(nonUniformScale);
m_radiusManipulator->SetBoundsDirty();
AzToolsFramework::ManipulatorViews views; AzToolsFramework::ManipulatorViews views;
views.emplace_back(AzToolsFramework::CreateManipulatorViewQuadBillboard(AzFramework::ViewportColors::DefaultManipulatorHandleColor, AzFramework::ViewportConstants::DefaultManipulatorHandleSize)); views.emplace_back(AzToolsFramework::CreateManipulatorViewQuadBillboard(AzFramework::ViewportColors::DefaultManipulatorHandleColor, AzFramework::ViewportConstants::DefaultManipulatorHandleSize));
@ -53,12 +63,18 @@ namespace PhysX
void ColliderSphereMode::Refresh(const AZ::EntityComponentIdPair& idPair) void ColliderSphereMode::Refresh(const AZ::EntityComponentIdPair& idPair)
{ {
AZ::Transform colliderWorldTransform = AZ::Transform::Identity(); AZ::Transform colliderWorldTransform = AZ::Transform::Identity();
PhysX::EditorColliderComponentRequestBus::EventResult(colliderWorldTransform, idPair, &PhysX::EditorColliderComponentRequests::GetColliderWorldTransform); AZ::TransformBus::EventResult(colliderWorldTransform, idPair.GetEntityId(), &AZ::TransformBus::Events::GetWorldTM);
m_radiusManipulator->SetSpace(colliderWorldTransform); m_radiusManipulator->SetSpace(colliderWorldTransform);
AZ::Vector3 nonUniformScale = AZ::Vector3::CreateOne();
AZ::NonUniformScaleRequestBus::EventResult(nonUniformScale, idPair.GetEntityId(), &AZ::NonUniformScaleRequests::GetScale);
const AZ::Transform colliderLocalTransform = Utils::GetColliderLocalTransform(idPair);
float sphereRadius = 0.0f; float sphereRadius = 0.0f;
PhysX::EditorColliderComponentRequestBus::EventResult(sphereRadius, idPair, &PhysX::EditorColliderComponentRequests::GetSphereRadius); PhysX::EditorColliderComponentRequestBus::EventResult(sphereRadius, idPair, &PhysX::EditorColliderComponentRequests::GetSphereRadius);
m_radiusManipulator->SetLocalPosition(ManipulatorAxis * sphereRadius); m_radiusManipulator->SetLocalTransform(colliderLocalTransform * AZ::Transform::CreateTranslation(ManipulatorAxis * sphereRadius));
m_radiusManipulator->SetBoundsDirty();
} }
void ColliderSphereMode::Teardown(const AZ::EntityComponentIdPair& idPair) void ColliderSphereMode::Teardown(const AZ::EntityComponentIdPair& idPair)
@ -80,22 +96,34 @@ namespace PhysX
AZ_UNUSED(debugDisplay); AZ_UNUSED(debugDisplay);
const AzFramework::CameraState cameraState = AzToolsFramework::GetCameraState(viewportInfo.m_viewportId); const AzFramework::CameraState cameraState = AzToolsFramework::GetCameraState(viewportInfo.m_viewportId);
float radius = m_radiusManipulator->GetLocalPosition().GetLength();
m_radiusManipulator->SetAxis(cameraState.m_side); if (!m_radiusManipulator->EntityComponentIdPairs().empty())
m_radiusManipulator->SetLocalPosition(cameraState.m_side * radius); {
const AZ::EntityComponentIdPair idPair = *m_radiusManipulator->EntityComponentIdPairs().begin();
float radius = 0.0f;
PhysX::EditorColliderComponentRequestBus::EventResult(radius, idPair, &PhysX::EditorColliderComponentRequests::GetSphereRadius);
const AZ::Transform colliderLocalTransform = Utils::GetColliderLocalTransform(idPair);
m_radiusManipulator->SetAxis(cameraState.m_side);
m_radiusManipulator->SetLocalTransform(colliderLocalTransform * AZ::Transform::CreateTranslation(cameraState.m_side * radius));
}
} }
void ColliderSphereMode::OnManipulatorMoved(const AzToolsFramework::LinearManipulator::Action& action, const AZ::EntityComponentIdPair& idPair) void ColliderSphereMode::OnManipulatorMoved(const AzToolsFramework::LinearManipulator::Action& action, const AZ::EntityComponentIdPair& idPair)
{ {
// manipulator offsets do not take transform scale into account, need to handle it here
const AZ::Transform colliderLocalTransform = Utils::GetColliderLocalTransform(idPair);
const AZ::Vector3 manipulatorPosition = AzToolsFramework::GetPositionInManipulatorFrame(
m_radiusManipulator->GetSpace().GetUniformScale(), colliderLocalTransform, action);
// Get the distance the manipulator has moved along the axis. // Get the distance the manipulator has moved along the axis.
float extent = action.LocalPosition().Dot(action.m_fixed.m_axis); float extent = manipulatorPosition.Dot(action.m_fixed.m_axis);
// Clamp the distance to a small value to prevent it going negative. // Clamp the distance to a small value to prevent it going negative.
extent = AZ::GetMax(extent, MinSphereRadius); extent = AZ::GetMax(extent, MinSphereRadius);
// Update the manipulator and sphere radius // Update the manipulator and sphere radius
m_radiusManipulator->SetLocalPosition(extent * action.m_fixed.m_axis); m_radiusManipulator->SetLocalTransform(
Utils::GetColliderLocalTransform(idPair) * AZ::Transform::CreateTranslation(extent * action.m_fixed.m_axis));
PhysX::EditorColliderComponentRequestBus::Event(idPair, &PhysX::EditorColliderComponentRequests::SetSphereRadius, extent); PhysX::EditorColliderComponentRequestBus::Event(idPair, &PhysX::EditorColliderComponentRequests::SetSphereRadius, extent);
} }
} }

@ -582,9 +582,8 @@ namespace PhysX
AZ::Transform EditorColliderComponent::GetColliderLocalTransform() const AZ::Transform EditorColliderComponent::GetColliderLocalTransform() const
{ {
const AZ::Vector3 nonUniformScale = Utils::GetTransformScale(GetEntityId());
return AZ::Transform::CreateFromQuaternionAndTranslation( return AZ::Transform::CreateFromQuaternionAndTranslation(
m_configuration.m_rotation, m_configuration.m_position * nonUniformScale); m_configuration.m_rotation, m_configuration.m_position);
} }
void EditorColliderComponent::UpdateMeshAsset() void EditorColliderComponent::UpdateMeshAsset()
@ -970,8 +969,10 @@ namespace PhysX
static_cast<const Physics::CookedMeshShapeConfiguration*>(shapeConfiguration); static_cast<const Physics::CookedMeshShapeConfiguration*>(shapeConfiguration);
const AZ::Vector3 overallScale = Utils::GetTransformScale(GetEntityId()) * m_cachedNonUniformScale * assetScale; const AZ::Vector3 overallScale = Utils::GetTransformScale(GetEntityId()) * m_cachedNonUniformScale * assetScale;
Physics::ColliderConfiguration nonUniformScaledColliderConfiguration = *colliderConfiguration;
nonUniformScaledColliderConfiguration.m_position *= m_cachedNonUniformScale;
m_colliderDebugDraw.DrawMesh(debugDisplay, *colliderConfiguration, *cookedMeshShapeConfiguration, m_colliderDebugDraw.DrawMesh(debugDisplay, nonUniformScaledColliderConfiguration, *cookedMeshShapeConfiguration,
overallScale, static_cast<AZ::u32>(shapeIndex)); overallScale, static_cast<AZ::u32>(shapeIndex));
break; break;
} }
@ -1054,12 +1055,17 @@ namespace PhysX
AZ::Transform EditorColliderComponent::GetCurrentTransform() AZ::Transform EditorColliderComponent::GetCurrentTransform()
{ {
return GetColliderWorldTransform(); return GetWorldTM();
}
AZ::Transform EditorColliderComponent::GetCurrentLocalTransform()
{
return GetColliderLocalTransform();
} }
AZ::Vector3 EditorColliderComponent::GetBoxScale() AZ::Vector3 EditorColliderComponent::GetBoxScale()
{ {
return AZ::Vector3(GetWorldTM().GetUniformScale()); return AZ::Vector3::CreateOne();
} }
void EditorColliderComponent::OnTransformChanged(const AZ::Transform& /*local*/, const AZ::Transform& world) void EditorColliderComponent::OnTransformChanged(const AZ::Transform& /*local*/, const AZ::Transform& world)
@ -1203,7 +1209,7 @@ namespace PhysX
AZ::Transform EditorColliderComponent::GetColliderWorldTransform() AZ::Transform EditorColliderComponent::GetColliderWorldTransform()
{ {
return AzToolsFramework::TransformNormalizedScale(GetWorldTM()) * GetColliderLocalTransform(); return GetWorldTM() * GetColliderLocalTransform();
} }
bool EditorColliderComponent::ShouldUpdateCollisionMeshFromRender() const bool EditorColliderComponent::ShouldUpdateCollisionMeshFromRender() const

@ -171,6 +171,7 @@ namespace PhysX
AZ::Vector3 GetDimensions() override; AZ::Vector3 GetDimensions() override;
void SetDimensions(const AZ::Vector3& dimensions) override; void SetDimensions(const AZ::Vector3& dimensions) override;
AZ::Transform GetCurrentTransform() override; AZ::Transform GetCurrentTransform() override;
AZ::Transform GetCurrentLocalTransform() override;
AZ::Vector3 GetBoxScale() override; AZ::Vector3 GetBoxScale() override;
// AZ::Render::MeshComponentNotificationBus // AZ::Render::MeshComponentNotificationBus

@ -29,6 +29,7 @@
#include <AzFramework/Physics/HeightfieldProviderBus.h> #include <AzFramework/Physics/HeightfieldProviderBus.h>
#include <PhysX/ColliderShapeBus.h> #include <PhysX/ColliderShapeBus.h>
#include <PhysX/EditorColliderComponentRequestBus.h>
#include <PhysX/SystemComponentBus.h> #include <PhysX/SystemComponentBus.h>
#include <PhysX/MeshAsset.h> #include <PhysX/MeshAsset.h>
#include <PhysX/Utils.h> #include <PhysX/Utils.h>
@ -832,6 +833,17 @@ namespace PhysX
return AZ::Transform::CreateFromQuaternionAndTranslation(colliderRelativeRotation, colliderRelativePosition); return AZ::Transform::CreateFromQuaternionAndTranslation(colliderRelativeRotation, colliderRelativePosition);
} }
AZ::Transform GetColliderLocalTransform(const AZ::EntityComponentIdPair& idPair)
{
AZ::Quaternion colliderRotation = AZ::Quaternion::CreateIdentity();
PhysX::EditorColliderComponentRequestBus::EventResult(colliderRotation, idPair, &PhysX::EditorColliderComponentRequests::GetColliderRotation);
AZ::Vector3 colliderOffset = AZ::Vector3::CreateZero();
PhysX::EditorColliderComponentRequestBus::EventResult(colliderOffset, idPair, &PhysX::EditorColliderComponentRequests::GetColliderOffset);
return AZ::Transform::CreateFromQuaternionAndTranslation(colliderRotation, colliderOffset);
}
AZ::Transform GetColliderWorldTransform(const AZ::Transform& worldTransform, AZ::Transform GetColliderWorldTransform(const AZ::Transform& worldTransform,
const AZ::Vector3& colliderRelativePosition, const AZ::Vector3& colliderRelativePosition,
const AZ::Quaternion& colliderRelativeRotation) const AZ::Quaternion& colliderRelativeRotation)

@ -142,6 +142,9 @@ namespace PhysX
AZ::Transform GetColliderLocalTransform(const AZ::Vector3& colliderRelativePosition AZ::Transform GetColliderLocalTransform(const AZ::Vector3& colliderRelativePosition
, const AZ::Quaternion& colliderRelativeRotation); , const AZ::Quaternion& colliderRelativeRotation);
//! Gets the local transform for a collider (the position and rotation relative to its entity).
AZ::Transform GetColliderLocalTransform(const AZ::EntityComponentIdPair& idPair);
//! Combines collider position and orientation offsets and world transform to a transform. //! Combines collider position and orientation offsets and world transform to a transform.
AZ::Transform GetColliderWorldTransform(const AZ::Transform& worldTransform AZ::Transform GetColliderWorldTransform(const AZ::Transform& worldTransform
, const AZ::Vector3& colliderRelativePosition , const AZ::Vector3& colliderRelativePosition

@ -17,7 +17,9 @@
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h> #include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <AzToolsFramework/Entity/EditorEntityHelpers.h> #include <AzToolsFramework/Entity/EditorEntityHelpers.h>
#include <AzToolsFramework/ViewportUi/ViewportUiManager.h> #include <AzToolsFramework/ViewportUi/ViewportUiManager.h>
#include <AzToolsFramework/ToolsComponents/EditorNonUniformScaleComponent.h>
#include <Tests/Viewport/ViewportUiManagerTests.cpp> #include <Tests/Viewport/ViewportUiManagerTests.cpp>
#include <EditorColliderComponent.h>
namespace UnitTest namespace UnitTest
{ {
@ -437,4 +439,378 @@ namespace UnitTest
EXPECT_NEAR(assetScale.GetY(), 1.0f, tolerance); EXPECT_NEAR(assetScale.GetY(), 1.0f, tolerance);
EXPECT_NEAR(assetScale.GetZ(), 1.0f, tolerance); EXPECT_NEAR(assetScale.GetZ(), 1.0f, tolerance);
} }
class PhysXEditorColliderComponentFixture : public UnitTest::ToolsApplicationFixture
{
public:
void SetUpEditorFixtureImpl() override;
void TearDownEditorFixtureImpl() override;
void SetupTransform(const AZ::Quaternion& rotation, const AZ::Vector3& translation, float uniformScale);
void SetupCollider(
const Physics::ShapeConfiguration& shapeConfiguration,
const AZ::Quaternion& colliderRotation,
const AZ::Vector3& colliderOffset);
void SetupNonUniformScale(const AZ::Vector3& nonUniformScale);
void EnterColliderSubMode(PhysX::ColliderComponentModeRequests::SubMode subMode);
AZ::Entity* m_entity = nullptr;
AZ::EntityComponentIdPair m_idPair;
};
void PhysXEditorColliderComponentFixture::SetUpEditorFixtureImpl()
{
AZ::SerializeContext* serializeContext = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
UnitTest::CreateDefaultEditorEntity("EditorColliderComponentEntity", &m_entity);
}
void PhysXEditorColliderComponentFixture::TearDownEditorFixtureImpl()
{
AzToolsFramework::EditorEntityContextRequestBus::Broadcast(
&AzToolsFramework::EditorEntityContextRequestBus::Events::DestroyEditorEntity, m_entity->GetId());
m_entity = nullptr;
}
void PhysXEditorColliderComponentFixture::SetupTransform(
const AZ::Quaternion& rotation, const AZ::Vector3& translation, float uniformScale)
{
const AZ::Transform transform = AZ::Transform::CreateFromQuaternionAndTranslation(rotation, translation);
AZ::TransformBus::Event(m_entity->GetId(), &AZ::TransformBus::Events::SetWorldTM, transform);
AZ::TransformBus::Event(m_entity->GetId(), &AZ::TransformBus::Events::SetLocalUniformScale, uniformScale);
}
void PhysXEditorColliderComponentFixture::SetupCollider(
const Physics::ShapeConfiguration& shapeConfiguration, const AZ::Quaternion& colliderRotation, const AZ::Vector3& colliderOffset)
{
m_entity->Deactivate();
auto* colliderComponent =
m_entity->CreateComponent<PhysX::EditorColliderComponent>(Physics::ColliderConfiguration(), shapeConfiguration);
m_entity->Activate();
m_idPair = AZ::EntityComponentIdPair(m_entity->GetId(), colliderComponent->GetId());
PhysX::EditorColliderComponentRequestBus::Event(
m_idPair, &PhysX::EditorColliderComponentRequests::SetColliderOffset, colliderOffset);
PhysX::EditorColliderComponentRequestBus::Event(
m_idPair, &PhysX::EditorColliderComponentRequests::SetColliderRotation, colliderRotation);
}
void PhysXEditorColliderComponentFixture::SetupNonUniformScale(const AZ::Vector3& nonUniformScale)
{
m_entity->Deactivate();
m_entity->CreateComponent(AzToolsFramework::Components::EditorNonUniformScaleComponent::RTTI_Type());
m_entity->Activate();
AZ::NonUniformScaleRequestBus::Event(m_entity->GetId(), &AZ::NonUniformScaleRequests::SetScale, nonUniformScale);
}
void PhysXEditorColliderComponentFixture::EnterColliderSubMode(PhysX::ColliderComponentModeRequests::SubMode subMode)
{
AzToolsFramework::SelectEntity(m_entity->GetId());
EnterComponentMode<PhysX::EditorColliderComponent>();
PhysX::ColliderComponentModeRequestBus::Broadcast(&PhysX::ColliderComponentModeRequests::SetCurrentMode, subMode);
}
using PhysXEditorColliderComponentManipulatorFixture =
UnitTest::IndirectCallManipulatorViewportInteractionFixtureMixin<PhysXEditorColliderComponentFixture>;
// use a reasonably large tolerance because manipulator precision is limited by viewport resolution
static const float ManipulatorTolerance = 0.01f;
TEST_F(PhysXEditorColliderComponentManipulatorFixture, OffsetManipulatorsCorrectlyLocatedRelativeToCollider)
{
const AZ::Vector3 boxDimensions(2.0f, 3.0f, 1.5f);
const AZ::Quaternion boxRotation(0.1f, 0.1f, 0.7f, 0.7f);
const AZ::Vector3 boxOffset(3.0f, 1.0f, 2.0f);
SetupCollider(Physics::BoxShapeConfiguration(boxDimensions), boxRotation, boxOffset);
const AZ::Quaternion entityRotation(0.8f, 0.2f, 0.4f, 0.4f);
const AZ::Vector3 entityTranslation(2.0f, -3.0f, 0.5f);
const float uniformScale = 2.0f;
SetupTransform(entityRotation, entityTranslation, uniformScale);
EnterColliderSubMode(PhysX::ColliderComponentModeRequests::SubMode::Offset);
// the expected position of the collider centre based on the combination of entity transform and collider offset
const AZ::Vector3 expectedColliderPosition(8.8f, -2.28f, 3.54f);
// the expected world space direction of the collider offset x-axis based on the entity transform
const AZ::Vector3 expectedXAxis(0.6f, 0.64f, 0.48f);
// position the camera to look down at the collider from above
AzFramework::SetCameraTransform(
m_cameraState,
AZ::Transform::CreateFromQuaternionAndTranslation(
AZ::Quaternion::CreateRotationX(-AZ::Constants::HalfPi), expectedColliderPosition + AZ::Vector3::CreateAxisZ(10.0f)));
// position in world space, slightly moved along the x-axis in order to grab the x translation manipulator
const AZ::Vector3 worldStart = expectedColliderPosition + 0.5f * expectedXAxis;
// position in world space to move to
const AZ::Vector3 worldEnd = worldStart + 2.0f * expectedXAxis;
const auto screenStart = AzFramework::WorldToScreen(worldStart, m_cameraState);
const auto screenEnd = AzFramework::WorldToScreen(worldEnd, m_cameraState);
m_actionDispatcher
->CameraState(m_cameraState)
// move the mouse to the position of the x offset manipulator
->MousePosition(screenStart)
// drag to move the manipulator
->MouseLButtonDown()
->MousePosition(screenEnd)
->MouseLButtonUp();
AZ::Vector3 newColliderOffset = AZ::Vector3::CreateZero();
PhysX::EditorColliderComponentRequestBus::EventResult(
newColliderOffset, m_idPair, &PhysX::EditorColliderComponentRequests::GetColliderOffset);
EXPECT_THAT(newColliderOffset, IsCloseTolerance(AZ::Vector3(4.0f, 1.0f, 2.0f), ManipulatorTolerance));
}
TEST_F(PhysXEditorColliderComponentManipulatorFixture, OffsetManipulatorsCorrectlyLocatedRelativeToColliderWithNonUniformScale)
{
const float capsuleRadius = 0.5f;
const float capsuleHeight = 2.0f;
const AZ::Quaternion capsuleRotation(0.2f, -0.4f, 0.8f, 0.4f);
const AZ::Vector3 capsuleOffset(-2.0f, 3.0f, -1.0f);
SetupCollider(Physics::CapsuleShapeConfiguration(capsuleHeight, capsuleRadius), capsuleRotation, capsuleOffset);
const AZ::Quaternion entityRotation(-0.1f, 0.7f, -0.7f, 0.1f);
const AZ::Vector3 entityTranslation(-1.0f, 1.0f, -2.5f);
const float uniformScale = 1.5f;
SetupTransform(entityRotation, entityTranslation, uniformScale);
const AZ::Vector3 nonUniformScale(2.0f, 0.5f, 1.5f);
SetupNonUniformScale(nonUniformScale);
EnterColliderSubMode(PhysX::ColliderComponentModeRequests::SubMode::Offset);
// the expected position of the collider centre based on the combination of entity transform, collider offset and non-uniform scale
const AZ::Vector3 expectedColliderPosition(4.13f, 4.84f, -4.75f);
// the expected world space direction of the collider offset z-axis based on the entity transform
const AZ::Vector3 expectedZAxis(0.28f, -0.96f, 0.0f);
// position the camera to look at the collider from underneath
AzFramework::SetCameraTransform(
m_cameraState,
AZ::Transform::CreateFromQuaternionAndTranslation(
AZ::Quaternion::CreateRotationX(AZ::Constants::HalfPi), expectedColliderPosition - AZ::Vector3::CreateAxisZ(10.0f)));
// position in world space, slightly moved along the z-axis in order to grab the z translation manipulator
// need to go in the negative z direction because the camera angle causes the manipulator to flip
const AZ::Vector3 worldStart = expectedColliderPosition - 0.5f * expectedZAxis;
// position in world space to move to
const AZ::Vector3 worldEnd = worldStart - 2.25f * expectedZAxis;
const auto screenStart = AzFramework::WorldToScreen(worldStart, m_cameraState);
const auto screenEnd = AzFramework::WorldToScreen(worldEnd, m_cameraState);
m_actionDispatcher
->CameraState(m_cameraState)
// move the mouse to the position of the z offset manipulator
->MousePosition(screenStart)
// drag to move the manipulator
->MouseLButtonDown()
->MousePosition(screenEnd)
->MouseLButtonUp();
AZ::Vector3 newColliderOffset = AZ::Vector3::CreateZero();
PhysX::EditorColliderComponentRequestBus::EventResult(
newColliderOffset, m_idPair, &PhysX::EditorColliderComponentRequests::GetColliderOffset);
EXPECT_THAT(newColliderOffset, IsCloseTolerance(AZ::Vector3(-2.0f, 3.0f, -2.0f), ManipulatorTolerance));
}
TEST_F(PhysXEditorColliderComponentManipulatorFixture, BoxColliderScaleManipulatorsCorrectlyLocatedRelativeToColliderWithNonUniformScale)
{
const AZ::Vector3 boxDimensions(2.0f, 2.0f, 3.0f);
const AZ::Quaternion boxRotation(0.7f, 0.7f, -0.1f, 0.1f);
const AZ::Vector3 boxOffset(0.5f, 1.5f, 2.0f);
SetupCollider(Physics::BoxShapeConfiguration(boxDimensions), boxRotation, boxOffset);
const AZ::Quaternion entityRotation(0.2f, 0.4f, -0.4f, 0.8f);
const AZ::Vector3 entityTranslation(2.0f, -3.0f, -2.0f);
const float uniformScale = 0.5f;
SetupTransform(entityRotation, entityTranslation, uniformScale);
const AZ::Vector3 nonUniformScale(3.0f, 1.5f, 2.5f);
SetupNonUniformScale(nonUniformScale);
EnterColliderSubMode(PhysX::ColliderComponentModeRequests::SubMode::Dimensions);
// the expected position of the collider centre based on the combination of entity transform, collider offset and non-uniform scale
const AZ::Vector3 expectedColliderPosition(4.37f, -4.285f, -1.1f);
// the expected position of the y scale manipulator relative to the centre of the collider, based on collider
// rotation, entity rotation and scale, and non-uniform scale
const AZ::Vector3 scaleManipulatorYDelta(0.54f, -0.72f, -1.2f);
// position the camera to look at the collider along the x-y diagonal
AzFramework::SetCameraTransform(
m_cameraState,
AZ::Transform::CreateFromQuaternionAndTranslation(
AZ::Quaternion::CreateRotationZ(-AZ::Constants::QuarterPi), expectedColliderPosition - AZ::Vector3(2.0f, 2.0f, 0.0f)));
const AZ::Vector3 worldStart = expectedColliderPosition + scaleManipulatorYDelta;
const AZ::Vector3 worldEnd = worldStart + 0.1f * scaleManipulatorYDelta;
const auto screenStart = AzFramework::WorldToScreen(worldStart, m_cameraState);
const auto screenEnd = AzFramework::WorldToScreen(worldEnd, m_cameraState);
m_actionDispatcher
->CameraState(m_cameraState)
// move the mouse to the position of the y scale manipulator
->MousePosition(screenStart)
// drag to move the manipulator
->MouseLButtonDown()
->MousePosition(screenEnd)
->MouseLButtonUp();
AZ::Vector3 newBoxDimensions = AZ::Vector3::CreateZero();
AzToolsFramework::BoxManipulatorRequestBus::EventResult(
newBoxDimensions, m_idPair, &AzToolsFramework::BoxManipulatorRequests::GetDimensions);
EXPECT_THAT(newBoxDimensions, IsCloseTolerance(AZ::Vector3(2.0f, 2.2f, 3.0f), ManipulatorTolerance));
}
TEST_F(PhysXEditorColliderComponentManipulatorFixture, SphereColliderScaleManipulatorsCorrectlyLocatedRelativeToColliderWithNonUniformScale)
{
const float sphereRadius = 1.0f;
const AZ::Quaternion sphereRotation(-0.1f, 0.7f, -0.7f, 0.1f);
const AZ::Vector3 sphereOffset(-2.0f, 1.0f, -3.0f);
SetupCollider(Physics::SphereShapeConfiguration(sphereRadius), sphereRotation, sphereOffset);
const AZ::Quaternion entityRotation(-0.4f, -0.2f, 0.4f, 0.8f);
const AZ::Vector3 entityTranslation(-1.0f, -3.0f, 3.0f);
const float uniformScale = 1.5f;
SetupTransform(entityRotation, entityTranslation, uniformScale);
const AZ::Vector3 nonUniformScale(1.5f, 0.5f, 2.0f);
SetupNonUniformScale(nonUniformScale);
EnterColliderSubMode(PhysX::ColliderComponentModeRequests::SubMode::Dimensions);
// the expected position of the collider centre based on the combination of entity transform, collider offset and non-uniform scale
const AZ::Vector3 expectedColliderPosition(1.7f, -10.65f, -3.0f);
// position the camera to look at the collider along the y-axis
AzFramework::SetCameraTransform(
m_cameraState, AZ::Transform::CreateTranslation(expectedColliderPosition - AZ::Vector3(0.0f, 5.0f, 0.0f)));
// the expected position of the scale manipulator relative to the centre of the collider, based on collider
// rotation, entity scale, non-uniform scale and camera state
const AZ::Vector3 scaleManipulatorDelta(-1.1952f, -1.8036f, 0.168f);
const AZ::Vector3 worldStart = expectedColliderPosition + scaleManipulatorDelta;
const AZ::Vector3 worldEnd = worldStart - 0.1f * scaleManipulatorDelta;
const auto screenStart = AzFramework::WorldToScreen(worldStart, m_cameraState);
const auto screenEnd = AzFramework::WorldToScreen(worldEnd, m_cameraState);
m_actionDispatcher
->CameraState(m_cameraState)
// move the mouse to the position of the y scale manipulator
->MousePosition(screenStart)
// drag to move the manipulator
->MouseLButtonDown()
->MousePosition(screenEnd)
->MouseLButtonUp();
float newSphereRadius = 0.0f;
PhysX::EditorColliderComponentRequestBus::EventResult(
newSphereRadius, m_idPair, &PhysX::EditorColliderComponentRequests::GetSphereRadius);
EXPECT_NEAR(newSphereRadius, 0.9f, ManipulatorTolerance);
}
TEST_F(PhysXEditorColliderComponentManipulatorFixture, CapsuleColliderScaleManipulatorsCorrectlyLocatedRelativeToColliderWithNonUniformScale)
{
const float capsuleRadius = 0.2f;
const float capsuleHeight = 1.0f;
const AZ::Quaternion capsuleRotation(-0.2f, -0.8f, -0.4f, 0.4f);
const AZ::Vector3 capsuleOffset(1.0f, -2.0f, 1.0f);
SetupCollider(Physics::CapsuleShapeConfiguration(capsuleHeight, capsuleRadius), capsuleRotation, capsuleOffset);
const AZ::Quaternion entityRotation(0.7f, -0.1f, -0.1f, 0.7f);
const AZ::Vector3 entityTranslation(-2.0f, 1.0f, -3.0f);
const float uniformScale = 2.0f;
SetupTransform(entityRotation, entityTranslation, uniformScale);
const AZ::Vector3 nonUniformScale(1.0f, 0.5f, 1.5f);
SetupNonUniformScale(nonUniformScale);
EnterColliderSubMode(PhysX::ColliderComponentModeRequests::SubMode::Dimensions);
// the expected position of the collider centre based on the combination of entity transform, collider offset and non-uniform scale
const AZ::Vector3 expectedColliderPosition(-0.92f, -2.44f, -5.0f);
// the expected position of the height manipulator relative to the centre of the collider, based on collider
// rotation, entity scale and non-uniform scale
const AZ::Vector3 heightManipulatorDelta(-0.3096f, 0.6528f, 0.4f);
// position the camera to look at the collider along the y-z diagonal
AzFramework::SetCameraTransform(
m_cameraState,
AZ::Transform::CreateFromQuaternionAndTranslation(
AZ::Quaternion::CreateRotationX(-AZ::Constants::QuarterPi), expectedColliderPosition + AZ::Vector3(0.0f, -1.0f, 1.0f)));
const AZ::Vector3 worldStart = expectedColliderPosition + heightManipulatorDelta;
const AZ::Vector3 worldEnd = worldStart + 0.2f * heightManipulatorDelta;
const auto screenStart = AzFramework::WorldToScreen(worldStart, m_cameraState);
const auto screenEnd = AzFramework::WorldToScreen(worldEnd, m_cameraState);
m_actionDispatcher
->CameraState(m_cameraState)
// move the mouse to the position of the height manipulator
->MousePosition(screenStart)
// drag to move the manipulator
->MouseLButtonDown()
->MousePosition(screenEnd)
->MouseLButtonUp();
float newCapsuleHeight = 0.0f;
PhysX::EditorColliderComponentRequestBus::EventResult(
newCapsuleHeight, m_idPair, &PhysX::EditorColliderComponentRequests::GetCapsuleHeight);
EXPECT_NEAR(newCapsuleHeight, 1.2f, ManipulatorTolerance);
}
TEST_F(PhysXEditorColliderComponentManipulatorFixture, ColliderRotationManipulatorsCorrectlyLocatedRelativeToColliderWithNonUniformScale)
{
const float capsuleRadius = 1.2f;
const float capsuleHeight = 4.0f;
const AZ::Quaternion capsuleRotation(0.7f, 0.7f, -0.1f, 0.1f);
const AZ::Vector3 capsuleOffset(-2.0f, -2.0f, 1.0f);
SetupCollider(Physics::CapsuleShapeConfiguration(capsuleHeight, capsuleRadius), capsuleRotation, capsuleOffset);
const AZ::Quaternion entityRotation(0.8f, -0.4f, -0.4f, 0.2f);
const AZ::Vector3 entityTranslation(1.0f, -1.5f, 2.0f);
const float uniformScale = 1.5f;
SetupTransform(entityRotation, entityTranslation, uniformScale);
const AZ::Vector3 nonUniformScale(1.5f, 1.5f, 2.0f);
SetupNonUniformScale(nonUniformScale);
EnterColliderSubMode(PhysX::ColliderComponentModeRequests::SubMode::Rotation);
// the expected position of the collider centre based on the combination of entity transform, collider offset and non-uniform scale
const AZ::Vector3 expectedColliderPosition(-0.86f, 4.8f, -0.52f);
// the y and z axes of the collider's frame in world space, used to locate points on the x rotation manipulator arc to interact with
const AZ::Vector3 yDirection(0.36f, -0.8f, -0.48f);
const AZ::Vector3 zDirection(0.9024f, 0.168f, 0.3968f);
// position the camera to look at the collider along the world y axis
AzFramework::SetCameraTransform(
m_cameraState,
AZ::Transform::CreateTranslation(expectedColliderPosition - AZ::Vector3(0.0f, 10.0f, 0.0f)));
const float screenToWorldMultiplier = AzToolsFramework::CalculateScreenToWorldMultiplier(expectedColliderPosition, m_cameraState);
const float manipulatorViewRadius = 2.0f;
const AZ::Vector3 worldStart = expectedColliderPosition + screenToWorldMultiplier * manipulatorViewRadius * yDirection;
const AZ::Vector3 worldEnd = expectedColliderPosition + screenToWorldMultiplier * manipulatorViewRadius * zDirection;
const auto screenStart = AzFramework::WorldToScreen(worldStart, m_cameraState);
const auto screenEnd = AzFramework::WorldToScreen(worldEnd, m_cameraState);
m_actionDispatcher
->CameraState(m_cameraState)
// move the mouse to a position on the angular manipulator
->MousePosition(screenStart)
// drag to move the manipulator
->MouseLButtonDown()
->MousePosition(screenEnd)
->MouseLButtonUp();
AZ::Quaternion newColliderRotation = AZ::Quaternion::CreateIdentity();
PhysX::EditorColliderComponentRequestBus::EventResult(
newColliderRotation, m_idPair, &PhysX::EditorColliderComponentRequests::GetColliderRotation);
EXPECT_THAT(newColliderRotation, testing::Not(IsCloseTolerance(capsuleRotation, ManipulatorTolerance)));
}
} // namespace UnitTest } // namespace UnitTest

Loading…
Cancel
Save