/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #pragma once #include namespace PhysX { class D6JointLimitConfiguration : public Physics::JointLimitConfiguration { public: AZ_CLASS_ALLOCATOR(D6JointLimitConfiguration, AZ::SystemAllocator, 0); AZ_RTTI(D6JointLimitConfiguration, "{90C5C23D-16C0-4F23-AD50-A190E402388E}", Physics::JointLimitConfiguration); static void Reflect(AZ::ReflectContext* context); const char* GetTypeName() override; float m_swingLimitY = 45.0f; ///< Maximum angle in degrees from the Y axis of the joint frame. float m_swingLimitZ = 45.0f; ///< Maximum angle in degrees from the Z axis of the joint frame. float m_twistLimitLower = -45.0f; ///< Lower limit in degrees for rotation about the X axis of the joint frame. float m_twistLimitUpper = 45.0f; ///< Upper limit in degrees for rotation about the X axis of the joint frame. }; class Joint : public Physics::Joint { public: AZ_CLASS_ALLOCATOR(Joint, AZ::SystemAllocator, 0); AZ_RTTI(Joint, "{3C739E22-8EF0-419F-966B-C575A1F5A08B}", Physics::Joint); Joint(physx::PxJoint* pxJoint, Physics::WorldBody* parentBody, Physics::WorldBody* childBody); virtual ~Joint() = default; Physics::WorldBody* GetParentBody() const override; Physics::WorldBody* GetChildBody() const override; void SetParentBody(Physics::WorldBody* parentBody) override; void SetChildBody(Physics::WorldBody* childBody) override; const AZStd::string& GetName() const override; void SetName(const AZStd::string& name) override; void* GetNativePointer() override; protected: bool SetPxActors(); using PxJointUniquePtr = AZStd::unique_ptr>; PxJointUniquePtr m_pxJoint; Physics::WorldBody* m_parentBody; Physics::WorldBody* m_childBody; AZStd::string m_name; }; class D6Joint : public Joint { public: AZ_CLASS_ALLOCATOR(D6Joint, AZ::SystemAllocator, 0); AZ_RTTI(D6Joint, "{962C4044-2BD2-4E4C-913C-FB8E85A2A12A}", Joint); D6Joint(physx::PxJoint* pxJoint, Physics::WorldBody* parentBody, Physics::WorldBody* childBody) : Joint(pxJoint, parentBody, childBody) { } virtual ~D6Joint() = default; const AZ::Crc32 GetNativeType() const override; void GenerateJointLimitVisualizationData( float scale, AZ::u32 angularSubdivisions, AZ::u32 radialSubdivisions, AZStd::vector& vertexBufferOut, AZStd::vector& indexBufferOut, AZStd::vector& lineBufferOut, AZStd::vector& lineValidityBufferOut) override; }; struct D6JointState { float m_swingAngleY; float m_swingAngleZ; float m_twistAngle; }; /// A fixed joint locks 2 bodies relative to one another on all axes of freedom. class FixedJoint : public Joint { public: AZ_CLASS_ALLOCATOR(FixedJoint, AZ::SystemAllocator, 0); AZ_TYPE_INFO(FixedJoint, "{203FB99C-7DC5-478A-A52C-A1F2AAF61FB8}"); FixedJoint(physx::PxJoint* pxJoint, Physics::WorldBody* parentBody, Physics::WorldBody* childBody) : Joint(pxJoint, parentBody, childBody) { } const AZ::Crc32 GetNativeType() const override; void GenerateJointLimitVisualizationData( float /*scale*/, AZ::u32 /*angularSubdivisions*/, AZ::u32 /*radialSubdivisions*/, AZStd::vector& /*vertexBufferOut*/, AZStd::vector& /*indexBufferOut*/, AZStd::vector& /*lineBufferOut*/, AZStd::vector& /*lineValidityBufferOut*/) override {} }; /// A hinge joint locks 2 bodies relative to one another except about the x-axis of the joint between them. class HingeJoint : public Joint { public: AZ_CLASS_ALLOCATOR(HingeJoint, AZ::SystemAllocator, 0); AZ_TYPE_INFO(HingeJoint, "{8EFF1002-B08C-47CE-883C-82F0CF3736E0}"); HingeJoint(physx::PxJoint* pxJoint, Physics::WorldBody* parentBody, Physics::WorldBody* childBody) : Joint(pxJoint, parentBody, childBody) { } const AZ::Crc32 GetNativeType() const override; void GenerateJointLimitVisualizationData( float /*scale*/, AZ::u32 /*angularSubdivisions*/, AZ::u32 /*radialSubdivisions*/, AZStd::vector& /*vertexBufferOut*/, AZStd::vector& /*indexBufferOut*/, AZStd::vector& /*lineBufferOut*/, AZStd::vector& /*lineValidityBufferOut*/) override {} }; /// A ball joint locks 2 bodies relative to one another except about the y and z axes of the joint between them. class BallJoint : public Joint { public: AZ_CLASS_ALLOCATOR(BallJoint, AZ::SystemAllocator, 0); AZ_TYPE_INFO(BallJoint, "{9FADA1C2-0E2F-4E1B-9E83-6292A1606372}"); BallJoint(physx::PxJoint* pxJoint, Physics::WorldBody* parentBody, Physics::WorldBody* childBody) : Joint(pxJoint, parentBody, childBody) { } const AZ::Crc32 GetNativeType() const override; void GenerateJointLimitVisualizationData( float /*scale*/, AZ::u32 /*angularSubdivisions*/, AZ::u32 /*radialSubdivisions*/, AZStd::vector& /*vertexBufferOut*/, AZStd::vector& /*indexBufferOut*/, AZStd::vector& /*lineBufferOut*/, AZStd::vector& /*lineValidityBufferOut*/) override {} }; /// Common parameters for all physics joint types. class GenericJointConfiguration { public: enum class GenericJointFlag : AZ::u16 { None = 0, Breakable = 1, SelfCollide = 1 << 1 }; AZ_CLASS_ALLOCATOR(GenericJointConfiguration, AZ::SystemAllocator, 0); AZ_TYPE_INFO(GenericJointConfiguration, "{AB2E2F92-0248-48A8-9DDD-21284AF0C1DF}"); static void Reflect(AZ::ReflectContext* context); static bool VersionConverter( AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement); GenericJointConfiguration() = default; GenericJointConfiguration(float forceMax, float torqueMax, AZ::Transform localTransformFromFollower, AZ::EntityId leadEntity, AZ::EntityId followerEntity, GenericJointFlag flags); bool GetFlag(GenericJointFlag flag); ///< Returns if a particular flag is set as a bool. GenericJointFlag m_flags = GenericJointFlag::None; ///< Flags that indicates if joint is breakable, self-colliding, etc.. Converting joint between breakable/non-breakable at game time is allowed. float m_forceMax = 1.0f; ///< Max force joint can tolerate before breaking. float m_torqueMax = 1.0f; ///< Max torque joint can tolerate before breaking. AZ::EntityId m_leadEntity; ///< EntityID for entity containing body that is lead to this joint constraint. AZ::EntityId m_followerEntity; ///< EntityID for entity containing body that is follower to this joint constraint. AZ::Transform m_localTransformFromFollower; ///< Joint's location and orientation in the frame (coordinate system) of the follower entity. }; AZ_DEFINE_ENUM_BITWISE_OPERATORS(PhysX::GenericJointConfiguration::GenericJointFlag) /// Generic pair of limit values for joint types, e.g. a pair of angular values. /// This is different from JointLimitConfiguration used in non-generic joints for character/ragdoll/animation. class GenericJointLimitsConfiguration { public: AZ_CLASS_ALLOCATOR(GenericJointLimitsConfiguration, AZ::SystemAllocator, 0); AZ_TYPE_INFO(GenericJointLimitsConfiguration, "{9D129B49-F4E6-4F2A-B94D-AC2D6AC6CE02}"); static void Reflect(AZ::ReflectContext* context); GenericJointLimitsConfiguration() = default; GenericJointLimitsConfiguration(float damping , bool isLimited , bool isSoftLimit , float limitFirst , float limitSecond , float stiffness , float tolerance); bool m_isLimited = true; ///< Specifies if limits are applied to the joint constraints. E.g. if the swing angles are limited. bool m_isSoftLimit = false; ///< If limit is soft, spring and damping are used, otherwise tolerance is used. Converting between soft/hard limit at game time is allowed. float m_damping = 20.0f; ///< The damping strength of the drive, the force proportional to the velocity error. Used if limit is soft. float m_limitFirst = 45.0f; ///< Positive angle limit in the case of twist angle limits, Y-axis swing limit in the case of cone limits. float m_limitSecond = 45.0f; ///< Negative angle limit in the case of twist angle limits, Z-axis swing limit in the case of cone limits. float m_stiffness = 100.0f; ///< The spring strength of the drive, the force proportional to the position error. Used if limit is soft. float m_tolerance = 0.1f; ///< Distance from the joint at which limits becomes enforced. Used if limit is hard. }; class JointUtils { public: static AZStd::vector GetSupportedJointTypes(); static AZStd::shared_ptr CreateJointLimitConfiguration(AZ::TypeId jointType); static AZStd::shared_ptr CreateJoint(const AZStd::shared_ptr& configuration, Physics::WorldBody* parentBody, Physics::WorldBody* childBody); static D6JointState CalculateD6JointState( const AZ::Quaternion& parentWorldRotation, const AZ::Quaternion& parentLocalRotation, const AZ::Quaternion& childWorldRotation, const AZ::Quaternion& childLocalRotation); static bool IsD6SwingValid( float swingAngleY, float swingAngleZ, float swingLimitY, float swingLimitZ); static void AppendD6SwingConeToLineBuffer( const AZ::Quaternion& parentLocalRotation, float swingAngleY, float swingAngleZ, float swingLimitY, float swingLimitZ, float scale, AZ::u32 angularSubdivisions, AZ::u32 radialSubdivisions, AZStd::vector& lineBufferOut, AZStd::vector& lineValidityBufferOut); static void AppendD6TwistArcToLineBuffer( const AZ::Quaternion& parentLocalRotation, float twistAngle, float twistLimitLower, float twistLimitUpper, float scale, AZ::u32 angularSubdivisions, AZ::u32 radialSubdivisions, AZStd::vector& lineBufferOut, AZStd::vector& lineValidityBufferOut); static void AppendD6CurrentTwistToLineBuffer( const AZ::Quaternion& parentLocalRotation, float twistAngle, float twistLimitLower, float twistLimitUpper, float scale, AZStd::vector& lineBufferOut, AZStd::vector& lineValidityBufferOut); static void GenerateJointLimitVisualizationData( const Physics::JointLimitConfiguration& configuration, const AZ::Quaternion& parentRotation, const AZ::Quaternion& childRotation, float scale, AZ::u32 angularSubdivisions, AZ::u32 radialSubdivisions, AZStd::vector& vertexBufferOut, AZStd::vector& indexBufferOut, AZStd::vector& lineBufferOut, AZStd::vector& lineValidityBufferOut); static AZStd::unique_ptr ComputeInitialJointLimitConfiguration( const AZ::TypeId& jointLimitTypeId, const AZ::Quaternion& parentWorldRotation, const AZ::Quaternion& childWorldRotation, const AZ::Vector3& axis, const AZStd::vector& exampleLocalRotations); }; } // namespace PhysX