add support for quad shapes in shape collider component

Signed-off-by: greerdv <greerdv@amazon.com>
This commit is contained in:
greerdv
2022-01-20 11:38:22 +00:00
parent 0ae1ab9eea
commit cc50a18fe9
3 changed files with 144 additions and 1 deletions
@@ -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>
@@ -64,6 +65,17 @@ namespace PhysX
return AZ::Edit::PropertyVisibility::Hide;
}
AZ::Crc32 EditorShapeColliderComponent::SingleSidedVisibility()
{
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)
;
}
}
@@ -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,60 @@ 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, 1, 2,
0, 2, 3
};
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 +506,12 @@ namespace PhysX
}
}
void EditorShapeColliderComponent::OnSingleSidedChange()
{
UpdateShapeConfigs();
CreateStaticEditorCollider();
}
AZ::u32 EditorShapeColliderComponent::OnSubdivisionCountChange()
{
const AZ::Vector3 uniformScale = Utils::GetUniformScale(GetEntityId());
@@ -615,6 +702,8 @@ namespace PhysX
m_editorSceneHandle = m_sceneInterface->GetSceneHandle(AzPhysics::EditorPhysicsSceneName);
}
UpdateTriggerSettings();
UpdateSingleSidedSettings();
UpdateShapeConfigs();
// Debug drawing
@@ -767,6 +856,7 @@ namespace PhysX
if (changeReason == LmbrCentral::ShapeComponentNotifications::ShapeChangeReasons::ShapeChanged)
{
UpdateShapeConfigs();
UpdateTriggerSettings();
CreateStaticEditorCollider();
Physics::ColliderComponentEventBus::Event(GetEntityId(), &Physics::ColliderComponentEvents::OnColliderChanged);
@@ -849,4 +939,45 @@ 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.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);
@@ -103,6 +106,8 @@ namespace PhysX
AZ::u32 OnSubdivisionCountChange();
AZ::Crc32 SubdivisionCountVisibility();
void OnSingleSidedChange();
AZ::Crc32 SingleSidedVisibility();
// 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.