Merge pull request #7041 from aws-lumberyard-dev/quad-collider-2
Support for quad shape in PhysX shape collider component
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
#include <LmbrCentral/Shape/SphereShapeComponentBus.h>
|
||||
#include <LmbrCentral/Shape/CylinderShapeComponentBus.h>
|
||||
#include <LmbrCentral/Shape/PolygonPrismShapeComponentBus.h>
|
||||
#include <LmbrCentral/Shape/QuadShapeComponentBus.h>
|
||||
#include <PhysX/SystemComponentBus.h>
|
||||
#include <Source/Utils.h>
|
||||
#include <AzCore/Math/Geometry2DUtils.h>
|
||||
@@ -54,7 +55,7 @@ namespace PhysX
|
||||
m_colliderConfig.SetPropertyVisibility(Physics::ColliderConfiguration::Offset, false);
|
||||
}
|
||||
|
||||
AZ::Crc32 EditorShapeColliderComponent::SubdivisionCountVisibility()
|
||||
AZ::Crc32 EditorShapeColliderComponent::SubdivisionCountVisibility() const
|
||||
{
|
||||
if (m_shapeType == ShapeType::Cylinder)
|
||||
{
|
||||
@@ -64,6 +65,17 @@ namespace PhysX
|
||||
return AZ::Edit::PropertyVisibility::Hide;
|
||||
}
|
||||
|
||||
AZ::Crc32 EditorShapeColliderComponent::SingleSidedVisibility() const
|
||||
{
|
||||
if ((m_shapeType == ShapeType::QuadSingleSided || m_shapeType == ShapeType::QuadDoubleSided)
|
||||
&& GetEntity()->FindComponent<EditorRigidBodyComponent>() == nullptr)
|
||||
{
|
||||
return AZ::Edit::PropertyVisibility::Show;
|
||||
}
|
||||
|
||||
return AZ::Edit::PropertyVisibility::Hide;
|
||||
}
|
||||
|
||||
void EditorShapeColliderComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
@@ -74,6 +86,7 @@ namespace PhysX
|
||||
->Field("DebugDrawSettings", &EditorShapeColliderComponent::m_colliderDebugDraw)
|
||||
->Field("ShapeConfigs", &EditorShapeColliderComponent::m_shapeConfigs)
|
||||
->Field("SubdivisionCount", &EditorShapeColliderComponent::m_subdivisionCount)
|
||||
->Field("SingleSided", &EditorShapeColliderComponent::m_singleSided)
|
||||
;
|
||||
|
||||
if (auto editContext = serializeContext->GetEditContext())
|
||||
@@ -100,6 +113,10 @@ namespace PhysX
|
||||
->Attribute(AZ::Edit::Attributes::Max, Utils::MaxFrustumSubdivisions)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorShapeColliderComponent::OnSubdivisionCountChange)
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &EditorShapeColliderComponent::SubdivisionCountVisibility)
|
||||
->DataElement(AZ::Edit::UIHandlers::Default, &EditorShapeColliderComponent::m_singleSided, "Single sided",
|
||||
"If enabled, planar shapes will only collide from one direction (not valid for shapes attached to dynamic rigid bodies)")
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorShapeColliderComponent::OnSingleSidedChange)
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, &EditorShapeColliderComponent::SingleSidedVisibility)
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -107,16 +124,16 @@ namespace PhysX
|
||||
|
||||
void EditorShapeColliderComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC("PhysicsWorldBodyService", 0x944da0cc));
|
||||
provided.push_back(AZ_CRC("PhysXColliderService", 0x4ff43f7c));
|
||||
provided.push_back(AZ_CRC("PhysXTriggerService", 0x3a117d7b));
|
||||
provided.push_back(AZ_CRC("PhysXShapeColliderService", 0x98a7e779));
|
||||
provided.push_back(AZ_CRC_CE("PhysicsWorldBodyService"));
|
||||
provided.push_back(AZ_CRC_CE("PhysXColliderService"));
|
||||
provided.push_back(AZ_CRC_CE("PhysXTriggerService"));
|
||||
provided.push_back(AZ_CRC_CE("PhysXShapeColliderService"));
|
||||
}
|
||||
|
||||
void EditorShapeColliderComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
|
||||
{
|
||||
required.push_back(AZ_CRC("TransformService", 0x8ee22c50));
|
||||
required.push_back(AZ_CRC("ShapeService", 0xe86aa5fe));
|
||||
required.push_back(AZ_CRC_CE("TransformService"));
|
||||
required.push_back(AZ_CRC_CE("ShapeService"));
|
||||
}
|
||||
|
||||
void EditorShapeColliderComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
@@ -126,7 +143,6 @@ namespace PhysX
|
||||
incompatible.push_back(AZ_CRC_CE("AxisAlignedBoxShapeService"));
|
||||
incompatible.push_back(AZ_CRC_CE("CompoundShapeService"));
|
||||
incompatible.push_back(AZ_CRC_CE("DiskShapeService"));
|
||||
incompatible.push_back(AZ_CRC_CE("QuadShapeService"));
|
||||
incompatible.push_back(AZ_CRC_CE("TubeShapeService"));
|
||||
incompatible.push_back(AZ_CRC_CE("ReferenceShapeService"));
|
||||
}
|
||||
@@ -206,6 +222,12 @@ namespace PhysX
|
||||
|
||||
break;
|
||||
}
|
||||
case ShapeType::QuadSingleSided:
|
||||
case ShapeType::QuadDoubleSided:
|
||||
{
|
||||
// a quad shape has no interior, just return an empty vector of sample points
|
||||
break;
|
||||
}
|
||||
default:
|
||||
AZ_WarningOnce("PhysX Shape Collider Component", false, "Unsupported shape type in UpdateCachedSamplePoints");
|
||||
break;
|
||||
@@ -331,6 +353,11 @@ namespace PhysX
|
||||
UpdateCylinderConfig(uniformScale);
|
||||
}
|
||||
|
||||
else if (shapeCrc == ShapeConstants::Quad)
|
||||
{
|
||||
UpdateQuadConfig(overallScale);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
m_shapeType = !shapeCrc ? ShapeType::None : ShapeType::Unsupported;
|
||||
@@ -354,6 +381,59 @@ namespace PhysX
|
||||
m_geometryCache.m_boxDimensions = scale * boxDimensions;
|
||||
}
|
||||
|
||||
void EditorShapeColliderComponent::UpdateQuadConfig(const AZ::Vector3& scale)
|
||||
{
|
||||
LmbrCentral::QuadShapeConfig quadShapeConfig;
|
||||
LmbrCentral::QuadShapeComponentRequestBus::EventResult(quadShapeConfig, GetEntityId(),
|
||||
&LmbrCentral::QuadShapeComponentRequests::GetQuadConfiguration);
|
||||
|
||||
const float minDimension = 1e-3f; // used to prevent the dimensions being 0 in any direction
|
||||
const float xDim = AZ::GetMax(minDimension, quadShapeConfig.m_width);
|
||||
const float yDim = AZ::GetMax(minDimension, quadShapeConfig.m_height);
|
||||
|
||||
if (m_singleSided)
|
||||
{
|
||||
AZStd::vector<AZ::u8> cookedData;
|
||||
|
||||
constexpr AZ::u32 vertexCount = 4;
|
||||
const AZ::Vector3 vertices[vertexCount] =
|
||||
{
|
||||
AZ::Vector3(-0.5f * xDim, -0.5f * yDim, 0.0f),
|
||||
AZ::Vector3(-0.5f * xDim, 0.5f * yDim, 0.0f),
|
||||
AZ::Vector3(0.5f * xDim, 0.5f * yDim, 0.0f),
|
||||
AZ::Vector3(0.5f * xDim, -0.5f * yDim, 0.0f),
|
||||
};
|
||||
|
||||
constexpr AZ::u32 indexCount = 6;
|
||||
const AZ::u32 indices[indexCount] =
|
||||
{
|
||||
0, 2, 1,
|
||||
0, 3, 2
|
||||
};
|
||||
|
||||
bool cookingResult = false;
|
||||
Physics::SystemRequestBus::BroadcastResult(cookingResult, &Physics::SystemRequests::CookTriangleMeshToMemory,
|
||||
vertices, vertexCount, indices, indexCount, cookedData);
|
||||
|
||||
Physics::CookedMeshShapeConfiguration shapeConfig;
|
||||
shapeConfig.SetCookedMeshData(cookedData.data(), cookedData.size(),
|
||||
Physics::CookedMeshShapeConfiguration::MeshType::TriangleMesh);
|
||||
shapeConfig.m_scale = scale;
|
||||
|
||||
SetShapeConfig(ShapeType::QuadSingleSided, shapeConfig);
|
||||
}
|
||||
else
|
||||
{
|
||||
// it's not possible to create a perfectly 2d convex in PhysX, so the best we can do is a very thin box
|
||||
const float zDim = AZ::GetMax(minDimension, 1e-3f * AZ::GetMin(xDim, yDim));
|
||||
const AZ::Vector3 boxDimensions(xDim, yDim, zDim);
|
||||
|
||||
SetShapeConfig(ShapeType::QuadDoubleSided, Physics::BoxShapeConfiguration(boxDimensions));
|
||||
|
||||
m_shapeConfigs.back()->m_scale = scale;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorShapeColliderComponent::UpdateCapsuleConfig(const AZ::Vector3& scale)
|
||||
{
|
||||
LmbrCentral::CapsuleShapeConfig lmbrCentralCapsuleShapeConfig;
|
||||
@@ -425,6 +505,12 @@ namespace PhysX
|
||||
}
|
||||
}
|
||||
|
||||
void EditorShapeColliderComponent::OnSingleSidedChange()
|
||||
{
|
||||
UpdateShapeConfigs();
|
||||
CreateStaticEditorCollider();
|
||||
}
|
||||
|
||||
AZ::u32 EditorShapeColliderComponent::OnSubdivisionCountChange()
|
||||
{
|
||||
const AZ::Vector3 uniformScale = Utils::GetUniformScale(GetEntityId());
|
||||
@@ -615,7 +701,9 @@ namespace PhysX
|
||||
m_editorSceneHandle = m_sceneInterface->GetSceneHandle(AzPhysics::EditorPhysicsSceneName);
|
||||
}
|
||||
|
||||
UpdateSingleSidedSettings();
|
||||
UpdateShapeConfigs();
|
||||
UpdateTriggerSettings();
|
||||
|
||||
// Debug drawing
|
||||
m_colliderDebugDraw.Connect(GetEntityId());
|
||||
@@ -767,6 +855,7 @@ namespace PhysX
|
||||
if (changeReason == LmbrCentral::ShapeComponentNotifications::ShapeChangeReasons::ShapeChanged)
|
||||
{
|
||||
UpdateShapeConfigs();
|
||||
UpdateTriggerSettings();
|
||||
|
||||
CreateStaticEditorCollider();
|
||||
Physics::ColliderComponentEventBus::Event(GetEntityId(), &Physics::ColliderComponentEvents::OnColliderChanged);
|
||||
@@ -849,4 +938,46 @@ namespace PhysX
|
||||
{
|
||||
return m_colliderConfig.m_isTrigger;
|
||||
}
|
||||
|
||||
void EditorShapeColliderComponent::UpdateTriggerSettings()
|
||||
{
|
||||
if (m_shapeType == ShapeType::QuadSingleSided || m_shapeType == ShapeType::QuadDoubleSided)
|
||||
{
|
||||
if (!m_previousIsTrigger.has_value())
|
||||
{
|
||||
m_previousIsTrigger = m_colliderConfig.m_isTrigger;
|
||||
m_colliderConfig.m_isTrigger = false;
|
||||
}
|
||||
m_colliderConfig.SetPropertyVisibility(Physics::ColliderConfiguration::PropertyVisibility::IsTrigger, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_previousIsTrigger.has_value())
|
||||
{
|
||||
m_colliderConfig.m_isTrigger = m_previousIsTrigger.value();
|
||||
m_previousIsTrigger.reset();
|
||||
}
|
||||
m_colliderConfig.SetPropertyVisibility(Physics::ColliderConfiguration::PropertyVisibility::IsTrigger, true);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorShapeColliderComponent::UpdateSingleSidedSettings()
|
||||
{
|
||||
if (GetEntity()->FindComponent<EditorRigidBodyComponent>())
|
||||
{
|
||||
if (!m_previousSingleSided.has_value())
|
||||
{
|
||||
m_previousSingleSided = m_singleSided;
|
||||
}
|
||||
m_singleSided = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_previousSingleSided.has_value())
|
||||
{
|
||||
m_singleSided = m_previousSingleSided.value();
|
||||
m_previousSingleSided.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace PhysX
|
||||
|
||||
@@ -41,6 +41,8 @@ namespace PhysX
|
||||
Sphere,
|
||||
PolygonPrism,
|
||||
Cylinder,
|
||||
QuadDoubleSided,
|
||||
QuadSingleSided,
|
||||
Unsupported
|
||||
};
|
||||
|
||||
@@ -89,6 +91,7 @@ namespace PhysX
|
||||
AZ::u32 OnConfigurationChanged();
|
||||
void UpdateShapeConfigs();
|
||||
void UpdateBoxConfig(const AZ::Vector3& scale);
|
||||
void UpdateQuadConfig(const AZ::Vector3& scale);
|
||||
void UpdateCapsuleConfig(const AZ::Vector3& scale);
|
||||
void UpdateSphereConfig(const AZ::Vector3& scale);
|
||||
void UpdateCylinderConfig(const AZ::Vector3& scale);
|
||||
@@ -102,7 +105,9 @@ namespace PhysX
|
||||
void RefreshUiProperties();
|
||||
|
||||
AZ::u32 OnSubdivisionCountChange();
|
||||
AZ::Crc32 SubdivisionCountVisibility();
|
||||
AZ::Crc32 SubdivisionCountVisibility() const;
|
||||
void OnSingleSidedChange();
|
||||
AZ::Crc32 SingleSidedVisibility() const;
|
||||
|
||||
// AZ::Component
|
||||
void Activate() override;
|
||||
@@ -137,6 +142,9 @@ namespace PhysX
|
||||
AZ::Aabb GetColliderShapeAabb() override;
|
||||
bool IsTrigger() override;
|
||||
|
||||
void UpdateTriggerSettings();
|
||||
void UpdateSingleSidedSettings();
|
||||
|
||||
Physics::ColliderConfiguration m_colliderConfig; //!< Stores collision layers, whether the collider is a trigger, etc.
|
||||
DebugDraw::Collider m_colliderDebugDraw; //!< Handles drawing the collider based on global and local
|
||||
AzPhysics::SceneInterface* m_sceneInterface = nullptr;
|
||||
@@ -151,6 +159,9 @@ namespace PhysX
|
||||
//! @note 16 is the number of subdivisions in the debug cylinder that is loaded as a mesh (not generated procedurally)
|
||||
AZ::u8 m_subdivisionCount = 16;
|
||||
mutable GeometryCache m_geometryCache; //!< Cached data for generating sample points inside the attached shape.
|
||||
AZStd::optional<bool> m_previousIsTrigger; //!< Stores the previous trigger setting if the shape is changed to one which does not support triggers.
|
||||
bool m_singleSided = false; //!< Used for 2d shapes like quad which may be treated as either single or doubled sided.
|
||||
AZStd::optional<bool> m_previousSingleSided; //!< Stores the previous single sided setting when unable to support single-sided shapes (such as when used with a dynamic rigid body).
|
||||
|
||||
AzPhysics::SystemEvents::OnConfigurationChangedEvent::Handler m_physXConfigChangedHandler;
|
||||
AzPhysics::SystemEvents::OnMaterialLibraryChangedEvent::Handler m_onMaterialLibraryChangedEventHandler;
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace PhysX
|
||||
static const AZ::Crc32 Sphere = AZ_CRC("Sphere", 0x55f96687);
|
||||
static const AZ::Crc32 PolygonPrism = AZ_CRC("PolygonPrism", 0xd6b50036);
|
||||
static const AZ::Crc32 Cylinder = AZ_CRC("Cylinder", 0x9b045bea);
|
||||
static const AZ::Crc32 Quad = AZ_CRC("QuadShape", 0x40d75e14);
|
||||
} // namespace ShapeConstants
|
||||
|
||||
/// Component that provides a collider based on geometry from a shape component.
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <LmbrCentral/Shape/PolygonPrismShapeComponentBus.h>
|
||||
#include <LmbrCentral/Shape/SphereShapeComponentBus.h>
|
||||
#include <LmbrCentral/Shape/CompoundShapeComponentBus.h>
|
||||
#include <LmbrCentral/Shape/QuadShapeComponentBus.h>
|
||||
#include <PhysX/ForceRegionComponentBus.h>
|
||||
#include <PhysX/PhysXLocks.h>
|
||||
#include <PhysX/SystemComponentBus.h>
|
||||
@@ -452,21 +453,55 @@ namespace PhysXEditorTests
|
||||
EXPECT_TRUE(aabb.GetMin().IsClose(translation - 0.5f * scale * boxDimensions));
|
||||
}
|
||||
|
||||
void SetTrigger(PhysX::EditorShapeColliderComponent* editorShapeColliderComponent, bool isTrigger)
|
||||
void SetBoolValueOnComponent(AZ::Component* component, AZ::Crc32 name, bool value)
|
||||
{
|
||||
AZ::SerializeContext* serializeContext = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
|
||||
AzToolsFramework::InstanceDataHierarchy instanceDataHierarchy;
|
||||
instanceDataHierarchy.AddRootInstance(editorShapeColliderComponent);
|
||||
instanceDataHierarchy.AddRootInstance(component);
|
||||
instanceDataHierarchy.Build(serializeContext, AZ::SerializeContext::ENUM_ACCESS_FOR_WRITE);
|
||||
AzToolsFramework::InstanceDataHierarchy::InstanceDataNode* instanceNode =
|
||||
instanceDataHierarchy.FindNodeByPartialAddress({ AZ_CRC("Trigger", 0x1a6b0f5d) });
|
||||
instanceDataHierarchy.FindNodeByPartialAddress({ name });
|
||||
if (instanceNode)
|
||||
{
|
||||
instanceNode->Write<bool>(isTrigger);
|
||||
instanceNode->Write<bool>(value);
|
||||
}
|
||||
}
|
||||
|
||||
void SetTrigger(PhysX::EditorShapeColliderComponent* editorShapeColliderComponent, bool isTrigger)
|
||||
{
|
||||
SetBoolValueOnComponent(editorShapeColliderComponent, AZ_CRC_CE("Trigger"), isTrigger);
|
||||
}
|
||||
|
||||
bool GetBoolValueFromComponent(AZ::Component* component, AZ::Crc32 name)
|
||||
{
|
||||
AZ::SerializeContext* serializeContext = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
|
||||
AzToolsFramework::InstanceDataHierarchy instanceDataHierarchy;
|
||||
instanceDataHierarchy.AddRootInstance(component);
|
||||
instanceDataHierarchy.Build(serializeContext, AZ::SerializeContext::ENUM_ACCESS_FOR_READ);
|
||||
AzToolsFramework::InstanceDataHierarchy::InstanceDataNode* instanceNode =
|
||||
instanceDataHierarchy.FindNodeByPartialAddress({ name });
|
||||
bool value = false;
|
||||
instanceNode->Read<bool>(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
bool IsTrigger(PhysX::EditorShapeColliderComponent* editorShapeColliderComponent)
|
||||
{
|
||||
return GetBoolValueFromComponent(editorShapeColliderComponent, AZ_CRC_CE("Trigger"));
|
||||
}
|
||||
|
||||
void SetSingleSided(PhysX::EditorShapeColliderComponent* editorShapeColliderComponent, bool singleSided)
|
||||
{
|
||||
SetBoolValueOnComponent(editorShapeColliderComponent, AZ_CRC_CE("SingleSided"), singleSided);
|
||||
}
|
||||
|
||||
bool IsSingleSided(PhysX::EditorShapeColliderComponent* editorShapeColliderComponent)
|
||||
{
|
||||
return GetBoolValueFromComponent(editorShapeColliderComponent, AZ_CRC_CE("SingleSided"));
|
||||
}
|
||||
|
||||
EntityPtr CreateRigidBox(const AZ::Vector3& boxDimensions, const AZ::Vector3& position)
|
||||
{
|
||||
EntityPtr rigidBodyEditorEntity = CreateInactiveEditorEntity("RigidBodyEditorEntity");
|
||||
@@ -566,4 +601,147 @@ namespace PhysXEditorTests
|
||||
EXPECT_THAT(aabb.GetMin(), UnitTest::IsClose(-0.5f * boxDimensions * parentScale));
|
||||
}
|
||||
|
||||
class PhysXEditorParamBoolFixture
|
||||
: public ::testing::WithParamInterface<bool>
|
||||
, public PhysXEditorFixture
|
||||
{
|
||||
};
|
||||
|
||||
TEST_P(PhysXEditorParamBoolFixture, EditorShapeColliderComponent_ShapeColliderWithQuadShapeNonUniformlyScalesCorrectly)
|
||||
{
|
||||
// test both single and double-sided quad colliders
|
||||
bool singleSided = GetParam();
|
||||
|
||||
EntityPtr editorEntity = CreateInactiveEditorEntity("QuadEntity");
|
||||
editorEntity->CreateComponent(LmbrCentral::EditorQuadShapeComponentTypeId);
|
||||
auto* shapeColliderComponent = editorEntity->CreateComponent<PhysX::EditorShapeColliderComponent>();
|
||||
SetSingleSided(shapeColliderComponent, singleSided);
|
||||
editorEntity->CreateComponent<AzToolsFramework::Components::EditorNonUniformScaleComponent>();
|
||||
const auto entityId = editorEntity->GetId();
|
||||
|
||||
editorEntity->Activate();
|
||||
|
||||
LmbrCentral::QuadShapeComponentRequestBus::Event(entityId, &LmbrCentral::QuadShapeComponentRequests::SetQuadWidth, 1.2f);
|
||||
LmbrCentral::QuadShapeComponentRequestBus::Event(entityId, &LmbrCentral::QuadShapeComponentRequests::SetQuadHeight, 0.8f);
|
||||
|
||||
// update the transform scale and non-uniform scale
|
||||
AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetLocalUniformScale, 3.0f);
|
||||
AZ::NonUniformScaleRequestBus::Event(entityId, &AZ::NonUniformScaleRequests::SetScale, AZ::Vector3(1.5f, 0.5f, 1.0f));
|
||||
|
||||
// make a game entity and check that its AABB is as expected
|
||||
EntityPtr gameEntity = CreateActiveGameEntityFromEditorEntity(editorEntity.get());
|
||||
AZ::Aabb aabb = gameEntity->FindComponent<PhysX::StaticRigidBodyComponent>()->GetAabb();
|
||||
|
||||
EXPECT_NEAR(aabb.GetMin().GetX(), -2.7f, 1e-3f);
|
||||
EXPECT_NEAR(aabb.GetMin().GetY(), -0.6f, 1e-3f);
|
||||
EXPECT_NEAR(aabb.GetMax().GetX(), 2.7f, 1e-3f);
|
||||
EXPECT_NEAR(aabb.GetMax().GetY(), 0.6f, 1e-3f);
|
||||
}
|
||||
|
||||
TEST_P(PhysXEditorParamBoolFixture, EditorShapeColliderComponent_TriggerSettingIsRememberedWhenSwitchingToQuadAndBack)
|
||||
{
|
||||
bool initialTriggerSetting = GetParam();
|
||||
|
||||
// create an editor entity with a box component (which does support trigger)
|
||||
EntityPtr editorEntity = CreateInactiveEditorEntity("QuadEntity");
|
||||
auto* boxShapeComponent = editorEntity->CreateComponent(LmbrCentral::EditorBoxShapeComponentTypeId);
|
||||
auto* shapeColliderComponent = editorEntity->CreateComponent<PhysX::EditorShapeColliderComponent>();
|
||||
SetTrigger(shapeColliderComponent, initialTriggerSetting);
|
||||
editorEntity->Activate();
|
||||
|
||||
// the trigger setting should be what it was set to
|
||||
EXPECT_EQ(IsTrigger(shapeColliderComponent), initialTriggerSetting);
|
||||
|
||||
// deactivate the entity and swap the box for a quad (which does not support trigger)
|
||||
editorEntity->Deactivate();
|
||||
editorEntity->RemoveComponent(boxShapeComponent);
|
||||
auto* quadShapeComponent = editorEntity->CreateComponent(LmbrCentral::EditorQuadShapeComponentTypeId);
|
||||
editorEntity->Activate();
|
||||
|
||||
// the trigger setting should now be false, because quad shape does not support triggers
|
||||
EXPECT_FALSE(IsTrigger(shapeColliderComponent));
|
||||
|
||||
// swap back to a box shape
|
||||
editorEntity->Deactivate();
|
||||
editorEntity->RemoveComponent(quadShapeComponent);
|
||||
editorEntity->AddComponent(boxShapeComponent);
|
||||
editorEntity->Activate();
|
||||
|
||||
// the original trigger setting should have been remembered
|
||||
EXPECT_EQ(IsTrigger(shapeColliderComponent), initialTriggerSetting);
|
||||
|
||||
// the quad shape component is no longer attached to the entity so won't be automatically cleared up
|
||||
delete quadShapeComponent;
|
||||
}
|
||||
|
||||
TEST_P(PhysXEditorParamBoolFixture, EditorShapeColliderComponent_SingleSidedSettingIsRememberedWhenAddingAndRemovingRigidBody)
|
||||
{
|
||||
bool initialSingleSidedSetting = GetParam();
|
||||
|
||||
// create an editor entity without a rigid body (that means both single-sided and double-sided quads are valid)
|
||||
EntityPtr editorEntity = CreateInactiveEditorEntity("QuadEntity");
|
||||
editorEntity->CreateComponent(LmbrCentral::EditorQuadShapeComponentTypeId);
|
||||
auto* shapeColliderComponent = editorEntity->CreateComponent<PhysX::EditorShapeColliderComponent>();
|
||||
SetSingleSided(shapeColliderComponent, initialSingleSidedSetting);
|
||||
editorEntity->Activate();
|
||||
|
||||
// verify that the single sided setting matches the initial value
|
||||
EXPECT_EQ(IsSingleSided(shapeColliderComponent), initialSingleSidedSetting);
|
||||
|
||||
// add an editor rigid body component (this should mean single-sided quads are not supported)
|
||||
editorEntity->Deactivate();
|
||||
auto rigidBodyComponent = editorEntity->CreateComponent<PhysX::EditorRigidBodyComponent>();
|
||||
editorEntity->Activate();
|
||||
|
||||
EXPECT_FALSE(IsSingleSided(shapeColliderComponent));
|
||||
|
||||
// remove the editor rigid body component (the previous single-sided setting should be restored)
|
||||
editorEntity->Deactivate();
|
||||
editorEntity->RemoveComponent(rigidBodyComponent);
|
||||
editorEntity->Activate();
|
||||
|
||||
EXPECT_EQ(IsSingleSided(shapeColliderComponent), initialSingleSidedSetting);
|
||||
|
||||
// the rigid body component is no longer attached to the entity so won't be automatically cleared up
|
||||
delete rigidBodyComponent;
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(PhysXEditorTest, PhysXEditorParamBoolFixture, ::testing::Bool());
|
||||
|
||||
TEST_F(PhysXEditorFixture, EditorShapeColliderComponent_SingleSidedQuadDoesNotCollideFromBelow)
|
||||
{
|
||||
// create an editor entity without a rigid body (that means both single-sided and double-sided quads are valid), positioned at the origin
|
||||
EntityPtr editorQuadEntity = CreateInactiveEditorEntity("QuadEntity");
|
||||
editorQuadEntity->CreateComponent(LmbrCentral::EditorQuadShapeComponentTypeId);
|
||||
auto* shapeColliderComponent = editorQuadEntity->CreateComponent<PhysX::EditorShapeColliderComponent>();
|
||||
SetSingleSided(shapeColliderComponent, true);
|
||||
editorQuadEntity->Activate();
|
||||
LmbrCentral::QuadShapeComponentRequestBus::Event(editorQuadEntity->GetId(), &LmbrCentral::QuadShapeComponentRequests::SetQuadHeight, 10.0f);
|
||||
LmbrCentral::QuadShapeComponentRequestBus::Event(editorQuadEntity->GetId(), &LmbrCentral::QuadShapeComponentRequests::SetQuadWidth, 10.0f);
|
||||
|
||||
// add a second entity with a box collider and a rigid body, positioned below the quad
|
||||
EntityPtr editorBoxEntity = CreateInactiveEditorEntity("BoxEntity");
|
||||
editorBoxEntity->CreateComponent(LmbrCentral::BoxShapeComponentTypeId);
|
||||
editorBoxEntity->CreateComponent<PhysX::EditorShapeColliderComponent>();
|
||||
editorBoxEntity->CreateComponent<PhysX::EditorRigidBodyComponent>();
|
||||
editorBoxEntity->Activate();
|
||||
AZ::TransformBus::Event(editorBoxEntity->GetId(), &AZ::TransformBus::Events::SetWorldTranslation, -AZ::Vector3::CreateAxisZ());
|
||||
|
||||
EntityPtr gameQuadEntity = CreateActiveGameEntityFromEditorEntity(editorQuadEntity.get());
|
||||
EntityPtr gameBoxEntity = CreateActiveGameEntityFromEditorEntity(editorBoxEntity.get());
|
||||
|
||||
// give the box enough upward velocity to rise above the level of the quad
|
||||
// simulate for enough time that the box would have reached the top of its trajectory and fallen back past the starting point if
|
||||
// it hadn't collided with the top of the quad
|
||||
const int numTimesteps = 100;
|
||||
Physics::RigidBodyRequestBus::Event(gameBoxEntity->GetId(), &Physics::RigidBodyRequests::SetLinearVelocity, AZ::Vector3::CreateAxisZ(6.0f));
|
||||
PhysX::TestUtils::UpdateScene(m_defaultScene, AzPhysics::SystemConfiguration::DefaultFixedTimestep, numTimesteps);
|
||||
|
||||
// the box should travel through the base of the quad because it has no collision from that direction
|
||||
// and land on the top surface of the quad, which does have collision
|
||||
float finalHeight = 0.0f;
|
||||
AZ::TransformBus::EventResult(finalHeight, gameBoxEntity->GetId(), &AZ::TransformBus::Events::GetWorldZ);
|
||||
|
||||
EXPECT_GT(finalHeight, 0.0f);
|
||||
}
|
||||
} // namespace PhysXEditorTests
|
||||
|
||||
Reference in New Issue
Block a user