Browse Source

Merge branch 'development' of https://github.com/o3de/o3de into daimini/ActionManager/MigrateEditorContextMenu

Danilo Aimini 2 years ago
parent
commit
2b2cbf3014

+ 3 - 0
Code/Framework/AzFramework/Platform/Windows/AzFramework/Process/ProcessUtils_Win.cpp

@@ -6,6 +6,9 @@
  *
  *
  */
  */
 #include <AzFramework/Process/ProcessUtils.h>
 #include <AzFramework/Process/ProcessUtils.h>
+#include <AzCore/PlatformIncl.h>
+#include <AzCore/std/string/string.h>
+
 #include <tlhelp32.h>
 #include <tlhelp32.h>
 
 
 namespace AzFramework::ProcessUtils
 namespace AzFramework::ProcessUtils

+ 4 - 1
Gems/PhysX/Code/Source/BaseColliderComponent.cpp

@@ -328,7 +328,10 @@ namespace PhysX
             return false;
             return false;
         }
         }
 
 
-        const bool hasNonUniformScale = (AZ::NonUniformScaleRequestBus::FindFirstHandler(GetEntityId()) != nullptr);
+        const bool isAssetScaleUniform =
+            AZ::IsClose(physicsAssetConfiguration.m_assetScale.GetX(), physicsAssetConfiguration.m_assetScale.GetY()) &&
+            AZ::IsClose(physicsAssetConfiguration.m_assetScale.GetX(), physicsAssetConfiguration.m_assetScale.GetZ());
+        const bool hasNonUniformScale = !isAssetScaleUniform || (AZ::NonUniformScaleRequestBus::FindFirstHandler(GetEntityId()) != nullptr);
         Utils::CreateShapesFromAsset(physicsAssetConfiguration, componentColliderConfiguration, hasNonUniformScale,
         Utils::CreateShapesFromAsset(physicsAssetConfiguration, componentColliderConfiguration, hasNonUniformScale,
             physicsAssetConfiguration.m_subdivisionLevel, m_shapes);
             physicsAssetConfiguration.m_subdivisionLevel, m_shapes);
 
 

+ 74 - 58
Gems/PhysX/Code/Source/EditorMeshColliderComponent.cpp

@@ -93,88 +93,104 @@ namespace PhysX
     EditorProxyAssetShapeConfig::EditorProxyAssetShapeConfig(
     EditorProxyAssetShapeConfig::EditorProxyAssetShapeConfig(
         const Physics::PhysicsAssetShapeConfiguration& assetShapeConfiguration)
         const Physics::PhysicsAssetShapeConfiguration& assetShapeConfiguration)
     {
     {
+        m_physicsAsset.m_pxAsset = assetShapeConfiguration.m_asset;
         m_physicsAsset.m_configuration = assetShapeConfiguration;
         m_physicsAsset.m_configuration = assetShapeConfiguration;
     }
     }
 
 
-    AZStd::string EditorProxyAssetShapeConfig::PhysXMeshAssetShapeTypeName() const
+    AZStd::vector<EditorProxyAssetShapeConfig::ShapeType> EditorProxyAssetShapeConfig::GetShapeTypesInsideAsset() const
     {
     {
-        const AZStd::string assetName = "Asset";
-
         if (!m_physicsAsset.m_pxAsset.IsReady())
         if (!m_physicsAsset.m_pxAsset.IsReady())
         {
         {
-            return assetName;
+            return {};
         }
         }
 
 
         Physics::ColliderConfiguration defaultColliderConfiguration;
         Physics::ColliderConfiguration defaultColliderConfiguration;
         Physics::PhysicsAssetShapeConfiguration physicsAssetConfiguration = m_physicsAsset.m_configuration;
         Physics::PhysicsAssetShapeConfiguration physicsAssetConfiguration = m_physicsAsset.m_configuration;
         physicsAssetConfiguration.m_asset = m_physicsAsset.m_pxAsset;
         physicsAssetConfiguration.m_asset = m_physicsAsset.m_pxAsset;
+        physicsAssetConfiguration.m_assetScale = AZ::Vector3::CreateOne(); // Remove the scale so it doesn't affect the query for the asset mesh type
+        const bool hasNonUniformScale = false;
 
 
         AzPhysics::ShapeColliderPairList shapeConfigList;
         AzPhysics::ShapeColliderPairList shapeConfigList;
         Utils::GetColliderShapeConfigsFromAsset(
         Utils::GetColliderShapeConfigsFromAsset(
-            physicsAssetConfiguration,
-            defaultColliderConfiguration,
-            m_hasNonUniformScale,
-            m_subdivisionLevel,
-            shapeConfigList);
+            physicsAssetConfiguration, defaultColliderConfiguration, hasNonUniformScale, m_subdivisionLevel, shapeConfigList);
 
 
-        if (shapeConfigList.empty())
+        AZStd::vector<ShapeType> shapeTypes;
+        shapeTypes.reserve(shapeConfigList.size());
+        for (const auto& shapeConfig : shapeConfigList)
         {
         {
-            return assetName;
-        }
+            const Physics::ShapeConfiguration* shapeConfiguration = shapeConfig.second.get();
+            AZ_Assert(shapeConfiguration, "GetShapeTypesInsideAsset: Invalid shape-collider configuration pair");
 
 
-        // It's enough looking at the first shape as the rest would be the same type.
-        const Physics::ShapeConfiguration* shapeConfiguration = shapeConfigList[0].second.get();
-        AZ_Assert(shapeConfiguration, "PhysXMeshAssetShapeTypeName: Invalid shape-collider configuration pair");
-
-        switch (shapeConfiguration->GetShapeType())
-        {
-        case Physics::ShapeType::CookedMesh:
+            switch (shapeConfiguration->GetShapeType())
             {
             {
-                const Physics::CookedMeshShapeConfiguration* cookedMeshShapeConfiguration =
-                    static_cast<const Physics::CookedMeshShapeConfiguration*>(shapeConfiguration);
-                switch (cookedMeshShapeConfiguration->GetMeshType())
+            case Physics::ShapeType::CookedMesh:
                 {
                 {
-                case Physics::CookedMeshShapeConfiguration::MeshType::Convex:
+                    const Physics::CookedMeshShapeConfiguration* cookedMeshShapeConfiguration =
+                        static_cast<const Physics::CookedMeshShapeConfiguration*>(shapeConfiguration);
+                    switch (cookedMeshShapeConfiguration->GetMeshType())
                     {
                     {
-                        return assetName + " (Convex)";
-                    }
-                case Physics::CookedMeshShapeConfiguration::MeshType::TriangleMesh:
-                    {
-                        return assetName + " (Triangle Mesh)";
-                    }
-                default:
-                    {
-                        AZ_Error(
-                            "EditorProxyAssetShapeConfig",
-                            false,
-                            "PhysXMeshAssetShapeTypeName: Unexpected MeshType %d",
-                            static_cast<AZ::u32>(cookedMeshShapeConfiguration->GetMeshType()));
-                        return assetName;
+                    case Physics::CookedMeshShapeConfiguration::MeshType::Convex:
+                        shapeTypes.push_back(ShapeType::Convex);
+                        break;
+                    case Physics::CookedMeshShapeConfiguration::MeshType::TriangleMesh:
+                        shapeTypes.push_back(ShapeType::TriangleMesh);
+                        break;
+                    default:
+                        shapeTypes.push_back(ShapeType::Invalid);
+                        break;
                     }
                     }
                 }
                 }
                 break;
                 break;
+            case Physics::ShapeType::Sphere:
+            case Physics::ShapeType::Box:
+            case Physics::ShapeType::Capsule:
+                shapeTypes.push_back(ShapeType::Primitive);
+                break;
+            default:
+                shapeTypes.push_back(ShapeType::Invalid);
+                break;
             }
             }
-        case Physics::ShapeType::Sphere:
-        case Physics::ShapeType::Box:
-        case Physics::ShapeType::Capsule:
-            {
-                return assetName + " (Primitive)";
-            }
+        }
+
+        return shapeTypes;
+    }
+
+    AZStd::string EditorProxyAssetShapeConfig::PhysXMeshAssetShapeTypeName() const
+    {
+        const AZStd::string assetName = "Asset";
+
+        const AZStd::vector<ShapeType> shapeTypes = GetShapeTypesInsideAsset();
+        if (shapeTypes.empty())
+        {
+            return assetName;
+        }
+
+        // Using the first shape type as representative for shapes inside the asset.
+        switch (shapeTypes[0])
+        {
+        case ShapeType::Primitive:
+            return assetName + " (Primitive)";
+        case ShapeType::Convex:
+            return assetName + " (Convex)";
+        case ShapeType::TriangleMesh:
+            return assetName + " (Triangle Mesh)";
         default:
         default:
-            {
-                AZ_Error(
-                    "EditorProxyAssetShapeConfig",
-                    false,
-                    "PhysXMeshAssetShapeTypeName: Unexpected ShapeType %d.",
-                    static_cast<AZ::u32>(shapeConfiguration->GetShapeType()));
-                return assetName;
-            }
+            return assetName;
         }
         }
     }
     }
 
 
     bool EditorProxyAssetShapeConfig::ShowingSubdivisionLevel() const
     bool EditorProxyAssetShapeConfig::ShowingSubdivisionLevel() const
     {
     {
-        return m_hasNonUniformScale;
+        const AZStd::vector<ShapeType> shapeTypes = GetShapeTypesInsideAsset();
+
+        return m_hasNonUniformScale &&
+            AZStd::any_of(
+                   shapeTypes.begin(),
+                   shapeTypes.end(),
+                   [](const ShapeType& shapeType)
+                   {
+                       return shapeType == ShapeType::Primitive;
+                   });
     }
     }
 
 
     AZ::u32 EditorProxyAssetShapeConfig::OnConfigurationChanged()
     AZ::u32 EditorProxyAssetShapeConfig::OnConfigurationChanged()
@@ -342,15 +358,10 @@ namespace PhysX
         AZ::NonUniformScaleRequestBus::Event(
         AZ::NonUniformScaleRequestBus::Event(
             entityId, &AZ::NonUniformScaleRequests::RegisterScaleChangedEvent,
             entityId, &AZ::NonUniformScaleRequests::RegisterScaleChangedEvent,
             m_nonUniformScaleChangedHandler);
             m_nonUniformScaleChangedHandler);
-        m_hasNonUniformScale = (AZ::NonUniformScaleRequestBus::FindFirstHandler(entityId) != nullptr);
-        m_proxyShapeConfiguration.m_hasNonUniformScale = m_hasNonUniformScale;
 
 
         AZ::TransformBus::EventResult(m_cachedWorldTransform, entityId, &AZ::TransformInterface::GetWorldTM);
         AZ::TransformBus::EventResult(m_cachedWorldTransform, entityId, &AZ::TransformInterface::GetWorldTM);
         m_cachedNonUniformScale = AZ::Vector3::CreateOne();
         m_cachedNonUniformScale = AZ::Vector3::CreateOne();
-        if (m_hasNonUniformScale)
-        {
-            AZ::NonUniformScaleRequestBus::EventResult(m_cachedNonUniformScale, entityId, &AZ::NonUniformScaleRequests::GetScale);
-        }
+        AZ::NonUniformScaleRequestBus::EventResult(m_cachedNonUniformScale, entityId, &AZ::NonUniformScaleRequests::GetScale);
 
 
         // Debug drawing
         // Debug drawing
         m_colliderDebugDraw.Connect(entityId);
         m_colliderDebugDraw.Connect(entityId);
@@ -845,6 +856,11 @@ namespace PhysX
 
 
     void EditorMeshColliderComponent::UpdateShapeConfigurationScale()
     void EditorMeshColliderComponent::UpdateShapeConfigurationScale()
     {
     {
+        const AZ::Vector3& assetScale = m_proxyShapeConfiguration.m_physicsAsset.m_configuration.m_assetScale;
+        const bool isAssetScaleUniform =
+            AZ::IsClose(assetScale.GetX(), assetScale.GetY()) && AZ::IsClose(assetScale.GetX(), assetScale.GetZ());
+        m_hasNonUniformScale = !isAssetScaleUniform || (AZ::NonUniformScaleRequestBus::FindFirstHandler(GetEntityId()) != nullptr);
+        m_proxyShapeConfiguration.m_hasNonUniformScale = m_hasNonUniformScale;
         m_proxyShapeConfiguration.m_physicsAsset.m_configuration.m_scale = GetWorldTM().ExtractUniformScale() * m_cachedNonUniformScale;
         m_proxyShapeConfiguration.m_physicsAsset.m_configuration.m_scale = GetWorldTM().ExtractUniformScale() * m_cachedNonUniformScale;
     }
     }
 
 

+ 8 - 0
Gems/PhysX/Code/Source/EditorMeshColliderComponent.h

@@ -63,6 +63,14 @@ namespace PhysX
         AZ::u8 m_subdivisionLevel = 4; //!< The level of subdivision if a primitive shape is replaced with a convex mesh due to scaling.
         AZ::u8 m_subdivisionLevel = 4; //!< The level of subdivision if a primitive shape is replaced with a convex mesh due to scaling.
 
 
     private:
     private:
+        enum class ShapeType
+        {
+            Invalid,
+            Primitive,
+            Convex,
+            TriangleMesh
+        };
+        AZStd::vector<ShapeType> GetShapeTypesInsideAsset() const;
         AZStd::string PhysXMeshAssetShapeTypeName() const;
         AZStd::string PhysXMeshAssetShapeTypeName() const;
         bool ShowingSubdivisionLevel() const;
         bool ShowingSubdivisionLevel() const;
         AZ::u32 OnConfigurationChanged();
         AZ::u32 OnConfigurationChanged();

+ 9 - 2
Gems/PhysX/Code/Source/EditorRigidBodyComponent.cpp

@@ -78,11 +78,18 @@ namespace PhysX
                     continue;
                     continue;
                 }
                 }
 
 
+                const AZ::Vector3& assetScale = shapeConfigurationProxy.m_physicsAsset.m_configuration.m_assetScale;
+                const bool isAssetScaleUniform =
+                    AZ::IsClose(assetScale.GetX(), assetScale.GetY()) && AZ::IsClose(assetScale.GetX(), assetScale.GetZ());
+
                 const Physics::ColliderConfiguration colliderConfigurationUnscaled = collider->GetColliderConfiguration();
                 const Physics::ColliderConfiguration colliderConfigurationUnscaled = collider->GetColliderConfiguration();
                 AZStd::vector<AZStd::shared_ptr<Physics::Shape>> shapes;
                 AZStd::vector<AZStd::shared_ptr<Physics::Shape>> shapes;
                 Utils::CreateShapesFromAsset(
                 Utils::CreateShapesFromAsset(
                     shapeConfigurationProxy.m_physicsAsset.m_configuration,
                     shapeConfigurationProxy.m_physicsAsset.m_configuration,
-                    colliderConfigurationUnscaled, hasNonUniformScaleComponent, shapeConfigurationProxy.m_subdivisionLevel, shapes);
+                    colliderConfigurationUnscaled,
+                    hasNonUniformScaleComponent || !isAssetScaleUniform,
+                    shapeConfigurationProxy.m_subdivisionLevel,
+                    shapes);
 
 
                 for (const auto& shape : shapes)
                 for (const auto& shape : shapes)
                 {
                 {
@@ -201,7 +208,7 @@ namespace PhysX
                         ->Attribute(AZ::Edit::Attributes::DescriptionTextOverride, &AzPhysics::RigidBodyConfiguration::GetKinematicTooltip)
                         ->Attribute(AZ::Edit::Attributes::DescriptionTextOverride, &AzPhysics::RigidBodyConfiguration::GetKinematicTooltip)
                         ->Attribute(AZ_CRC_CE("EditButtonVisible"), true)
                         ->Attribute(AZ_CRC_CE("EditButtonVisible"), true)
                         ->Attribute(AZ_CRC_CE("SetTrueLabel"), "Kinematic")
                         ->Attribute(AZ_CRC_CE("SetTrueLabel"), "Kinematic")
-                        ->Attribute(AZ_CRC_CE("SetFalseLabel"), "Dynamic")
+                        ->Attribute(AZ_CRC_CE("SetFalseLabel"), "Simulated")
                     ->Attribute(
                     ->Attribute(
                         AZ_CRC_CE("EditButtonCallback"), AzToolsFramework::GenericEditButtonCallback<bool>(&OnEditButtonClicked))
                         AZ_CRC_CE("EditButtonCallback"), AzToolsFramework::GenericEditButtonCallback<bool>(&OnEditButtonClicked))
                         ->Attribute(AZ_CRC_CE("EditButtonToolTip"), "Open Type dialog for a detailed description on the motion types")
                         ->Attribute(AZ_CRC_CE("EditButtonToolTip"), "Open Type dialog for a detailed description on the motion types")

+ 1 - 1
Gems/PhysX/Code/Source/RigidBodyComponent.cpp

@@ -152,7 +152,7 @@ namespace PhysX
 
 
         if (m_staticTransformAtActivation)
         if (m_staticTransformAtActivation)
         {
         {
-            AZ_Warning("PhysX Rigid Body Component", false, "It is not valid to have a PhysX Rigid Body Component "
+            AZ_Warning("RigidBodyComponent", false, "It is not valid to have a PhysX Dynamic Rigid Body Component "
                 "when the Transform Component is marked static.  Entity \"%s\" will behave as a static rigid body.",
                 "when the Transform Component is marked static.  Entity \"%s\" will behave as a static rigid body.",
                 GetEntity()->GetName().c_str());
                 GetEntity()->GetName().c_str());
 
 

+ 116 - 260
Gems/PhysX/Code/Tests/EditorMeshColliderComponentTests.cpp

@@ -34,6 +34,56 @@
 
 
 namespace PhysXEditorTests
 namespace PhysXEditorTests
 {
 {
+    static bool MeshColliderHasOnePhysicsAssetShapeType(PhysX::MeshColliderComponent* meshColliderComponent)
+    {
+        if (!meshColliderComponent)
+        {
+            return false;
+        }
+
+        const AzPhysics::ShapeColliderPairList shapeConfigList = meshColliderComponent->GetShapeConfigurations();
+        if (shapeConfigList.size() != 1)
+        {
+            return false;
+        }
+
+        return shapeConfigList[0].second->GetShapeType() == Physics::ShapeType::PhysicsAsset;
+    }
+
+    static physx::PxGeometryType::Enum GetSimulatedBodyFirstPxGeometryType(const AZ::EntityId& entityId)
+    {
+        AzPhysics::SimulatedBody* simulatedBody = nullptr;
+        AzPhysics::SimulatedBodyComponentRequestsBus::EventResult(
+            simulatedBody, entityId, &AzPhysics::SimulatedBodyComponentRequests::GetSimulatedBody);
+        if (!simulatedBody)
+        {
+            return physx::PxGeometryType::eINVALID;
+        }
+
+        const auto* pxRigidActor = static_cast<const physx::PxRigidActor*>(simulatedBody->GetNativePointer());
+        if (!pxRigidActor)
+        {
+            return physx::PxGeometryType::eINVALID;
+        }
+
+        PHYSX_SCENE_READ_LOCK(pxRigidActor->getScene());
+
+        if (pxRigidActor->getNbShapes() == 0)
+        {
+            return physx::PxGeometryType::eINVALID;
+        }
+
+        physx::PxShape* shape = nullptr;
+        pxRigidActor->getShapes(&shape, 1, 0);
+
+        if (!shape)
+        {
+            return physx::PxGeometryType::eINVALID;
+        }
+
+        return shape->getGeometryType();
+    }
+
     TEST_F(PhysXEditorFixture, EditorMeshColliderComponent_RigidBodyDependencySatisfied_EntityIsValid)
     TEST_F(PhysXEditorFixture, EditorMeshColliderComponent_RigidBodyDependencySatisfied_EntityIsValid)
     {
     {
         EntityPtr entity = CreateInactiveEditorEntity("MeshColliderComponentEditorEntity");
         EntityPtr entity = CreateInactiveEditorEntity("MeshColliderComponentEditorEntity");
@@ -147,45 +197,21 @@ namespace PhysXEditorTests
 
 
         EntityPtr gameEntity = CreateActiveGameEntityFromEditorEntity(editorEntity.get());
         EntityPtr gameEntity = CreateActiveGameEntityFromEditorEntity(editorEntity.get());
 
 
-        // check that the runtime entity has the expected components
-        auto* meshColliderComponent = gameEntity->FindComponent<PhysX::MeshColliderComponent>();
-        auto* staticRigidBodyComponent = gameEntity->FindComponent<PhysX::StaticRigidBodyComponent>();
-        EXPECT_TRUE(meshColliderComponent != nullptr);
-        EXPECT_TRUE(staticRigidBodyComponent != nullptr);
-
-        AzPhysics::ShapeColliderPairList shapeConfigList = meshColliderComponent->GetShapeConfigurations();
-        EXPECT_EQ(shapeConfigList.size(), 1);
-
-        for (const auto& shapeConfigPair : shapeConfigList)
+        for (const auto& entityId : { editorEntity->GetId(), gameEntity->GetId() })
         {
         {
-            EXPECT_EQ(shapeConfigPair.second->GetShapeType(), Physics::ShapeType::PhysicsAsset);
-        }
+            EXPECT_EQ(GetSimulatedBodyFirstPxGeometryType(entityId), physx::PxGeometryType::eSPHERE);
 
 
-        const auto* simulatedBody = staticRigidBodyComponent->GetSimulatedBody();
-        const auto* pxRigidStatic = static_cast<const physx::PxRigidStatic*>(simulatedBody->GetNativePointer());
-
-        PHYSX_SCENE_READ_LOCK(pxRigidStatic->getScene());
-
-        // there should be a single shape on the rigid body and it should be a box
-        EXPECT_EQ(pxRigidStatic->getNbShapes(), 1);
-        if (pxRigidStatic->getNbShapes() > 0)
-        {
-            physx::PxShape* shape = nullptr;
-            pxRigidStatic->getShapes(&shape, 1, 0);
-            EXPECT_EQ(shape->getGeometryType(), physx::PxGeometryType::eSPHERE);
+            const AZ::Aabb aabb = GetSimulatedBodyAabb(entityId);
+            EXPECT_THAT(aabb.GetMin(), UnitTest::IsCloseTolerance(AZ::Vector3(-0.5f, -0.5f, -0.5f), 1e-3f));
+            EXPECT_THAT(aabb.GetMax(), UnitTest::IsCloseTolerance(AZ::Vector3(0.5f, 0.5f, 0.5f), 1e-3f));
         }
         }
 
 
-        const AZ::Aabb aabb = simulatedBody->GetAabb();
-        EXPECT_THAT(aabb.GetMin(), UnitTest::IsCloseTolerance(AZ::Vector3(-0.5f, -0.5f, -0.5f), 1e-3f));
-        EXPECT_THAT(aabb.GetMax(), UnitTest::IsCloseTolerance(AZ::Vector3(0.5f, 0.5f, 0.5f), 1e-3f));
+        EXPECT_TRUE(MeshColliderHasOnePhysicsAssetShapeType(gameEntity->FindComponent<PhysX::MeshColliderComponent>()));
 
 
         delete meshAssetData;
         delete meshAssetData;
     }
     }
 
 
-    // [o3de/o3de#14907]
-    // Asset Scale (with non-uniform value) does not work when the asset contains primitives and there
-    // is no non-uniform scale component present.
-    TEST_F(PhysXEditorFixture, DISABLED_EditorMeshColliderComponent_AssetWithPrimitive_AssetScale_CorrectShapeTypeGeometryTypeAndAabb)
+    TEST_F(PhysXEditorFixture, EditorMeshColliderComponent_AssetWithPrimitive_AssetScale_CorrectShapeTypeGeometryTypeAndAabb)
     {
     {
         auto* meshAssetData = AZ::Utils::LoadObjectFromBuffer<PhysX::Pipeline::MeshAssetData>(
         auto* meshAssetData = AZ::Utils::LoadObjectFromBuffer<PhysX::Pipeline::MeshAssetData>(
             PhysXMeshTestData::SpherePrimitive.data(), PhysXMeshTestData::SpherePrimitive.size());
             PhysXMeshTestData::SpherePrimitive.data(), PhysXMeshTestData::SpherePrimitive.size());
@@ -202,41 +228,18 @@ namespace PhysXEditorTests
 
 
         EntityPtr gameEntity = CreateActiveGameEntityFromEditorEntity(editorEntity.get());
         EntityPtr gameEntity = CreateActiveGameEntityFromEditorEntity(editorEntity.get());
 
 
-        // check that the runtime entity has the expected components
-        auto* meshColliderComponent = gameEntity->FindComponent<PhysX::MeshColliderComponent>();
-        auto* staticRigidBodyComponent = gameEntity->FindComponent<PhysX::StaticRigidBodyComponent>();
-        EXPECT_TRUE(meshColliderComponent != nullptr);
-        EXPECT_TRUE(staticRigidBodyComponent != nullptr);
-
-        // because there is a non-uniform scale applied, the runtime entity should have a MeshColliderComponent with a
-        // cooked mesh shape configuration, rather than a Sphere shape configuration.
-        AzPhysics::ShapeColliderPairList shapeConfigList = meshColliderComponent->GetShapeConfigurations();
-        EXPECT_EQ(shapeConfigList.size(), 1);
-
-        for (const auto& shapeConfigPair : shapeConfigList)
+        for (const auto& entityId : { editorEntity->GetId(), gameEntity->GetId() })
         {
         {
-            EXPECT_EQ(shapeConfigPair.second->GetShapeType(), Physics::ShapeType::PhysicsAsset);
-        }
-
-        const auto* simulatedBody = staticRigidBodyComponent->GetSimulatedBody();
-        const auto* pxRigidStatic = static_cast<const physx::PxRigidStatic*>(simulatedBody->GetNativePointer());
-
-        PHYSX_SCENE_READ_LOCK(pxRigidStatic->getScene());
-
-        // there should be a single shape on the rigid body and it should be a box
-        EXPECT_EQ(pxRigidStatic->getNbShapes(), 1);
-        if (pxRigidStatic->getNbShapes() > 0)
-        {
-            physx::PxShape* shape = nullptr;
-            pxRigidStatic->getShapes(&shape, 1, 0);
             // because there is a non-uniform scale applied, the geometry type used should be a convex mesh
             // because there is a non-uniform scale applied, the geometry type used should be a convex mesh
             // rather than a primitive type
             // rather than a primitive type
-            EXPECT_EQ(shape->getGeometryType(), physx::PxGeometryType::eCONVEXMESH);
+            EXPECT_EQ(GetSimulatedBodyFirstPxGeometryType(entityId), physx::PxGeometryType::eCONVEXMESH);
+
+            const AZ::Aabb aabb = GetSimulatedBodyAabb(entityId);
+            EXPECT_THAT(aabb.GetMin(), UnitTest::IsCloseTolerance(AZ::Vector3(-1.0f, -0.55f, -1.75f), 1e-3f));
+            EXPECT_THAT(aabb.GetMax(), UnitTest::IsCloseTolerance(AZ::Vector3(1.0f, 0.55f, 1.75f), 1e-3f));
         }
         }
 
 
-        const AZ::Aabb aabb = simulatedBody->GetAabb();
-        EXPECT_THAT(aabb.GetMin(), UnitTest::IsCloseTolerance(AZ::Vector3(-1.0f, -0.55f, -1.75f), 1e-3f));
-        EXPECT_THAT(aabb.GetMax(), UnitTest::IsCloseTolerance(AZ::Vector3(1.0f, 0.55f, 1.75f), 1e-3f));
+        EXPECT_TRUE(MeshColliderHasOnePhysicsAssetShapeType(gameEntity->FindComponent<PhysX::MeshColliderComponent>()));
 
 
         delete meshAssetData;
         delete meshAssetData;
     }
     }
@@ -264,41 +267,18 @@ namespace PhysXEditorTests
 
 
         EntityPtr gameEntity = CreateActiveGameEntityFromEditorEntity(editorEntity.get());
         EntityPtr gameEntity = CreateActiveGameEntityFromEditorEntity(editorEntity.get());
 
 
-        // check that the runtime entity has the expected components
-        auto* meshColliderComponent = gameEntity->FindComponent<PhysX::MeshColliderComponent>();
-        auto* staticRigidBodyComponent = gameEntity->FindComponent<PhysX::StaticRigidBodyComponent>();
-        EXPECT_TRUE(meshColliderComponent != nullptr);
-        EXPECT_TRUE(staticRigidBodyComponent != nullptr);
-
-        // because there is a non-uniform scale applied, the runtime entity should have a MeshColliderComponent with a
-        // cooked mesh shape configuration, rather than a Sphere shape configuration.
-        AzPhysics::ShapeColliderPairList shapeConfigList = meshColliderComponent->GetShapeConfigurations();
-        EXPECT_EQ(shapeConfigList.size(), 1);
-
-        for (const auto& shapeConfigPair : shapeConfigList)
+        for (const auto& entityId : { editorEntity->GetId(), gameEntity->GetId() })
         {
         {
-            EXPECT_EQ(shapeConfigPair.second->GetShapeType(), Physics::ShapeType::PhysicsAsset);
-        }
-
-        const auto* simulatedBody = staticRigidBodyComponent->GetSimulatedBody();
-        const auto* pxRigidStatic = static_cast<const physx::PxRigidStatic*>(simulatedBody->GetNativePointer());
-
-        PHYSX_SCENE_READ_LOCK(pxRigidStatic->getScene());
-
-        // there should be a single shape on the rigid body and it should be a box
-        EXPECT_EQ(pxRigidStatic->getNbShapes(), 1);
-        if (pxRigidStatic->getNbShapes() > 0)
-        {
-            physx::PxShape* shape = nullptr;
-            pxRigidStatic->getShapes(&shape, 1, 0);
             // because there is a non-uniform scale applied, the geometry type used should be a convex mesh
             // because there is a non-uniform scale applied, the geometry type used should be a convex mesh
             // rather than a primitive type
             // rather than a primitive type
-            EXPECT_EQ(shape->getGeometryType(), physx::PxGeometryType::eCONVEXMESH);
+            EXPECT_EQ(GetSimulatedBodyFirstPxGeometryType(entityId), physx::PxGeometryType::eCONVEXMESH);
+
+            const AZ::Aabb aabb = GetSimulatedBodyAabb(entityId);
+            EXPECT_THAT(aabb.GetMin(), UnitTest::IsCloseTolerance(AZ::Vector3(-1.0f, -0.825f, -1.75f), 1e-3f));
+            EXPECT_THAT(aabb.GetMax(), UnitTest::IsCloseTolerance(AZ::Vector3(1.0f, 0.825f, 1.75f), 1e-3f));
         }
         }
 
 
-        const AZ::Aabb aabb = simulatedBody->GetAabb();
-        EXPECT_THAT(aabb.GetMin(), UnitTest::IsCloseTolerance(AZ::Vector3(-1.0f, -0.825f, -1.75f), 1e-3f));
-        EXPECT_THAT(aabb.GetMax(), UnitTest::IsCloseTolerance(AZ::Vector3(1.0f, 0.825f, 1.75f), 1e-3f));
+        EXPECT_TRUE(MeshColliderHasOnePhysicsAssetShapeType(gameEntity->FindComponent<PhysX::MeshColliderComponent>()));
 
 
         delete meshAssetData;
         delete meshAssetData;
     }
     }
@@ -314,39 +294,18 @@ namespace PhysXEditorTests
 
 
         EntityPtr gameEntity = CreateActiveGameEntityFromEditorEntity(editorEntity.get());
         EntityPtr gameEntity = CreateActiveGameEntityFromEditorEntity(editorEntity.get());
 
 
-        // check that the runtime entity has the expected components
-        auto* meshColliderComponent = gameEntity->FindComponent<PhysX::MeshColliderComponent>();
-        auto* staticRigidBodyComponent = gameEntity->FindComponent<PhysX::StaticRigidBodyComponent>();
-        EXPECT_TRUE(meshColliderComponent != nullptr);
-        EXPECT_TRUE(staticRigidBodyComponent != nullptr);
-
-        AzPhysics::ShapeColliderPairList shapeConfigList = meshColliderComponent->GetShapeConfigurations();
-        EXPECT_EQ(shapeConfigList.size(), 1);
-
-        for (const auto& shapeConfigPair : shapeConfigList)
+        for (const auto& entityId : { editorEntity->GetId(), gameEntity->GetId() })
         {
         {
-            EXPECT_EQ(shapeConfigPair.second->GetShapeType(), Physics::ShapeType::PhysicsAsset);
-        }
-
-        const auto* simulatedBody = staticRigidBodyComponent->GetSimulatedBody();
-        const auto* pxRigidStatic = static_cast<const physx::PxRigidStatic*>(simulatedBody->GetNativePointer());
+            EXPECT_EQ(GetSimulatedBodyFirstPxGeometryType(entityId), physx::PxGeometryType::eCONVEXMESH);
 
 
-        PHYSX_SCENE_READ_LOCK(pxRigidStatic->getScene());
-
-        // there should be a single shape on the rigid body and it should be a box
-        EXPECT_EQ(pxRigidStatic->getNbShapes(), 1);
-        if (pxRigidStatic->getNbShapes() > 0)
-        {
-            physx::PxShape* shape = nullptr;
-            pxRigidStatic->getShapes(&shape, 1, 0);
-            EXPECT_EQ(shape->getGeometryType(), physx::PxGeometryType::eCONVEXMESH);
+            const AZ::Aabb aabb = GetSimulatedBodyAabb(entityId);
+            // convex shapes used to export the sphere mesh requires a higher toleance
+            // when checking its aabb due to the lower tesselation it does to cover the sphere.
+            EXPECT_THAT(aabb.GetMin(), UnitTest::IsCloseTolerance(AZ::Vector3(-0.5f, -0.5f, -0.5f), 1e-1f));
+            EXPECT_THAT(aabb.GetMax(), UnitTest::IsCloseTolerance(AZ::Vector3(0.5f, 0.5f, 0.5f), 1e-1f));
         }
         }
 
 
-        const AZ::Aabb aabb = simulatedBody->GetAabb();
-        // convex shapes used to export the sphere mesh requires a higher toleance
-        // when checking its aabb due to the lower tesselation it does to cover the sphere.
-        EXPECT_THAT(aabb.GetMin(), UnitTest::IsCloseTolerance(AZ::Vector3(-0.5f, -0.5f, -0.5f), 1e-1f));
-        EXPECT_THAT(aabb.GetMax(), UnitTest::IsCloseTolerance(AZ::Vector3(0.5f, 0.5f, 0.5f), 1e-1f));
+        EXPECT_TRUE(MeshColliderHasOnePhysicsAssetShapeType(gameEntity->FindComponent<PhysX::MeshColliderComponent>()));
 
 
         delete meshAssetData;
         delete meshAssetData;
     }
     }
@@ -368,39 +327,18 @@ namespace PhysXEditorTests
 
 
         EntityPtr gameEntity = CreateActiveGameEntityFromEditorEntity(editorEntity.get());
         EntityPtr gameEntity = CreateActiveGameEntityFromEditorEntity(editorEntity.get());
 
 
-        // check that the runtime entity has the expected components
-        auto* meshColliderComponent = gameEntity->FindComponent<PhysX::MeshColliderComponent>();
-        auto* staticRigidBodyComponent = gameEntity->FindComponent<PhysX::StaticRigidBodyComponent>();
-        EXPECT_TRUE(meshColliderComponent != nullptr);
-        EXPECT_TRUE(staticRigidBodyComponent != nullptr);
-
-        AzPhysics::ShapeColliderPairList shapeConfigList = meshColliderComponent->GetShapeConfigurations();
-        EXPECT_EQ(shapeConfigList.size(), 1);
-
-        for (const auto& shapeConfigPair : shapeConfigList)
+        for (const auto& entityId : { editorEntity->GetId(), gameEntity->GetId() })
         {
         {
-            EXPECT_EQ(shapeConfigPair.second->GetShapeType(), Physics::ShapeType::PhysicsAsset);
-        }
+            EXPECT_EQ(GetSimulatedBodyFirstPxGeometryType(entityId), physx::PxGeometryType::eCONVEXMESH);
 
 
-        const auto* simulatedBody = staticRigidBodyComponent->GetSimulatedBody();
-        const auto* pxRigidStatic = static_cast<const physx::PxRigidStatic*>(simulatedBody->GetNativePointer());
-
-        PHYSX_SCENE_READ_LOCK(pxRigidStatic->getScene());
-
-        // there should be a single shape on the rigid body and it should be a box
-        EXPECT_EQ(pxRigidStatic->getNbShapes(), 1);
-        if (pxRigidStatic->getNbShapes() > 0)
-        {
-            physx::PxShape* shape = nullptr;
-            pxRigidStatic->getShapes(&shape, 1, 0);
-            EXPECT_EQ(shape->getGeometryType(), physx::PxGeometryType::eCONVEXMESH);
+            const AZ::Aabb aabb = GetSimulatedBodyAabb(entityId);
+            // convex shapes used to export the sphere mesh requires a higher toleance
+            // when checking its aabb due to the lower tesselation it does to cover the sphere.
+            EXPECT_THAT(aabb.GetMin(), UnitTest::IsCloseTolerance(AZ::Vector3(-1.0f, -0.55f, -1.75f), 1e-1f));
+            EXPECT_THAT(aabb.GetMax(), UnitTest::IsCloseTolerance(AZ::Vector3(1.0f, 0.55f, 1.75f), 1e-1f));
         }
         }
 
 
-        const AZ::Aabb aabb = simulatedBody->GetAabb();
-        // convex shapes used to export the sphere mesh requires a higher toleance
-        // when checking its aabb due to the lower tesselation it does to cover the sphere.
-        EXPECT_THAT(aabb.GetMin(), UnitTest::IsCloseTolerance(AZ::Vector3(-1.0f, -0.55f, -1.75f), 1e-1f));
-        EXPECT_THAT(aabb.GetMax(), UnitTest::IsCloseTolerance(AZ::Vector3(1.0f, 0.55f, 1.75f), 1e-1f));
+        EXPECT_TRUE(MeshColliderHasOnePhysicsAssetShapeType(gameEntity->FindComponent<PhysX::MeshColliderComponent>()));
 
 
         delete meshAssetData;
         delete meshAssetData;
     }
     }
@@ -428,39 +366,18 @@ namespace PhysXEditorTests
 
 
         EntityPtr gameEntity = CreateActiveGameEntityFromEditorEntity(editorEntity.get());
         EntityPtr gameEntity = CreateActiveGameEntityFromEditorEntity(editorEntity.get());
 
 
-        // check that the runtime entity has the expected components
-        auto* meshColliderComponent = gameEntity->FindComponent<PhysX::MeshColliderComponent>();
-        auto* staticRigidBodyComponent = gameEntity->FindComponent<PhysX::StaticRigidBodyComponent>();
-        EXPECT_TRUE(meshColliderComponent != nullptr);
-        EXPECT_TRUE(staticRigidBodyComponent != nullptr);
-
-        AzPhysics::ShapeColliderPairList shapeConfigList = meshColliderComponent->GetShapeConfigurations();
-        EXPECT_EQ(shapeConfigList.size(), 1);
-
-        for (const auto& shapeConfigPair : shapeConfigList)
+        for (const auto& entityId : { editorEntity->GetId(), gameEntity->GetId() })
         {
         {
-            EXPECT_EQ(shapeConfigPair.second->GetShapeType(), Physics::ShapeType::PhysicsAsset);
-        }
-
-        const auto* simulatedBody = staticRigidBodyComponent->GetSimulatedBody();
-        const auto* pxRigidStatic = static_cast<const physx::PxRigidStatic*>(simulatedBody->GetNativePointer());
+            EXPECT_EQ(GetSimulatedBodyFirstPxGeometryType(entityId), physx::PxGeometryType::eCONVEXMESH);
 
 
-        PHYSX_SCENE_READ_LOCK(pxRigidStatic->getScene());
-
-        // there should be a single shape on the rigid body and it should be a box
-        EXPECT_EQ(pxRigidStatic->getNbShapes(), 1);
-        if (pxRigidStatic->getNbShapes() > 0)
-        {
-            physx::PxShape* shape = nullptr;
-            pxRigidStatic->getShapes(&shape, 1, 0);
-            EXPECT_EQ(shape->getGeometryType(), physx::PxGeometryType::eCONVEXMESH);
+            const AZ::Aabb aabb = GetSimulatedBodyAabb(entityId);
+            // convex shapes used to export the sphere mesh requires a higher toleance
+            // when checking its aabb due to the lower tesselation it does to cover the sphere.
+            EXPECT_THAT(aabb.GetMin(), UnitTest::IsCloseTolerance(AZ::Vector3(-1.0f, -0.825f, -1.75f), 1e-1f));
+            EXPECT_THAT(aabb.GetMax(), UnitTest::IsCloseTolerance(AZ::Vector3(1.0f, 0.825f, 1.75f), 1e-1f));
         }
         }
 
 
-        const AZ::Aabb aabb = simulatedBody->GetAabb();
-        // convex shapes used to export the sphere mesh requires a higher toleance
-        // when checking its aabb due to the lower tesselation it does to cover the sphere.
-        EXPECT_THAT(aabb.GetMin(), UnitTest::IsCloseTolerance(AZ::Vector3(-1.0f, -0.825f, -1.75f), 1e-1f));
-        EXPECT_THAT(aabb.GetMax(), UnitTest::IsCloseTolerance(AZ::Vector3(1.0f, 0.825f, 1.75f), 1e-1f));
+        EXPECT_TRUE(MeshColliderHasOnePhysicsAssetShapeType(gameEntity->FindComponent<PhysX::MeshColliderComponent>()));
 
 
         delete meshAssetData;
         delete meshAssetData;
     }
     }
@@ -476,37 +393,16 @@ namespace PhysXEditorTests
 
 
         EntityPtr gameEntity = CreateActiveGameEntityFromEditorEntity(editorEntity.get());
         EntityPtr gameEntity = CreateActiveGameEntityFromEditorEntity(editorEntity.get());
 
 
-        // check that the runtime entity has the expected components
-        auto* meshColliderComponent = gameEntity->FindComponent<PhysX::MeshColliderComponent>();
-        auto* staticRigidBodyComponent = gameEntity->FindComponent<PhysX::StaticRigidBodyComponent>();
-        EXPECT_TRUE(meshColliderComponent != nullptr);
-        EXPECT_TRUE(staticRigidBodyComponent != nullptr);
-
-        AzPhysics::ShapeColliderPairList shapeConfigList = meshColliderComponent->GetShapeConfigurations();
-        EXPECT_EQ(shapeConfigList.size(), 1);
-
-        for (const auto& shapeConfigPair : shapeConfigList)
+        for (const auto& entityId : { editorEntity->GetId(), gameEntity->GetId() })
         {
         {
-            EXPECT_EQ(shapeConfigPair.second->GetShapeType(), Physics::ShapeType::PhysicsAsset);
-        }
+            EXPECT_EQ(GetSimulatedBodyFirstPxGeometryType(entityId), physx::PxGeometryType::eTRIANGLEMESH);
 
 
-        const auto* simulatedBody = staticRigidBodyComponent->GetSimulatedBody();
-        const auto* pxRigidStatic = static_cast<const physx::PxRigidStatic*>(simulatedBody->GetNativePointer());
-
-        PHYSX_SCENE_READ_LOCK(pxRigidStatic->getScene());
-
-        // there should be a single shape on the rigid body and it should be a box
-        EXPECT_EQ(pxRigidStatic->getNbShapes(), 1);
-        if (pxRigidStatic->getNbShapes() > 0)
-        {
-            physx::PxShape* shape = nullptr;
-            pxRigidStatic->getShapes(&shape, 1, 0);
-            EXPECT_EQ(shape->getGeometryType(), physx::PxGeometryType::eTRIANGLEMESH);
+            const AZ::Aabb aabb = GetSimulatedBodyAabb(entityId);
+            EXPECT_THAT(aabb.GetMin(), UnitTest::IsCloseTolerance(AZ::Vector3(-0.5f, -0.5f, -0.5f), 1e-3f));
+            EXPECT_THAT(aabb.GetMax(), UnitTest::IsCloseTolerance(AZ::Vector3(0.5f, 0.5f, 0.5f), 1e-3f));
         }
         }
 
 
-        const AZ::Aabb aabb = simulatedBody->GetAabb();
-        EXPECT_THAT(aabb.GetMin(), UnitTest::IsCloseTolerance(AZ::Vector3(-0.5f, -0.5f, -0.5f), 1e-3f));
-        EXPECT_THAT(aabb.GetMax(), UnitTest::IsCloseTolerance(AZ::Vector3(0.5f, 0.5f, 0.5f), 1e-3f));
+        EXPECT_TRUE(MeshColliderHasOnePhysicsAssetShapeType(gameEntity->FindComponent<PhysX::MeshColliderComponent>()));
 
 
         delete meshAssetData;
         delete meshAssetData;
     }
     }
@@ -528,37 +424,16 @@ namespace PhysXEditorTests
 
 
         EntityPtr gameEntity = CreateActiveGameEntityFromEditorEntity(editorEntity.get());
         EntityPtr gameEntity = CreateActiveGameEntityFromEditorEntity(editorEntity.get());
 
 
-        // check that the runtime entity has the expected components
-        auto* meshColliderComponent = gameEntity->FindComponent<PhysX::MeshColliderComponent>();
-        auto* staticRigidBodyComponent = gameEntity->FindComponent<PhysX::StaticRigidBodyComponent>();
-        EXPECT_TRUE(meshColliderComponent != nullptr);
-        EXPECT_TRUE(staticRigidBodyComponent != nullptr);
-
-        AzPhysics::ShapeColliderPairList shapeConfigList = meshColliderComponent->GetShapeConfigurations();
-        EXPECT_EQ(shapeConfigList.size(), 1);
-
-        for (const auto& shapeConfigPair : shapeConfigList)
+        for (const auto& entityId : { editorEntity->GetId(), gameEntity->GetId() })
         {
         {
-            EXPECT_EQ(shapeConfigPair.second->GetShapeType(), Physics::ShapeType::PhysicsAsset);
-        }
-
-        const auto* simulatedBody = staticRigidBodyComponent->GetSimulatedBody();
-        const auto* pxRigidStatic = static_cast<const physx::PxRigidStatic*>(simulatedBody->GetNativePointer());
-
-        PHYSX_SCENE_READ_LOCK(pxRigidStatic->getScene());
+            EXPECT_EQ(GetSimulatedBodyFirstPxGeometryType(entityId), physx::PxGeometryType::eTRIANGLEMESH);
 
 
-        // there should be a single shape on the rigid body and it should be a box
-        EXPECT_EQ(pxRigidStatic->getNbShapes(), 1);
-        if (pxRigidStatic->getNbShapes() > 0)
-        {
-            physx::PxShape* shape = nullptr;
-            pxRigidStatic->getShapes(&shape, 1, 0);
-            EXPECT_EQ(shape->getGeometryType(), physx::PxGeometryType::eTRIANGLEMESH);
+            const AZ::Aabb aabb = GetSimulatedBodyAabb(entityId);
+            EXPECT_THAT(aabb.GetMin(), UnitTest::IsCloseTolerance(AZ::Vector3(-1.0f, -0.55f, -1.75f), 1e-3f));
+            EXPECT_THAT(aabb.GetMax(), UnitTest::IsCloseTolerance(AZ::Vector3(1.0f, 0.55f, 1.75f), 1e-3f));
         }
         }
 
 
-        const AZ::Aabb aabb = simulatedBody->GetAabb();
-        EXPECT_THAT(aabb.GetMin(), UnitTest::IsCloseTolerance(AZ::Vector3(-1.0f, -0.55f, -1.75f), 1e-3f));
-        EXPECT_THAT(aabb.GetMax(), UnitTest::IsCloseTolerance(AZ::Vector3(1.0f, 0.55f, 1.75f), 1e-3f));
+        EXPECT_TRUE(MeshColliderHasOnePhysicsAssetShapeType(gameEntity->FindComponent<PhysX::MeshColliderComponent>()));
 
 
         delete meshAssetData;
         delete meshAssetData;
     }
     }
@@ -586,37 +461,16 @@ namespace PhysXEditorTests
 
 
         EntityPtr gameEntity = CreateActiveGameEntityFromEditorEntity(editorEntity.get());
         EntityPtr gameEntity = CreateActiveGameEntityFromEditorEntity(editorEntity.get());
 
 
-        // check that the runtime entity has the expected components
-        auto* meshColliderComponent = gameEntity->FindComponent<PhysX::MeshColliderComponent>();
-        auto* staticRigidBodyComponent = gameEntity->FindComponent<PhysX::StaticRigidBodyComponent>();
-        EXPECT_TRUE(meshColliderComponent != nullptr);
-        EXPECT_TRUE(staticRigidBodyComponent != nullptr);
-
-        AzPhysics::ShapeColliderPairList shapeConfigList = meshColliderComponent->GetShapeConfigurations();
-        EXPECT_EQ(shapeConfigList.size(), 1);
-
-        for (const auto& shapeConfigPair : shapeConfigList)
+        for (const auto& entityId : { editorEntity->GetId(), gameEntity->GetId() })
         {
         {
-            EXPECT_EQ(shapeConfigPair.second->GetShapeType(), Physics::ShapeType::PhysicsAsset);
-        }
-
-        const auto* simulatedBody = staticRigidBodyComponent->GetSimulatedBody();
-        const auto* pxRigidStatic = static_cast<const physx::PxRigidStatic*>(simulatedBody->GetNativePointer());
+            EXPECT_EQ(GetSimulatedBodyFirstPxGeometryType(entityId), physx::PxGeometryType::eTRIANGLEMESH);
 
 
-        PHYSX_SCENE_READ_LOCK(pxRigidStatic->getScene());
-
-        // there should be a single shape on the rigid body and it should be a box
-        EXPECT_EQ(pxRigidStatic->getNbShapes(), 1);
-        if (pxRigidStatic->getNbShapes() > 0)
-        {
-            physx::PxShape* shape = nullptr;
-            pxRigidStatic->getShapes(&shape, 1, 0);
-            EXPECT_EQ(shape->getGeometryType(), physx::PxGeometryType::eTRIANGLEMESH);
+            const AZ::Aabb aabb = GetSimulatedBodyAabb(entityId);
+            EXPECT_THAT(aabb.GetMin(), UnitTest::IsCloseTolerance(AZ::Vector3(-1.0f, -0.825f, -1.75f), 1e-3f));
+            EXPECT_THAT(aabb.GetMax(), UnitTest::IsCloseTolerance(AZ::Vector3(1.0f, 0.825f, 1.75f), 1e-3f));
         }
         }
 
 
-        const AZ::Aabb aabb = simulatedBody->GetAabb();
-        EXPECT_THAT(aabb.GetMin(), UnitTest::IsCloseTolerance(AZ::Vector3(-1.0f, -0.825f, -1.75f), 1e-3f));
-        EXPECT_THAT(aabb.GetMax(), UnitTest::IsCloseTolerance(AZ::Vector3(1.0f, 0.825f, 1.75f), 1e-3f));
+        EXPECT_TRUE(MeshColliderHasOnePhysicsAssetShapeType(gameEntity->FindComponent<PhysX::MeshColliderComponent>()));
 
 
         delete meshAssetData;
         delete meshAssetData;
     }
     }
@@ -638,7 +492,9 @@ namespace PhysXEditorTests
             AZStd::nullopt,
             AZStd::nullopt,
             RigidBodyType::Dynamic);
             RigidBodyType::Dynamic);
 
 
-        EXPECT_EQ(errorHandler.GetExpectedErrorCount(), 1);
+        // The error appears twice because the CreateMeshColliderEditorEntity helper activates
+        // the entity twice when using dynamic rigid bodies.
+        EXPECT_EQ(errorHandler.GetExpectedErrorCount(), 2);
 
 
         delete meshAssetData;
         delete meshAssetData;
     }
     }

+ 50 - 6
Gems/PhysX/Code/Tests/EditorTestUtilities.cpp

@@ -30,6 +30,16 @@
 
 
 namespace PhysXEditorTests
 namespace PhysXEditorTests
 {
 {
+    // This function reactivates the entity to cause the simulated body to be recreated.
+    // This is necessary when modifying properties that affect a dynamic rigid body,
+    // because it will delay applying the changes until the next simulation tick,
+    // which happens automatically in the editor but not in test environment.
+    static void ForceSimulatedBodyRecreation(AZ::Entity& entity)
+    {
+        entity.Deactivate();
+        entity.Activate();
+    }
+
     EntityPtr CreateInactiveEditorEntity(const char* entityName)
     EntityPtr CreateInactiveEditorEntity(const char* entityName)
     {
     {
         AZ::Entity* entity = nullptr;
         AZ::Entity* entity = nullptr;
@@ -85,6 +95,11 @@ namespace PhysXEditorTests
             AZ::NonUniformScaleRequestBus::Event(editorEntity->GetId(), &AZ::NonUniformScaleRequests::SetScale, *nonUniformScale);
             AZ::NonUniformScaleRequestBus::Event(editorEntity->GetId(), &AZ::NonUniformScaleRequests::SetScale, *nonUniformScale);
         }
         }
 
 
+        if (rigidBodyType == RigidBodyType::Dynamic)
+        {
+            ForceSimulatedBodyRecreation(*editorEntity);
+        }
+
         return editorEntity;
         return editorEntity;
     }
     }
 
 
@@ -127,6 +142,11 @@ namespace PhysXEditorTests
             AZ::NonUniformScaleRequestBus::Event(editorEntity->GetId(), &AZ::NonUniformScaleRequests::SetScale, *nonUniformScale);
             AZ::NonUniformScaleRequestBus::Event(editorEntity->GetId(), &AZ::NonUniformScaleRequests::SetScale, *nonUniformScale);
         }
         }
 
 
+        if (rigidBodyType == RigidBodyType::Dynamic)
+        {
+            ForceSimulatedBodyRecreation(*editorEntity);
+        }
+
         return editorEntity;
         return editorEntity;
     }
     }
 
 
@@ -165,6 +185,11 @@ namespace PhysXEditorTests
             AZ::NonUniformScaleRequestBus::Event(editorEntity->GetId(), &AZ::NonUniformScaleRequests::SetScale, *nonUniformScale);
             AZ::NonUniformScaleRequestBus::Event(editorEntity->GetId(), &AZ::NonUniformScaleRequests::SetScale, *nonUniformScale);
         }
         }
 
 
+        if (rigidBodyType == RigidBodyType::Dynamic)
+        {
+            ForceSimulatedBodyRecreation(*editorEntity);
+        }
+
         return editorEntity;
         return editorEntity;
     }
     }
 
 
@@ -210,6 +235,11 @@ namespace PhysXEditorTests
             AZ::NonUniformScaleRequestBus::Event(editorEntity->GetId(), &AZ::NonUniformScaleRequests::SetScale, *nonUniformScale);
             AZ::NonUniformScaleRequestBus::Event(editorEntity->GetId(), &AZ::NonUniformScaleRequests::SetScale, *nonUniformScale);
         }
         }
 
 
+        if (rigidBodyType == RigidBodyType::Dynamic)
+        {
+            ForceSimulatedBodyRecreation(*editorEntity);
+        }
+
         return editorEntity;
         return editorEntity;
     }
     }
 
 
@@ -256,6 +286,11 @@ namespace PhysXEditorTests
             AZ::NonUniformScaleRequestBus::Event(editorEntity->GetId(), &AZ::NonUniformScaleRequests::SetScale, *nonUniformScale);
             AZ::NonUniformScaleRequestBus::Event(editorEntity->GetId(), &AZ::NonUniformScaleRequests::SetScale, *nonUniformScale);
         }
         }
 
 
+        if (rigidBodyType == RigidBodyType::Dynamic)
+        {
+            ForceSimulatedBodyRecreation(*editorEntity);
+        }
+
         return editorEntity;
         return editorEntity;
     }
     }
 
 
@@ -300,6 +335,11 @@ namespace PhysXEditorTests
             AZ::NonUniformScaleRequestBus::Event(editorEntity->GetId(), &AZ::NonUniformScaleRequests::SetScale, *nonUniformScale);
             AZ::NonUniformScaleRequestBus::Event(editorEntity->GetId(), &AZ::NonUniformScaleRequests::SetScale, *nonUniformScale);
         }
         }
 
 
+        if (rigidBodyType == RigidBodyType::Dynamic)
+        {
+            ForceSimulatedBodyRecreation(*editorEntity);
+        }
+
         return editorEntity;
         return editorEntity;
     }
     }
 
 
@@ -345,9 +385,10 @@ namespace PhysXEditorTests
             AZ::NonUniformScaleRequestBus::Event(editorEntity->GetId(), &AZ::NonUniformScaleRequests::SetScale, *nonUniformScale);
             AZ::NonUniformScaleRequestBus::Event(editorEntity->GetId(), &AZ::NonUniformScaleRequests::SetScale, *nonUniformScale);
         }
         }
 
 
-        // reactivate the entity to recreate the editor world body, which happens automatically in the editor but not in test environment
-        editorEntity->Deactivate();
-        editorEntity->Activate();
+        if (rigidBodyType == RigidBodyType::Dynamic)
+        {
+            ForceSimulatedBodyRecreation(*editorEntity);
+        }
 
 
         return editorEntity;
         return editorEntity;
     }
     }
@@ -395,6 +436,11 @@ namespace PhysXEditorTests
             AZ::NonUniformScaleRequestBus::Event(editorEntity->GetId(), &AZ::NonUniformScaleRequests::SetScale, *nonUniformScale);
             AZ::NonUniformScaleRequestBus::Event(editorEntity->GetId(), &AZ::NonUniformScaleRequests::SetScale, *nonUniformScale);
         }
         }
 
 
+        if (rigidBodyType == RigidBodyType::Dynamic)
+        {
+            ForceSimulatedBodyRecreation(*editorEntity);
+        }
+
         return editorEntity;
         return editorEntity;
     }
     }
 
 
@@ -405,9 +451,7 @@ namespace PhysXEditorTests
             simulatedBody, entityId, &AzPhysics::SimulatedBodyComponentRequests::GetSimulatedBody);
             simulatedBody, entityId, &AzPhysics::SimulatedBodyComponentRequests::GetSimulatedBody);
         if (simulatedBody)
         if (simulatedBody)
         {
         {
-            const auto* pxActor = static_cast<const physx::PxActor*>(simulatedBody->GetNativePointer());
-            PHYSX_SCENE_READ_LOCK(pxActor->getScene());
-            return PxMathConvert(pxActor->getWorldBounds(1.0f));
+            return simulatedBody->GetAabb();
         }
         }
         return AZ::Aabb::CreateNull();
         return AZ::Aabb::CreateNull();
     }
     }