diff --git a/Code/Framework/AzFramework/AzFramework/Physics/RigidBody.h b/Code/Framework/AzFramework/AzFramework/Physics/RigidBody.h deleted file mode 100644 index 13d29b6bb9..0000000000 --- a/Code/Framework/AzFramework/AzFramework/Physics/RigidBody.h +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include -#include - -#include -#include - -namespace -{ - class ReflectContext; -} - -namespace Physics -{ - class ShapeConfiguration; - class World; - class Shape; - - /// Default values used for initializing RigidBodySettings. - /// These can be modified by Physics Implementation gems. // O3DE_DEPRECATED(LY-114472) - DefaultRigidBodyConfiguration values are not shared across modules. - // Use RigidBodyConfiguration default values. - struct DefaultRigidBodyConfiguration - { - static float m_mass; - static bool m_computeInertiaTensor; - static float m_linearDamping; - static float m_angularDamping; - static float m_sleepMinEnergy; - static float m_maxAngularVelocity; - }; - - enum class MassComputeFlags : AZ::u8 - { - NONE = 0, - - //! Flags indicating whether a certain mass property should be auto-computed or not. - COMPUTE_MASS = 1, - COMPUTE_INERTIA = 1 << 1, - COMPUTE_COM = 1 << 2, - - //! If set, non-simulated shapes will also be included in the mass properties calculation. - INCLUDE_ALL_SHAPES = 1 << 3, - - DEFAULT = COMPUTE_COM | COMPUTE_INERTIA | COMPUTE_MASS - }; - - class RigidBodyConfiguration - : public WorldBodyConfiguration - { - public: - AZ_CLASS_ALLOCATOR(RigidBodyConfiguration, AZ::SystemAllocator, 0); - AZ_RTTI(RigidBodyConfiguration, "{ACFA8900-8530-4744-AF00-AA533C868A8E}", WorldBodyConfiguration); - static void Reflect(AZ::ReflectContext* context); - - enum PropertyVisibility : AZ::u16 - { - InitialVelocities = 1 << 0, ///< Whether the initial linear and angular velocities are visible. - InertiaProperties = 1 << 1, ///< Whether the whole category of inertia properties (mass, compute inertia, - ///< inertia tensor etc) is visible. - Damping = 1 << 2, ///< Whether linear and angular damping are visible. - SleepOptions = 1 << 3, ///< Whether the sleep threshold and start asleep options are visible. - Interpolation = 1 << 4, ///< Whether the interpolation option is visible. - Gravity = 1 << 5, ///< Whether the effected by gravity option is visible. - Kinematic = 1 << 6, ///< Whether the option to make the body kinematic is visible. - ContinuousCollisionDetection = 1 << 7, ///< Whether the option to enable continuous collision detection is visible. - MaxVelocities = 1 << 8 ///< Whether upper limits on velocities are visible. - }; - - RigidBodyConfiguration() = default; - RigidBodyConfiguration(const RigidBodyConfiguration& settings) = default; - - // Visibility functions. - AZ::Crc32 GetPropertyVisibility(PropertyVisibility property) const; - void SetPropertyVisibility(PropertyVisibility property, bool isVisible); - - AZ::Crc32 GetInitialVelocitiesVisibility() const; - /// Returns whether the whole category of inertia settings (mass, inertia, center of mass offset etc) is visible. - AZ::Crc32 GetInertiaSettingsVisibility() const; - /// Returns whether the individual inertia tensor field is visible or is hidden because the compute inertia option is selected. - AZ::Crc32 GetInertiaVisibility() const; - /// Returns whether the mass field is visible or is hidden because compute mass option is selected. - AZ::Crc32 GetMassVisibility() const; - /// Returns whether the individual centre of mass offset field is visible or is hidden because compute CoM option is selected. - AZ::Crc32 GetCoMVisibility() const; - AZ::Crc32 GetDampingVisibility() const; - AZ::Crc32 GetSleepOptionsVisibility() const; - AZ::Crc32 GetInterpolationVisibility() const; - AZ::Crc32 GetGravityVisibility() const; - AZ::Crc32 GetKinematicVisibility() const; - AZ::Crc32 GetCCDVisibility() const; - AZ::Crc32 GetMaxVelocitiesVisibility() const; - MassComputeFlags GetMassComputeFlags() const; - void SetMassComputeFlags(MassComputeFlags flags); - - bool IsCCDEnabled() const; - - // Basic initial settings. - AZ::Vector3 m_initialLinearVelocity = AZ::Vector3::CreateZero(); - AZ::Vector3 m_initialAngularVelocity = AZ::Vector3::CreateZero(); - AZ::Vector3 m_centerOfMassOffset = AZ::Vector3::CreateZero(); - - // Simulation parameters. - float m_mass = DefaultRigidBodyConfiguration::m_mass; - AZ::Matrix3x3 m_inertiaTensor = AZ::Matrix3x3::CreateIdentity(); - float m_linearDamping = DefaultRigidBodyConfiguration::m_linearDamping; - float m_angularDamping = DefaultRigidBodyConfiguration::m_angularDamping; - float m_sleepMinEnergy = DefaultRigidBodyConfiguration::m_sleepMinEnergy; - float m_maxAngularVelocity = DefaultRigidBodyConfiguration::m_maxAngularVelocity; - - // Visibility settings. - AZ::u16 m_propertyVisibilityFlags = (std::numeric_limits::max)(); - - bool m_startAsleep = false; - bool m_interpolateMotion = false; - bool m_gravityEnabled = true; - bool m_simulated = true; - bool m_kinematic = false; - bool m_ccdEnabled = false; ///< Whether continuous collision detection is enabled. - float m_ccdMinAdvanceCoefficient = 0.15f; ///< Coefficient affecting how granularly time is subdivided in CCD. - bool m_ccdFrictionEnabled = false; ///< Whether friction is applied when resolving CCD collisions. - - bool m_computeCenterOfMass = true; - bool m_computeInertiaTensor = true; - bool m_computeMass = true; - - //! If set, non-simulated shapes will also be included in the mass properties calculation. - bool m_includeAllShapesInMassCalculation = false; - }; - - /// Dynamic rigid body. - class RigidBody - : public WorldBody - { - public: - - AZ_CLASS_ALLOCATOR(RigidBody, AZ::SystemAllocator, 0); - AZ_RTTI(RigidBody, "{156E459F-7BB7-4B4E-ADA0-2130D96B7E80}", WorldBody); - - public: - RigidBody() = default; - explicit RigidBody(const RigidBodyConfiguration& settings); - - - virtual void AddShape(AZStd::shared_ptr shape) = 0; - virtual void RemoveShape(AZStd::shared_ptr shape) = 0; - virtual AZ::u32 GetShapeCount() { return 0; } - virtual AZStd::shared_ptr GetShape(AZ::u32 /*index*/) { return nullptr; } - - virtual AZ::Vector3 GetCenterOfMassWorld() const = 0; - virtual AZ::Vector3 GetCenterOfMassLocal() const = 0; - - virtual AZ::Matrix3x3 GetInverseInertiaWorld() const = 0; - virtual AZ::Matrix3x3 GetInverseInertiaLocal() const = 0; - - virtual float GetMass() const = 0; - virtual float GetInverseMass() const = 0; - virtual void SetMass(float mass) = 0; - virtual void SetCenterOfMassOffset(const AZ::Vector3& comOffset) = 0; - - /// Retrieves the velocity at center of mass; only linear velocity, no rotational velocity contribution. - virtual AZ::Vector3 GetLinearVelocity() const = 0; - virtual void SetLinearVelocity(const AZ::Vector3& velocity) = 0; - virtual AZ::Vector3 GetAngularVelocity() const = 0; - virtual void SetAngularVelocity(const AZ::Vector3& angularVelocity) = 0; - virtual AZ::Vector3 GetLinearVelocityAtWorldPoint(const AZ::Vector3& worldPoint) = 0; - virtual void ApplyLinearImpulse(const AZ::Vector3& impulse) = 0; - virtual void ApplyLinearImpulseAtWorldPoint(const AZ::Vector3& impulse, const AZ::Vector3& worldPoint) = 0; - virtual void ApplyAngularImpulse(const AZ::Vector3& angularImpulse) = 0; - - virtual float GetLinearDamping() const = 0; - virtual void SetLinearDamping(float damping) = 0; - virtual float GetAngularDamping() const = 0; - virtual void SetAngularDamping(float damping) = 0; - - virtual bool IsAwake() const = 0; - virtual void ForceAsleep() = 0; - virtual void ForceAwake() = 0; - virtual float GetSleepThreshold() const = 0; - virtual void SetSleepThreshold(float threshold) = 0; - - virtual bool IsKinematic() const = 0; - virtual void SetKinematic(bool kinematic) = 0; - virtual void SetKinematicTarget(const AZ::Transform& targetPosition) = 0; - - virtual bool IsGravityEnabled() const = 0; - virtual void SetGravityEnabled(bool enabled) = 0; - virtual void SetSimulationEnabled(bool enabled) = 0; - virtual void SetCCDEnabled(bool enabled) = 0; - - //! Recalculates mass, inertia and center of mass based on the flags passed. - //! @param flags MassComputeFlags specifying which properties should be recomputed. - //! @param centerOfMassOffsetOverride Optional override of the center of mass. Note: This parameter will be ignored if COMPUTE_COM is passed in flags. - //! @param inertiaTensorOverride Optional override of the inertia. Note: This parameter will be ignored if COMPUTE_INERTIA is passed in flags. - //! @param massOverride Optional override of the mass. Note: This parameter will be ignored if COMPUTE_MASS is passed in flags. - virtual void UpdateMassProperties(MassComputeFlags flags = MassComputeFlags::DEFAULT, - const AZ::Vector3* centerOfMassOffsetOverride = nullptr, - const AZ::Matrix3x3* inertiaTensorOverride = nullptr, - const float* massOverride = nullptr) = 0; - }; - - /// Bitwise operators for MassComputeFlags - inline MassComputeFlags operator|(MassComputeFlags lhs, MassComputeFlags rhs) - { - return aznumeric_cast(aznumeric_cast(lhs) | aznumeric_cast(rhs)); - } - - inline MassComputeFlags operator&(MassComputeFlags lhs, MassComputeFlags rhs) - { - return aznumeric_cast(aznumeric_cast(lhs) & aznumeric_cast(rhs)); - } - - /// Static rigid body. - class RigidBodyStatic - : public WorldBody - { - public: - AZ_CLASS_ALLOCATOR(RigidBodyStatic, AZ::SystemAllocator, 0); - AZ_RTTI(RigidBodyStatic, "{13A677BB-7085-4EDB-BCC8-306548238692}", WorldBody); - - virtual void AddShape(const AZStd::shared_ptr& shape) = 0; - virtual AZ::u32 GetShapeCount() { return 0; } - virtual AZStd::shared_ptr GetShape(AZ::u32 /*index*/) { return nullptr; } - }; -} // namespace Physics diff --git a/Code/Framework/AzFramework/AzFramework/Physics/SimulatedBodies/RigidBody.h b/Code/Framework/AzFramework/AzFramework/Physics/SimulatedBodies/RigidBody.h index 3c0a1afa1d..e9bf8a7307 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/SimulatedBodies/RigidBody.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/SimulatedBodies/RigidBody.h @@ -89,9 +89,9 @@ namespace AzPhysics //! @param inertiaTensorOverride Optional override of the inertia. Note: This parameter will be ignored if COMPUTE_INERTIA is passed in flags. //! @param massOverride Optional override of the mass. Note: This parameter will be ignored if COMPUTE_MASS is passed in flags. virtual void UpdateMassProperties(MassComputeFlags flags = MassComputeFlags::DEFAULT, - const AZ::Vector3* centerOfMassOffsetOverride = nullptr, - const AZ::Matrix3x3* inertiaTensorOverride = nullptr, - const float* massOverride = nullptr) = 0; + const AZ::Vector3& centerOfMassOffsetOverride = AZ::Vector3::CreateZero(), + const AZ::Matrix3x3& inertiaTensorOverride = AZ::Matrix3x3::CreateIdentity(), + const float massOverride = 1.0f) = 0; }; } // namespace AzPhysics diff --git a/Gems/Blast/Code/Tests/Mocks/BlastMocks.h b/Gems/Blast/Code/Tests/Mocks/BlastMocks.h index dddd1e275a..1fe6e35d75 100644 --- a/Gems/Blast/Code/Tests/Mocks/BlastMocks.h +++ b/Gems/Blast/Code/Tests/Mocks/BlastMocks.h @@ -344,9 +344,9 @@ namespace Blast void UpdateMassProperties( [[maybe_unused]] AzPhysics::MassComputeFlags flags, - [[maybe_unused]] const AZ::Vector3* centerOfMassOffsetOverride, - [[maybe_unused]] const AZ::Matrix3x3* inertiaTensorOverride, - [[maybe_unused]] const float* massOverride) override + [[maybe_unused]] const AZ::Vector3& centerOfMassOffsetOverride, + [[maybe_unused]] const AZ::Matrix3x3& inertiaTensorOverride, + [[maybe_unused]] const float massOverride) override { } diff --git a/Gems/PhysX/Code/Source/RigidBody.cpp b/Gems/PhysX/Code/Source/RigidBody.cpp index f8b22affe0..5b36376da5 100644 --- a/Gems/PhysX/Code/Source/RigidBody.cpp +++ b/Gems/PhysX/Code/Source/RigidBody.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -23,6 +24,28 @@ namespace PhysX { + namespace + { + const AZ::Vector3 DefaultCenterOfMass = AZ::Vector3::CreateZero(); + const float DefaultMass = 1.0f; + const AZ::Matrix3x3 DefaultInertiaTensor = AZ::Matrix3x3::CreateIdentity(); + + bool IsSimulationShape(const physx::PxShape& pxShape) + { + return (pxShape.getFlags() & physx::PxShapeFlag::eSIMULATION_SHAPE); + } + + bool CanShapeComputeMassProperties(const physx::PxShape& pxShape) + { + // Note: List based on computeMassAndInertia function in ExtRigidBodyExt.cpp file in PhysX. + const physx::PxGeometryType::Enum geometryType = pxShape.getGeometryType(); + return geometryType == physx::PxGeometryType::eSPHERE + || geometryType == physx::PxGeometryType::eBOX + || geometryType == physx::PxGeometryType::eCAPSULE + || geometryType == physx::PxGeometryType::eCONVEXMESH; + } + } + void RigidBody::Reflect(AZ::ReflectContext* context) { AZ::SerializeContext* serializeContext = azrtti_cast(context); @@ -152,104 +175,120 @@ namespace PhysX m_shapes.erase(found); } - void RigidBody::UpdateMassProperties(AzPhysics::MassComputeFlags flags, const AZ::Vector3* centerOfMassOffsetOverride, const AZ::Matrix3x3* inertiaTensorOverride, const float* massOverride) + void RigidBody::UpdateMassProperties(AzPhysics::MassComputeFlags flags, const AZ::Vector3& centerOfMassOffsetOverride, const AZ::Matrix3x3& inertiaTensorOverride, const float massOverride) { - // Input validation - bool computeCenterOfMass = AzPhysics::MassComputeFlags::COMPUTE_COM == (flags & AzPhysics::MassComputeFlags::COMPUTE_COM); - AZ_Assert(computeCenterOfMass || centerOfMassOffsetOverride, - "UpdateMassProperties: MassComputeFlags::COMPUTE_COM is not set but COM offset is not specified"); - computeCenterOfMass = computeCenterOfMass || !centerOfMassOffsetOverride; - - bool computeInertiaTensor = AzPhysics::MassComputeFlags::COMPUTE_INERTIA == (flags & AzPhysics::MassComputeFlags::COMPUTE_INERTIA); - AZ_Assert(computeInertiaTensor || inertiaTensorOverride, - "UpdateMassProperties: MassComputeFlags::COMPUTE_INERTIA is not set but inertia tensor is not specified"); - computeInertiaTensor = computeInertiaTensor || !inertiaTensorOverride; - - bool computeMass = AzPhysics::MassComputeFlags::COMPUTE_MASS == (flags & AzPhysics::MassComputeFlags::COMPUTE_MASS); - AZ_Assert(computeMass || massOverride, - "UpdateMassProperties: MassComputeFlags::COMPUTE_MASS is not set but mass is not specified"); - computeMass = computeMass || !massOverride; + const bool computeCenterOfMass = AzPhysics::MassComputeFlags::COMPUTE_COM == (flags & AzPhysics::MassComputeFlags::COMPUTE_COM); + const bool computeInertiaTensor = AzPhysics::MassComputeFlags::COMPUTE_INERTIA == (flags & AzPhysics::MassComputeFlags::COMPUTE_INERTIA); + const bool computeMass = AzPhysics::MassComputeFlags::COMPUTE_MASS == (flags & AzPhysics::MassComputeFlags::COMPUTE_MASS); + const bool needsCompute = computeCenterOfMass || computeInertiaTensor || computeMass; + const bool includeAllShapesInMassCalculation = AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES == (flags & AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES); - AZ::u32 shapesCount = GetShapeCount(); - - // Basic cases when we don't need to compute anything - if (shapesCount == 0 || flags == AzPhysics::MassComputeFlags::NONE) + // Basic case where all properties are set directly. + if (!needsCompute) { - if (massOverride) - { - SetMass(*massOverride); - } - - if (inertiaTensorOverride) - { - SetInertia(*inertiaTensorOverride); - } - - if (centerOfMassOffsetOverride) - { - SetCenterOfMassOffset(*centerOfMassOffsetOverride); - } + SetCenterOfMassOffset(centerOfMassOffsetOverride); + SetMass(massOverride); + SetInertia(inertiaTensorOverride); return; } - // Setup center of mass offset pointer for PxRigidBodyExt::updateMassAndInertia function - AZStd::optional optionalComOverride; - if (!computeCenterOfMass && centerOfMassOffsetOverride) + // If there are no shapes then set the properties directly without computing anything. + if (m_shapes.empty()) { - optionalComOverride = PxMathConvert(*centerOfMassOffsetOverride); + SetCenterOfMassOffset(computeCenterOfMass ? DefaultCenterOfMass : centerOfMassOffsetOverride); + SetMass(computeMass ? DefaultMass : massOverride); + SetInertia(computeInertiaTensor ? DefaultInertiaTensor : inertiaTensorOverride); + return; } - const physx::PxVec3* massLocalPose = optionalComOverride.has_value() ? &optionalComOverride.value() : nullptr; + auto cannotComputeMassProperties = [this, includeAllShapesInMassCalculation] + { + PHYSX_SCENE_READ_LOCK(m_pxRigidActor->getScene()); + return AZStd::any_of(m_shapes.cbegin(), m_shapes.cend(), + [includeAllShapesInMassCalculation](const AZStd::shared_ptr& shape) + { + const physx::PxShape& pxShape = *shape->GetPxShape(); + const bool includeShape = includeAllShapesInMassCalculation || IsSimulationShape(pxShape); + + return includeShape && !CanShapeComputeMassProperties(pxShape); + }); + }; + + // If contains shapes that cannot compute mass properties (triangle mesh, + // plane or heightfield) then default values will be used. + if (cannotComputeMassProperties()) + { + AZ_Warning("RigidBody", !computeCenterOfMass, + "Rigid body '%s' cannot compute COM because it contains triangle mesh, plane or heightfield shapes, it will default to %s.", + GetName().c_str(), AZ::ToString(DefaultCenterOfMass).c_str()); + AZ_Warning("RigidBody", !computeMass, + "Rigid body '%s' cannot compute Mass because it contains triangle mesh, plane or heightfield shapes, it will default to %0.1f.", + GetName().c_str(), DefaultMass); + AZ_Warning("RigidBody", !computeInertiaTensor, + "Rigid body '%s' cannot compute Inertia because it contains triangle mesh, plane or heightfield shapes, it will default to %s.", + GetName().c_str(), AZ::ToString(DefaultInertiaTensor.RetrieveScale()).c_str()); + + SetCenterOfMassOffset(computeCenterOfMass ? DefaultCenterOfMass : centerOfMassOffsetOverride); + SetMass(computeMass ? DefaultMass : massOverride); + SetInertia(computeInertiaTensor ? DefaultInertiaTensor : inertiaTensorOverride); + return; + } - bool includeAllShapesInMassCalculation = - AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES == (flags & AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES); + // Center of mass needs to be considered first since + // it's needed when computing mass and inertia. + if (computeCenterOfMass) + { + // Compute Center of Mass + UpdateCenterOfMass(includeAllShapesInMassCalculation); + } + else + { + SetCenterOfMassOffset(centerOfMassOffsetOverride); + } + const physx::PxVec3 pxCenterOfMass = PxMathConvert(GetCenterOfMassLocal()); - // Handle the case when we don't compute mass - if (!computeMass) + if (computeMass) { + // Gather material densities from all shapes, + // mass computation is based on them. + AZStd::vector densities; + densities.reserve(m_shapes.size()); + for (const auto& shape : m_shapes) + { + densities.emplace_back(shape->GetMaterial()->GetDensity()); + } + + // Compute Mass + Inertia { PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene()); - physx::PxRigidBodyExt::setMassAndUpdateInertia(*m_pxRigidActor, *massOverride, massLocalPose, - includeAllShapesInMassCalculation); + physx::PxRigidBodyExt::updateMassAndInertia(*m_pxRigidActor, + densities.data(), static_cast(densities.size()), + &pxCenterOfMass, includeAllShapesInMassCalculation); } + // There is no physx function to only compute the mass without + // computing the inertia. So now that both have been computed + // we can override the inertia if it's suppose to use a + // specific value set by the user. if (!computeInertiaTensor) { - SetInertia(*inertiaTensorOverride); + SetInertia(inertiaTensorOverride); } - - return; - } - - // Handle the cases when mass should be computed from density - if (shapesCount == 1) - { - AZStd::shared_ptr shape = GetShape(0); - float density = shape->GetMaterial()->GetDensity(); - - PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene()); - physx::PxRigidBodyExt::updateMassAndInertia(*m_pxRigidActor, density, massLocalPose, - includeAllShapesInMassCalculation); } else { - AZStd::vector densities(shapesCount); - for (AZ::u32 i = 0; i < shapesCount; ++i) + if (computeInertiaTensor) { - densities[i] = GetShape(i)->GetMaterial()->GetDensity(); + // Set Mass + Compute Inertia + PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene()); + physx::PxRigidBodyExt::setMassAndUpdateInertia(*m_pxRigidActor, massOverride, + &pxCenterOfMass, includeAllShapesInMassCalculation); + } + else + { + SetMass(massOverride); + SetInertia(inertiaTensorOverride); } - - PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene()); - physx::PxRigidBodyExt::updateMassAndInertia(*m_pxRigidActor, densities.data(), - shapesCount, massLocalPose, includeAllShapesInMassCalculation); - } - - // Set the overrides if provided. - // Note: We don't set the center of mass here because it was already provided - // to PxRigidBodyExt::updateMassAndInertia above - if (!computeInertiaTensor) - { - SetInertia(*inertiaTensorOverride); } } @@ -344,70 +383,57 @@ namespace PhysX } } - void RigidBody::UpdateComputedCenterOfMass() + void RigidBody::UpdateCenterOfMass(bool includeAllShapesInMassCalculation) { - if (m_pxRigidActor) + if (m_shapes.empty()) { - physx::PxU32 shapeCount = 0; - { - PHYSX_SCENE_READ_LOCK(m_pxRigidActor->getScene()); - shapeCount = m_pxRigidActor->getNbShapes(); - } - if (shapeCount > 0) - { - AZStd::vector shapes; - shapes.resize(shapeCount); - - { - PHYSX_SCENE_READ_LOCK(m_pxRigidActor->getScene()); - m_pxRigidActor->getShapes(&shapes[0], shapeCount); - } - - shapes.erase(AZStd::remove_if(shapes.begin() - , shapes.end() - , [](const physx::PxShape* shape) - { - return shape->getFlags() & physx::PxShapeFlag::eTRIGGER_SHAPE; - }) - , shapes.end()); - shapeCount = static_cast(shapes.size()); + SetCenterOfMassOffset(DefaultCenterOfMass); + return; + } - if (shapeCount == 0) - { - SetZeroCenterOfMass(); - return; - } + AZStd::vector pxShapes; + pxShapes.reserve(m_shapes.size()); + { + // Filter shapes in the same way that updateMassAndInertia function does. + PHYSX_SCENE_READ_LOCK(m_pxRigidActor->getScene()); + for (const auto& shape : m_shapes) + { + const physx::PxShape& pxShape = *shape->GetPxShape(); + const bool includeShape = includeAllShapesInMassCalculation || IsSimulationShape(pxShape); - const auto properties = physx::PxRigidBodyExt::computeMassPropertiesFromShapes(&shapes[0], shapeCount); - const physx::PxTransform computedCenterOfMass(properties.centerOfMass); + if (includeShape && CanShapeComputeMassProperties(pxShape)) { - PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene()); - m_pxRigidActor->setCMassLocalPose(computedCenterOfMass); + pxShapes.emplace_back(&pxShape); } } - else - { - SetZeroCenterOfMass(); - } } - } - void RigidBody::SetInertia(const AZ::Matrix3x3& inertia) - { - if (m_pxRigidActor) + if (pxShapes.empty()) { - PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene()); - m_pxRigidActor->setMassSpaceInertiaTensor(PxMathConvert(inertia.RetrieveScale())); + SetCenterOfMassOffset(DefaultCenterOfMass); + return; } + + const physx::PxMassProperties pxMassProperties = [this, &pxShapes] + { + // Note: PhysX computeMassPropertiesFromShapes function does not use densities + // to compute the shape's masses, which are needed to calculate the center of mass. + // This differs from updateMassAndInertia function, which uses material density values. + // So the masses used during center of mass calculation do not match the masses + // used during mass/inertia calculation. This is an inconsistency in PhysX. + PHYSX_SCENE_READ_LOCK(m_pxRigidActor->getScene()); + return physx::PxRigidBodyExt::computeMassPropertiesFromShapes(pxShapes.data(), static_cast(pxShapes.size())); + }(); + + SetCenterOfMassOffset(PxMathConvert(pxMassProperties.centerOfMass)); } - void RigidBody::ComputeInertia() + void RigidBody::SetInertia(const AZ::Matrix3x3& inertia) { if (m_pxRigidActor) { PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene()); - auto localPose = m_pxRigidActor->getCMassLocalPose().p; - physx::PxRigidBodyExt::setMassAndUpdateInertia(*m_pxRigidActor, m_pxRigidActor->getMass(), &localPose); + m_pxRigidActor->setMassSpaceInertiaTensor(PxMathConvert(inertia.RetrieveScale())); } } @@ -783,13 +809,4 @@ namespace PhysX { return m_name; } - - void RigidBody::SetZeroCenterOfMass() - { - if (m_pxRigidActor) - { - PHYSX_SCENE_WRITE_LOCK(m_pxRigidActor->getScene()); - m_pxRigidActor->setCMassLocalPose(physx::PxTransform(PxMathConvert(AZ::Vector3::CreateZero()))); - } - } } diff --git a/Gems/PhysX/Code/Source/RigidBody.h b/Gems/PhysX/Code/Source/RigidBody.h index 10f2ebb556..a20f79b161 100644 --- a/Gems/PhysX/Code/Source/RigidBody.h +++ b/Gems/PhysX/Code/Source/RigidBody.h @@ -109,17 +109,15 @@ namespace PhysX void RemoveShape(AZStd::shared_ptr shape) override; void UpdateMassProperties(AzPhysics::MassComputeFlags flags = AzPhysics::MassComputeFlags::DEFAULT, - const AZ::Vector3* centerOfMassOffsetOverride = nullptr, - const AZ::Matrix3x3* inertiaTensorOverride = nullptr, - const float* massOverride = nullptr) override; + const AZ::Vector3& centerOfMassOffsetOverride = AZ::Vector3::CreateZero(), + const AZ::Matrix3x3& inertiaTensorOverride = AZ::Matrix3x3::CreateIdentity(), + const float massOverride = 1.0f) override; private: void CreatePhysXActor(const AzPhysics::RigidBodyConfiguration& configuration); - void UpdateComputedCenterOfMass(); - void ComputeInertia(); + void UpdateCenterOfMass(bool includeAllShapesInMassCalculation); void SetInertia(const AZ::Matrix3x3& inertia); - void SetZeroCenterOfMass(); AZStd::shared_ptr m_pxRigidActor; AZStd::vector> m_shapes; diff --git a/Gems/PhysX/Code/Source/Scene/PhysXScene.cpp b/Gems/PhysX/Code/Source/Scene/PhysXScene.cpp index 3b5c98ba2d..86e3ceb98f 100644 --- a/Gems/PhysX/Code/Source/Scene/PhysXScene.cpp +++ b/Gems/PhysX/Code/Source/Scene/PhysXScene.cpp @@ -198,8 +198,8 @@ namespace PhysX AZ_Warning("PhysXScene", shapeAdded, "No Collider or Shape information found when creating Rigid body [%s]", configuration->m_debugName.c_str()); } const AzPhysics::MassComputeFlags& flags = configuration->GetMassComputeFlags(); - newBody->UpdateMassProperties(flags, &configuration->m_centerOfMassOffset, - &configuration->m_inertiaTensor, &configuration->m_mass); + newBody->UpdateMassProperties(flags, configuration->m_centerOfMassOffset, + configuration->m_inertiaTensor, configuration->m_mass); crc = AZ::Crc32(newBody, sizeof(*newBody)); return newBody; diff --git a/Gems/PhysX/Code/Tests/PhysXSpecificTest.cpp b/Gems/PhysX/Code/Tests/PhysXSpecificTest.cpp index 0c0eee3eb0..9e3a738370 100644 --- a/Gems/PhysX/Code/Tests/PhysXSpecificTest.cpp +++ b/Gems/PhysX/Code/Tests/PhysXSpecificTest.cpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include @@ -1283,11 +1285,13 @@ namespace PhysX EXPECT_TRUE(AZ::IsClose(expectedMass, mass, 0.001f)); } + // Valid material density values: [0.01f, 1e5f] INSTANTIATE_TEST_CASE_P(PhysX, MultiShapesDensityTestFixture, ::testing::Values( - AZStd::make_pair(std::numeric_limits::min(), std::numeric_limits::max()), - AZStd::make_pair(-std::numeric_limits::max(), 0.0f), - AZStd::make_pair(1.0f, 1e9f) + AZStd::make_pair(0.01f, 0.01f), + AZStd::make_pair(1e5f, 1e5f), + AZStd::make_pair(0.01f, 1e5f), + AZStd::make_pair(2364.0f, 10.0f) )); // Fixture for testing extreme density values @@ -1311,6 +1315,7 @@ namespace PhysX && resultingDensity <= Physics::MaterialConfiguration::MaxDensityLimit); } + // Valid material density values: [0.01f, 1e5f] INSTANTIATE_TEST_CASE_P(PhysX, DensityBoundariesTestFixture, ::testing::Values( std::numeric_limits::min(), @@ -1318,7 +1323,9 @@ namespace PhysX -std::numeric_limits::max(), 0.0f, 1.0f, - 1e9f + 1e9f, + 0.01f, + 1e5f )); enum class SimulatedShapesMode @@ -1329,7 +1336,7 @@ namespace PhysX }; class MassComputeFixture - : public ::testing::TestWithParam<::testing::tuple> + : public ::testing::TestWithParam<::testing::tuple> { public: void SetUp() override final @@ -1349,6 +1356,8 @@ namespace PhysX AzPhysics::SimulatedBodyHandle simBodyHandle = sceneInterface->AddSimulatedBody(m_testSceneHandle, &m_rigidBodyConfig); m_rigidBody = azdynamic_cast(sceneInterface->GetSimulatedBodyFromHandle(m_testSceneHandle, simBodyHandle)); } + + ASSERT_TRUE(m_rigidBody != nullptr); } void TearDown() override final @@ -1363,130 +1372,242 @@ namespace PhysX m_rigidBody = nullptr; } - SimulatedShapesMode GetShapesMode() const + Physics::ShapeType GetShapeType() const { return ::testing::get<0>(GetParam()); } - AzPhysics::MassComputeFlags GetMassComputeFlags() const + SimulatedShapesMode GetShapesMode() const { return ::testing::get<1>(GetParam()); } + AzPhysics::MassComputeFlags GetMassComputeFlags() const + { + const AzPhysics::MassComputeFlags massComputeFlags = ::testing::get<2>(GetParam()); + if (IncludeAllShapes()) + { + return massComputeFlags | AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES; + } + else + { + return massComputeFlags; + } + } + + bool IncludeAllShapes() const + { + return ::testing::get<3>(GetParam()); + } + bool IsMultiShapeTest() const { - return ::testing::get<2>(GetParam()); + return ::testing::get<4>(GetParam()); } bool IsMassExpectedToChange() const { return m_rigidBodyConfig.m_computeMass && - (!(GetShapesMode() == SimulatedShapesMode::NONE) || m_rigidBodyConfig.m_includeAllShapesInMassCalculation); + (GetShapesMode() != SimulatedShapesMode::NONE || m_rigidBodyConfig.m_includeAllShapesInMassCalculation); } bool IsComExpectedToChange() const { return m_rigidBodyConfig.m_computeCenterOfMass && - (!(GetShapesMode() == SimulatedShapesMode::NONE) || m_rigidBodyConfig.m_includeAllShapesInMassCalculation); + (GetShapesMode() != SimulatedShapesMode::NONE || m_rigidBodyConfig.m_includeAllShapesInMassCalculation); } bool IsInertiaExpectedToChange() const { return m_rigidBodyConfig.m_computeInertiaTensor && - (!(GetShapesMode() == SimulatedShapesMode::NONE) || m_rigidBodyConfig.m_includeAllShapesInMassCalculation); + (GetShapesMode() != SimulatedShapesMode::NONE || m_rigidBodyConfig.m_includeAllShapesInMassCalculation); } + AZStd::shared_ptr CreateShape(const Physics::ColliderConfiguration& colliderConfiguration, Physics::ShapeType shapeType) + { + AZStd::shared_ptr shape; + Physics::System* physics = AZ::Interface::Get(); + switch (shapeType) + { + case Physics::ShapeType::Sphere: + shape = physics->CreateShape(colliderConfiguration, Physics::SphereShapeConfiguration()); + break; + case Physics::ShapeType::Box: + shape = physics->CreateShape(colliderConfiguration, Physics::BoxShapeConfiguration()); + break; + case Physics::ShapeType::Capsule: + shape = physics->CreateShape(colliderConfiguration, Physics::CapsuleShapeConfiguration()); + break; + } + return shape; + }; + AzPhysics::RigidBodyConfiguration m_rigidBodyConfig; - AzPhysics::RigidBody* m_rigidBody; + AzPhysics::RigidBody* m_rigidBody = nullptr; AzPhysics::SceneHandle m_testSceneHandle = AzPhysics::InvalidSceneHandle; }; TEST_P(MassComputeFixture, RigidBody_ComputeMassFlagsCombinationsTwoShapes_MassPropertiesCalculatedAccordingly) { - SimulatedShapesMode shapeMode = GetShapesMode(); - AzPhysics::MassComputeFlags massComputeFlags = GetMassComputeFlags(); - bool multiShapeTest = IsMultiShapeTest(); - Physics::System* physics = AZ::Interface::Get(); + const Physics::ShapeType shapeType = GetShapeType(); + const SimulatedShapesMode shapeMode = GetShapesMode(); + const AzPhysics::MassComputeFlags massComputeFlags = GetMassComputeFlags(); + const bool multiShapeTest = IsMultiShapeTest(); // Save initial values - AZ::Vector3 comBefore = m_rigidBody->GetCenterOfMassWorld(); - AZ::Matrix3x3 inertiaBefore = m_rigidBody->GetInverseInertiaWorld(); - float massBefore = m_rigidBody->GetMass(); + const AZ::Vector3 comBefore = m_rigidBody->GetCenterOfMassWorld(); + const AZ::Matrix3x3 inertiaBefore = m_rigidBody->GetInverseInertiaWorld(); + const float massBefore = m_rigidBody->GetMass(); - // Box shape will be simulated for ALL and MIXED shape modes - Physics::ColliderConfiguration boxColliderConfig; - boxColliderConfig.m_isSimulated = + // Shape will be simulated for ALL and MIXED shape modes + Physics::ColliderConfiguration colliderConfig; + colliderConfig.m_isSimulated = (shapeMode == SimulatedShapesMode::ALL || shapeMode == SimulatedShapesMode::MIXED); - boxColliderConfig.m_position = AZ::Vector3(1.0f, 0.0f, 0.0f); + colliderConfig.m_position = AZ::Vector3(1.0f, 0.0f, 0.0f); - AZStd::shared_ptr boxShape = - physics->CreateShape(boxColliderConfig, Physics::BoxShapeConfiguration()); - m_rigidBody->AddShape(boxShape); + AZStd::shared_ptr shape = CreateShape(colliderConfig, shapeType); + m_rigidBody->AddShape(shape); if (multiShapeTest) { // Sphere shape will be simulated only for the ALL shape mode Physics::ColliderConfiguration sphereColliderConfig; sphereColliderConfig.m_isSimulated = (shapeMode == SimulatedShapesMode::ALL); - sphereColliderConfig.m_position = AZ::Vector3(-1.0f, 0.0f, 0.0f); - AZStd::shared_ptr sphereShape = - physics->CreateShape(sphereColliderConfig, Physics::SphereShapeConfiguration()); + sphereColliderConfig.m_position = AZ::Vector3(-2.0f, 0.0f, 0.0f); + AZStd::shared_ptr sphereShape = CreateShape(sphereColliderConfig, Physics::ShapeType::Sphere); m_rigidBody->AddShape(sphereShape); } // Verify swapping materials results in changes in the mass. - m_rigidBody->UpdateMassProperties(massComputeFlags, &m_rigidBodyConfig.m_centerOfMassOffset, - &m_rigidBodyConfig.m_inertiaTensor, &m_rigidBodyConfig.m_mass); + m_rigidBody->UpdateMassProperties(massComputeFlags, m_rigidBodyConfig.m_centerOfMassOffset, + m_rigidBodyConfig.m_inertiaTensor, m_rigidBodyConfig.m_mass); - float massAfter = m_rigidBody->GetMass(); - AZ::Vector3 comAfter = m_rigidBody->GetCenterOfMassWorld(); - AZ::Matrix3x3 inertiaAfter = m_rigidBody->GetInverseInertiaWorld(); + const float massAfter = m_rigidBody->GetMass(); + const AZ::Vector3 comAfter = m_rigidBody->GetCenterOfMassWorld(); + const AZ::Matrix3x3 inertiaAfter = m_rigidBody->GetInverseInertiaWorld(); + using ::testing::Not; + using ::testing::FloatNear; + using ::UnitTest::IsClose; if (IsMassExpectedToChange()) { - EXPECT_FALSE(AZ::IsClose(massBefore, massAfter, FLT_EPSILON)); + EXPECT_THAT(massBefore, Not(FloatNear(massAfter, FLT_EPSILON))); } else { - EXPECT_TRUE(AZ::IsClose(massBefore, massAfter, FLT_EPSILON)); + EXPECT_THAT(massBefore, FloatNear(massAfter, FLT_EPSILON)); } if (IsComExpectedToChange()) { - EXPECT_FALSE(comBefore.IsClose(comAfter)); + EXPECT_THAT(comBefore, Not(IsClose(comAfter))); } else { - EXPECT_TRUE(comBefore.IsClose(comAfter)); + EXPECT_THAT(comBefore, IsClose(comAfter)); } if (IsInertiaExpectedToChange()) { - EXPECT_FALSE(inertiaBefore.IsClose(inertiaAfter)); + EXPECT_THAT(inertiaBefore, Not(IsClose(inertiaAfter))); } else { - EXPECT_TRUE(inertiaBefore.IsClose(inertiaAfter)); + EXPECT_THAT(inertiaBefore, IsClose(inertiaAfter)); } } - AzPhysics::MassComputeFlags possibleMassComputeFlags[] = { - AzPhysics::MassComputeFlags::NONE, AzPhysics::MassComputeFlags::DEFAULT, AzPhysics::MassComputeFlags::COMPUTE_MASS, - AzPhysics::MassComputeFlags::COMPUTE_COM, AzPhysics::MassComputeFlags::COMPUTE_INERTIA, - AzPhysics::MassComputeFlags::DEFAULT | AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES, - AzPhysics::MassComputeFlags::COMPUTE_COM, AzPhysics::MassComputeFlags::COMPUTE_INERTIA, AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES, + static const AzPhysics::MassComputeFlags PossibleMassComputeFlags[] = + { + // No compute + AzPhysics::MassComputeFlags::NONE, + + // Compute Mass only + AzPhysics::MassComputeFlags::COMPUTE_MASS, + + // Compute Inertia only + AzPhysics::MassComputeFlags::COMPUTE_INERTIA, + + // Compute COM only + AzPhysics::MassComputeFlags::COMPUTE_COM, + + // Compute combinations of 2 AzPhysics::MassComputeFlags::COMPUTE_MASS | AzPhysics::MassComputeFlags::COMPUTE_COM, - AzPhysics::MassComputeFlags::COMPUTE_MASS | AzPhysics::MassComputeFlags::COMPUTE_COM | AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES, AzPhysics::MassComputeFlags::COMPUTE_MASS | AzPhysics::MassComputeFlags::COMPUTE_INERTIA, - AzPhysics::MassComputeFlags::COMPUTE_MASS | AzPhysics::MassComputeFlags::COMPUTE_INERTIA | AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES, AzPhysics::MassComputeFlags::COMPUTE_COM | AzPhysics::MassComputeFlags::COMPUTE_INERTIA, - AzPhysics::MassComputeFlags::COMPUTE_COM | AzPhysics::MassComputeFlags::COMPUTE_INERTIA | AzPhysics::MassComputeFlags::INCLUDE_ALL_SHAPES + + // Compute all + AzPhysics::MassComputeFlags::DEFAULT, // COMPUTE_COM | COMPUTE_INERTIA | COMPUTE_MASS }; INSTANTIATE_TEST_CASE_P(PhysX, MassComputeFixture, ::testing::Combine( - ::testing::ValuesIn({ SimulatedShapesMode::NONE, SimulatedShapesMode::MIXED, SimulatedShapesMode::ALL }), - ::testing::ValuesIn(possibleMassComputeFlags), - ::testing::Bool())); + ::testing::ValuesIn({ Physics::ShapeType::Sphere, Physics::ShapeType::Box, Physics::ShapeType::Capsule }), // Values for GetShapeType() + ::testing::ValuesIn({ SimulatedShapesMode::NONE, SimulatedShapesMode::MIXED, SimulatedShapesMode::ALL }), // Values for GetShapesMode() + ::testing::ValuesIn(PossibleMassComputeFlags), // Values for GetMassComputeFlags() + ::testing::Bool(), // Values for IncludeAllShapes() + ::testing::Bool())); // Values for IsMultiShapeTest() + + class MassPropertiesWithTriangleMesh + : public ::testing::TestWithParam + { + public: + void SetUp() override + { + if (auto* physicsSystem = AZ::Interface::Get()) + { + AzPhysics::SceneConfiguration sceneConfiguration = physicsSystem->GetDefaultSceneConfiguration(); + sceneConfiguration.m_sceneName = AzPhysics::DefaultPhysicsSceneName; + m_testSceneHandle = physicsSystem->AddScene(sceneConfiguration); + } + } + + void TearDown() override + { + // Clean up the Test scene + if (auto* physicsSystem = AZ::Interface::Get()) + { + physicsSystem->RemoveScene(m_testSceneHandle); + } + m_testSceneHandle = AzPhysics::InvalidSceneHandle; + } + + AzPhysics::MassComputeFlags GetMassComputeFlags() const + { + return GetParam(); + } + + AzPhysics::SceneHandle m_testSceneHandle = AzPhysics::InvalidSceneHandle; + }; + + TEST_P(MassPropertiesWithTriangleMesh, KinematicRigidBody_ComputeMassProperties_TriggersWarnings) + { + const AzPhysics::MassComputeFlags flags = GetMassComputeFlags(); + + const bool doesComputeCenterOfMass = AzPhysics::MassComputeFlags::COMPUTE_COM == (flags & AzPhysics::MassComputeFlags::COMPUTE_COM); + const bool doesComputeMass = AzPhysics::MassComputeFlags::COMPUTE_MASS == (flags & AzPhysics::MassComputeFlags::COMPUTE_MASS); + const bool doesComputeInertia = AzPhysics::MassComputeFlags::COMPUTE_INERTIA == (flags & AzPhysics::MassComputeFlags::COMPUTE_INERTIA); + + UnitTest::ErrorHandler computeCenterOfMassWarningHandler( + "cannot compute COM"); + UnitTest::ErrorHandler computeMassWarningHandler( + "cannot compute Mass"); + UnitTest::ErrorHandler computeIneriaWarningHandler( + "cannot compute Inertia"); + + AzPhysics::SimulatedBodyHandle rigidBodyhandle = TestUtils::AddKinematicTriangleMeshCubeToScene(m_testSceneHandle, 3.0f, flags); + + EXPECT_TRUE(rigidBodyhandle != AzPhysics::InvalidSimulatedBodyHandle); + EXPECT_EQ(computeCenterOfMassWarningHandler.GetExpectedWarningCount(), doesComputeCenterOfMass ? 1 : 0); + EXPECT_EQ(computeMassWarningHandler.GetExpectedWarningCount(), doesComputeMass ? 1 : 0); + EXPECT_EQ(computeIneriaWarningHandler.GetExpectedWarningCount(), doesComputeInertia ? 1 : 0); + + if (auto* sceneInterface = AZ::Interface::Get()) + { + sceneInterface->RemoveSimulatedBody(m_testSceneHandle, rigidBodyhandle); + } + } + INSTANTIATE_TEST_CASE_P(PhysX, MassPropertiesWithTriangleMesh, + ::testing::ValuesIn(PossibleMassComputeFlags)); // Values for GetMassComputeFlags() } // namespace PhysX diff --git a/Gems/PhysX/Code/Tests/PhysXTestCommon.cpp b/Gems/PhysX/Code/Tests/PhysXTestCommon.cpp index 6186db6f1e..67fe67bc23 100644 --- a/Gems/PhysX/Code/Tests/PhysXTestCommon.cpp +++ b/Gems/PhysX/Code/Tests/PhysXTestCommon.cpp @@ -253,6 +253,36 @@ namespace PhysX return AzPhysics::InvalidSimulatedBodyHandle; } + AzPhysics::SimulatedBodyHandle AddKinematicTriangleMeshCubeToScene(AzPhysics::SceneHandle scene, float halfExtent, AzPhysics::MassComputeFlags massComputeFlags) + { + // Generate input data + VertexIndexData cubeMeshData = GenerateCubeMeshData(halfExtent); + AZStd::vector cookedData; + bool cookingResult = false; + Physics::SystemRequestBus::BroadcastResult(cookingResult, &Physics::SystemRequests::CookTriangleMeshToMemory, + cubeMeshData.first.data(), static_cast(cubeMeshData.first.size()), + cubeMeshData.second.data(), static_cast(cubeMeshData.second.size()), + cookedData); + AZ_Assert(cookingResult, "Failed to cook the cube mesh."); + + // Setup shape & collider configurations + auto shapeConfig = AZStd::make_shared(); + shapeConfig->SetCookedMeshData(cookedData.data(), cookedData.size(), + Physics::CookedMeshShapeConfiguration::MeshType::TriangleMesh); + + AzPhysics::RigidBodyConfiguration rigidBodyConfiguration; + rigidBodyConfiguration.m_kinematic = true; + rigidBodyConfiguration.SetMassComputeFlags(massComputeFlags); + rigidBodyConfiguration.m_colliderAndShapeData = AzPhysics::ShapeColliderPair( + AZStd::make_shared(), shapeConfig); + + if (auto* sceneInterface = AZ::Interface::Get()) + { + return sceneInterface->AddSimulatedBody(scene, &rigidBodyConfiguration); + } + return AzPhysics::InvalidSimulatedBodyHandle; + } + void SetCollisionLayer(EntityPtr& entity, const AZStd::string& layerName, const AZStd::string& colliderTag) { Physics::CollisionFilteringRequestBus::Event(entity->GetId(), &Physics::CollisionFilteringRequests::SetCollisionLayer, layerName, AZ::Crc32(colliderTag.c_str())); diff --git a/Gems/PhysX/Code/Tests/PhysXTestCommon.h b/Gems/PhysX/Code/Tests/PhysXTestCommon.h index ef12ca8350..95859a3f86 100644 --- a/Gems/PhysX/Code/Tests/PhysXTestCommon.h +++ b/Gems/PhysX/Code/Tests/PhysXTestCommon.h @@ -89,6 +89,7 @@ namespace PhysX const AzPhysics::CollisionLayer& layer = AzPhysics::CollisionLayer::Default); AzPhysics::SimulatedBodyHandle AddStaticTriangleMeshCubeToScene(AzPhysics::SceneHandle scene, float halfExtent); + AzPhysics::SimulatedBodyHandle AddKinematicTriangleMeshCubeToScene(AzPhysics::SceneHandle scene, float halfExtent, AzPhysics::MassComputeFlags massComputeFlags); // Collision Filtering void SetCollisionLayer(EntityPtr& entity, const AZStd::string& layerName, const AZStd::string& colliderTag = ""); diff --git a/Gems/WhiteBox/Code/Source/Components/WhiteBoxColliderComponent.cpp b/Gems/WhiteBox/Code/Source/Components/WhiteBoxColliderComponent.cpp index a7e6b6c707..18bddfa26f 100644 --- a/Gems/WhiteBox/Code/Source/Components/WhiteBoxColliderComponent.cpp +++ b/Gems/WhiteBox/Code/Source/Components/WhiteBoxColliderComponent.cpp @@ -91,6 +91,11 @@ namespace WhiteBox bodyConfiguration.m_position = worldTransform.GetTranslation(); bodyConfiguration.m_kinematic = true; // note: this field is ignored in the WhiteBoxBodyType::Static case bodyConfiguration.m_colliderAndShapeData = shape; + // Since the shape used is a triangle mesh the COM, Mass and Inertia + // cannot be computed. Disable them to use default values. + bodyConfiguration.m_computeCenterOfMass = false; + bodyConfiguration.m_computeMass = false; + bodyConfiguration.m_computeInertiaTensor = false; m_simulatedBodyHandle = sceneInterface->AddSimulatedBody(defaultScene, &bodyConfiguration); } break;