Merge branch 'development' into TIF/Runtime

This commit is contained in:
John
2021-06-18 10:15:04 +01:00
108 changed files with 2948 additions and 1819 deletions
@@ -56,6 +56,7 @@ def C18243584_Joints_HingeSoftLimitsConstrained():
"""
import os
import sys
import math
import ImportPathHelper as imports
@@ -93,22 +94,51 @@ def C18243584_Joints_HingeSoftLimitsConstrained():
Report.info_vector3(lead.position, "lead initial position:")
Report.info_vector3(follower.position, "follower initial position:")
leadInitialPosition = lead.position
followerInitialPosition = follower.position
# 4) Wait for the follower to move above the lead or Timeout
normalizedStartPos = JointsHelper.getRelativeVector(lead.position, follower.position)
normalizedStartPos = normalizedStartPos.GetNormalizedSafe()
# 4) Wait for several seconds
general.idle_wait(4.0) # wait for lead and follower to move
class WaitCondition:
TARGET_ANGLE = math.radians(45)
TARGET_MAX_ANGLE = math.radians(180)
angleAchieved = 0.0
followerMovedAbove45Deg = False #this is expected to be true to pass the test
followerMovedAbove180Deg = True #this is expected to be false to pass the test
def checkConditionMet(self):
#calculate the current follower-lead vector
normalVec = JointsHelper.getRelativeVector(lead.position, follower.position)
normalVec = normalVec.GetNormalizedSafe()
#dot product + acos to get the angle
currentAngle = math.acos(normalizedStartPos.Dot(normalVec))
#if the angle is now less then last time, it is no longer rising, so end the test.
if currentAngle < self.angleAchieved:
return True
self.angleAchieved = currentAngle
self.followerMovedAbove45Deg = currentAngle > self.TARGET_ANGLE
self.followerMovedAbove180Deg = currentAngle > self.TARGET_MAX_ANGLE
return False
def isFollowerPositionCorrect(self):
return self.followerMovedAbove45Deg and not self.followerMovedAbove180Deg
waitCondition = WaitCondition()
MAX_WAIT_TIME = 5.0 #seconds
conditionMet = helper.wait_for_condition(lambda: waitCondition.checkConditionMet(), MAX_WAIT_TIME)
# 5) Check to see if lead and follower behaved as expected
Report.info_vector3(lead.position, "lead position after 1 second:")
Report.info_vector3(follower.position, "follower position after 1 second:")
Report.info_vector3(lead.position, "lead position after test:")
Report.info_vector3(follower.position, "follower position after test:")
leadPositionDelta = lead.position.Subtract(leadInitialPosition)
leadRemainedStill = JointsHelper.vector3SmallerThanScalar(leadPositionDelta, FLOAT_EPSILON)
Report.critical_result(Tests.check_lead_position, leadRemainedStill)
followerMovedInXOnly = ((follower.position.x > leadInitialPosition.x) > FLOAT_EPSILON and
(follower.position.z - leadInitialPosition.z) > FLOAT_EPSILON)
Report.critical_result(Tests.check_follower_position, followerMovedInXOnly)
Report.critical_result(Tests.check_follower_position, conditionMet and waitCondition.isFollowerPositionCorrect())
# 6) Exit Game Mode
helper.exit_game_mode(Tests.exit_game_mode)
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:16f592487e8973abcf6b696aee6e430924c22daac0d6bb781c9e76153cd932f7
size 8885
oid sha256:352a64f523b3246000393309fa7f14955fe554e0b792a4177349f0f2db8a2b62
size 5901
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4d5c38cf9b97ae28c391916e6637aebf767d5ac009df61e730396fe8b116f3e5
size 6913
oid sha256:31bd1feb92c3bb8a5c5df4638927a9a80e879329965732c4c32f673c236a8b0a
size 6021
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a6f26f1c1c037fa0b848ac9b3d9a76e476b4853d770f1a77c01714286733b567
size 6921
oid sha256:063779c1e80ce22319cb82ff0d7635d3dcbb043b789c3830cc405ffa36d3c0ef
size 5876
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4ffd3c4ee04fa8a414995c39c7ca79246e3d9b0ceee1ad1b85d61a5298f71495
size 6940
oid sha256:5bd3a952841aa924a4869c74fad7ed397667a87948270f0ce35f314e6cf2e14a
size 5927
@@ -0,0 +1,36 @@
/*
* 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.
*
*/
#include <AzFramework/Physics/Common/PhysicsJoint.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/Physics/PhysicsScene.h>
#include <AzFramework/Physics/PhysicsSystem.h>
namespace AzPhysics
{
AZ_CLASS_ALLOCATOR_IMPL(Joint, AZ::SystemAllocator, 0);
void Joint::Reflect(AZ::ReflectContext* context)
{
if (auto* serializeContext = azdynamic_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<AzPhysics::Joint>()
->Version(1)
->Field("SceneOwner", &Joint::m_sceneOwner)
->Field("JointHandle", &Joint::m_jointHandle)
;
}
}
}
@@ -0,0 +1,143 @@
/*
* 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 <AzCore/Math/Aabb.h>
#include <AzCore/Math/Crc.h>
#include <AzCore/Math/Quaternion.h>
#include <AzCore/Memory/Memory.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/std/containers/variant.h>
#include <AzCore/std/containers/vector.h>
#include <AzFramework/Physics/Common/PhysicsSimulatedBodyEvents.h>
#include <AzFramework/Physics/Common/PhysicsSceneQueries.h>
#include <AzFramework/Physics/Common/PhysicsTypes.h>
namespace AZ
{
class ReflectContext;
}
namespace AzPhysics
{
struct JointConfiguration;
//! Base class for all Joints in Physics.
struct Joint
{
AZ_CLASS_ALLOCATOR_DECL;
AZ_RTTI(AzPhysics::Joint, "{1EEC9382-3434-4866-9B18-E93F151A6F59}");
static void Reflect(AZ::ReflectContext* context);
virtual ~Joint() = default;
//! The current Scene the joint is contained.
SceneHandle m_sceneOwner = AzPhysics::InvalidSceneHandle;
//! The handle to this joint.
JointHandle m_jointHandle = AzPhysics::InvalidJointHandle;
//! Helper functions for setting user data.
//! @param userData Can be a pointer to any type as internally will be cast to a void*. Object lifetime not managed by the Joint.
template<typename T>
void SetUserData(T* userData)
{
m_customUserData = static_cast<void*>(userData);
}
//! Helper functions for getting the set user data.
//! @return Will return a void* to the user data set.
void* GetUserData()
{
return m_customUserData;
}
virtual AZ::Crc32 GetNativeType() const = 0;
virtual void* GetNativePointer() const = 0;
virtual AzPhysics::SimulatedBodyHandle GetParentBodyHandle() const = 0;
virtual AzPhysics::SimulatedBodyHandle GetChildBodyHandle() const = 0;
virtual void SetParentBody(AzPhysics::SimulatedBodyHandle parentBody) = 0;
virtual void SetChildBody(AzPhysics::SimulatedBodyHandle childBody) = 0;
virtual void GenerateJointLimitVisualizationData(
[[ maybe_unused ]] float scale,
[[ maybe_unused ]] AZ::u32 angularSubdivisions,
[[ maybe_unused ]] AZ::u32 radialSubdivisions,
[[ maybe_unused ]] AZStd::vector<AZ::Vector3>& vertexBufferOut,
[[ maybe_unused ]] AZStd::vector<AZ::u32>& indexBufferOut,
[[ maybe_unused ]] AZStd::vector<AZ::Vector3>& lineBufferOut,
[[ maybe_unused ]] AZStd::vector<bool>& lineValidityBufferOut) { }
private:
void* m_customUserData = nullptr;
};
//! Alias for a list of non owning weak pointers to Joint objects.
using JointList = AZStd::vector<Joint*>;
//! Interface to access Joint utilities and helper functions
class JointHelpersInterface
{
public:
AZ_RTTI(AzPhysics::JointHelpersInterface, "{A511C64D-C8A5-4E8F-9C69-8DC5EFAD0C4C}");
JointHelpersInterface() = default;
virtual ~JointHelpersInterface() = default;
AZ_DISABLE_COPY_MOVE(JointHelpersInterface);
//! Returns a list of supported Joint types
virtual const AZStd::vector<AZ::TypeId> GetSupportedJointTypeIds() const = 0;
//! Returns a TypeID if the request joint type is supported.
//! If the Physics backend supports this joint type JointHelpersInterface::GetSupportedJointTypeId will return a AZ::TypeId.
virtual AZStd::optional<const AZ::TypeId> GetSupportedJointTypeId(JointType typeEnum) const = 0;
//! Computes parameters such as joint limit local rotations to give the desired initial joint limit orientation.
//! @param jointLimitTypeId The type ID used to identify the particular kind of joint limit configuration to be created.
//! @param parentWorldRotation The rotation in world space of the parent world body associated with the joint.
//! @param childWorldRotation The rotation in world space of the child world body associated with the joint.
//! @param axis Axis used to define the centre for limiting angular degrees of freedom.
//! @param exampleLocalRotations A vector (which may be empty) containing example valid rotations in the local space
//! of the child world body relative to the parent world body, which may optionally be used to help estimate the extents
//! of the joint limit.
virtual AZStd::unique_ptr<JointConfiguration> ComputeInitialJointLimitConfiguration(
const AZ::TypeId& jointLimitTypeId,
const AZ::Quaternion& parentWorldRotation,
const AZ::Quaternion& childWorldRotation,
const AZ::Vector3& axis,
const AZStd::vector<AZ::Quaternion>& exampleLocalRotations) = 0;
/// Generates joint limit visualization data in appropriate format to pass to DebugDisplayRequests draw functions.
/// @param configuration The joint configuration to generate visualization data for.
/// @param parentRotation The rotation of the joint's parent body (in the same frame as childRotation).
/// @param childRotation The rotation of the joint's child body (in the same frame as parentRotation).
/// @param scale Scale factor for the output display data.
/// @param angularSubdivisions Level of detail in the angular direction (may be clamped in the implementation).
/// @param radialSubdivisions Level of detail in the radial direction (may be clamped in the implementation).
/// @param[out] vertexBufferOut Used with indexBufferOut to define triangles to be displayed.
/// @param[out] indexBufferOut Used with vertexBufferOut to define triangles to be displayed.
/// @param[out] lineBufferOut Used to define lines to be displayed.
/// @param[out] lineValidityBufferOut Whether each line in the line buffer is part of a valid or violated limit.
virtual void GenerateJointLimitVisualizationData(
const JointConfiguration& configuration,
const AZ::Quaternion& parentRotation,
const AZ::Quaternion& childRotation,
float scale,
AZ::u32 angularSubdivisions,
AZ::u32 radialSubdivisions,
AZStd::vector<AZ::Vector3>& vertexBufferOut,
AZStd::vector<AZ::u32>& indexBufferOut,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut) = 0;
};
}
@@ -51,8 +51,10 @@ namespace AzPhysics
using SceneIndex = AZ::s8;
using SimulatedBodyIndex = AZ::s32;
using JointIndex = AZ::s32;
static_assert(std::is_signed<SceneIndex>::value
&& std::is_signed<SimulatedBodyIndex>::value, "SceneIndex and SimulatedBodyIndex must be signed integers.");
&& std::is_signed<SimulatedBodyIndex>::value
&& std::is_signed<JointIndex>::value, "SceneIndex, SimulatedBodyIndex and JointIndex must be signed integers.");
//! A handle to a Scene within the physics simulation.
@@ -69,12 +71,27 @@ namespace AzPhysics
static constexpr SimulatedBodyHandle InvalidSimulatedBodyHandle = { AZ::Crc32(), -1 };
using SimulatedBodyHandleList = AZStd::vector<SimulatedBodyHandle>;
//! A handle to a Joint within a physics scene.
//! A JointHandle is a tuple of a Crc of the scene's name and the index in the Joint list.
using JointHandle = AZStd::tuple<AZ::Crc32, JointIndex>;
static constexpr JointHandle InvalidJointHandle = { AZ::Crc32(), -1 };
//! Helper used for pairing the ShapeConfiguration and ColliderConfiguration together which is used when creating a Simulated Body.
using ShapeColliderPair = AZStd::pair<
AZStd::shared_ptr<Physics::ColliderConfiguration>,
AZStd::shared_ptr<Physics::ShapeConfiguration>>;
using ShapeColliderPairList = AZStd::vector<ShapeColliderPair>;
//! Joint types are used to request for AZ::TypeId with the JointHelpersInterface::GetSupportedJointTypeId.
//! If the Physics backend supports this joint type JointHelpersInterface::GetSupportedJointTypeId will return a AZ::TypeId.
enum class JointType
{
D6Joint,
FixedJoint,
BallJoint,
HingeJoint
};
//! Flags used to specifying which properties of a body to compute.
enum class MassComputeFlags : AZ::u8
{
@@ -0,0 +1,37 @@
/*
* 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.
*
*/
#include <AzFramework/Physics/Configuration/JointConfiguration.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace AzPhysics
{
AZ_CLASS_ALLOCATOR_IMPL(JointConfiguration, AZ::SystemAllocator, 0);
void JointConfiguration::Reflect(AZ::ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<JointConfiguration>()
->Version(1)
->Field("Name", &JointConfiguration::m_debugName)
->Field("ParentLocalRotation", &JointConfiguration::m_parentLocalRotation)
->Field("ParentLocalPosition", &JointConfiguration::m_parentLocalPosition)
->Field("ChildLocalRotation", &JointConfiguration::m_childLocalRotation)
->Field("ChildLocalPosition", &JointConfiguration::m_childLocalPosition)
->Field("StartSimulationEnabled", &JointConfiguration::m_startSimulationEnabled)
;
}
}
}
@@ -0,0 +1,51 @@
/*
* 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 <AzCore/Component/EntityId.h>
#include <AzCore/Math/Quaternion.h>
#include <AzCore/Math/Vector3.h>
#include <AzCore/Memory/Memory.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/std/containers/vector.h>
namespace AZ
{
class ReflectContext;
}
namespace AzPhysics
{
//! Base Class of all Physics Joints that will be simulated.
struct JointConfiguration
{
AZ_CLASS_ALLOCATOR_DECL;
AZ_RTTI(AzPhysics::JointConfiguration, "{DF91D39A-4901-48C4-9159-93FD2ACA5252}");
static void Reflect(AZ::ReflectContext* context);
JointConfiguration() = default;
virtual ~JointConfiguration() = default;
// Entity/object association.
void* m_customUserData = nullptr;
// Basic initial settings.
AZ::Quaternion m_parentLocalRotation = AZ::Quaternion::CreateIdentity(); ///< Parent joint frame relative to parent body.
AZ::Vector3 m_parentLocalPosition = AZ::Vector3::CreateZero(); ///< Joint position relative to parent body.
AZ::Quaternion m_childLocalRotation = AZ::Quaternion::CreateIdentity(); ///< Child joint frame relative to child body.
AZ::Vector3 m_childLocalPosition = AZ::Vector3::CreateZero(); ///< Joint position relative to child body.
bool m_startSimulationEnabled = true;
// For debugging/tracking purposes only.
AZStd::string m_debugName;
};
}
@@ -1,56 +0,0 @@
/*
* 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.
*
*/
#include <AzFramework/Physics/Joint.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/Physics/Common/PhysicsSimulatedBody.h>
namespace Physics
{
const char* JointLimitConfiguration::GetTypeName()
{
return "Base Joint";
}
void JointLimitConfiguration::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<JointLimitConfiguration>()
->Version(1)
->Field("ParentLocalRotation", &JointLimitConfiguration::m_parentLocalRotation)
->Field("ParentLocalPosition", &JointLimitConfiguration::m_parentLocalPosition)
->Field("ChildLocalRotation", &JointLimitConfiguration::m_childLocalRotation)
->Field("ChildLocalPosition", &JointLimitConfiguration::m_childLocalPosition)
;
AZ::EditContext* editContext = serializeContext->GetEditContext();
if (editContext)
{
editContext->Class<JointLimitConfiguration>(
"Joint Configuration", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->DataElement(AZ::Edit::UIHandlers::Default, &JointLimitConfiguration::m_parentLocalRotation,
"Parent local rotation", "The rotation of the parent joint frame relative to the parent body")
->DataElement(AZ::Edit::UIHandlers::Default, &JointLimitConfiguration::m_parentLocalPosition,
"Parent local position", "The position of the joint in the frame of the parent body")
->DataElement(AZ::Edit::UIHandlers::Default, &JointLimitConfiguration::m_childLocalRotation,
"Child local rotation", "The rotation of the child joint frame relative to the child body")
->DataElement(AZ::Edit::UIHandlers::Default, &JointLimitConfiguration::m_childLocalPosition,
"Child local position", "The position of the joint in the frame of the child body")
;
}
}
}
} // namespace Physics
@@ -1,75 +0,0 @@
/*
* 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 <AzCore/Math/Transform.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace AzPhysics
{
struct SimulatedBody;
}
namespace Physics
{
class JointLimitConfiguration
{
public:
AZ_CLASS_ALLOCATOR(JointLimitConfiguration, AZ::SystemAllocator, 0);
AZ_RTTI(JointLimitConfiguration, "{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}");
static void Reflect(AZ::ReflectContext* context);
JointLimitConfiguration() = default;
JointLimitConfiguration(const JointLimitConfiguration&) = default;
virtual ~JointLimitConfiguration() = default;
virtual const char* GetTypeName();
AZ::Quaternion m_parentLocalRotation = AZ::Quaternion::CreateIdentity(); ///< Parent joint frame relative to parent body.
AZ::Vector3 m_parentLocalPosition = AZ::Vector3::CreateZero(); ///< Joint position relative to parent body.
AZ::Quaternion m_childLocalRotation = AZ::Quaternion::CreateIdentity(); ///< Child joint frame relative to child body.
AZ::Vector3 m_childLocalPosition = AZ::Vector3::CreateZero(); ///< Joint position relative to child body.
};
class Joint
{
public:
AZ_CLASS_ALLOCATOR(Joint, AZ::SystemAllocator, 0);
AZ_RTTI(Joint, "{405F517C-E986-4ACB-9606-D5D080DDE987}");
virtual AzPhysics::SimulatedBody* GetParentBody() const = 0;
virtual AzPhysics::SimulatedBody* GetChildBody() const = 0;
virtual void SetParentBody(AzPhysics::SimulatedBody* parentBody) = 0;
virtual void SetChildBody(AzPhysics::SimulatedBody* childBody) = 0;
virtual const AZStd::string& GetName() const = 0;
virtual void SetName(const AZStd::string& name) = 0;
virtual const AZ::Crc32 GetNativeType() const = 0;
virtual void* GetNativePointer() = 0;
/// Generates joint limit visualization data in appropriate format to pass to DebugDisplayRequests draw functions.
/// @param scale Scale factor for the output display data.
/// @param angularSubdivisions Level of detail in the angular direction (may be clamped in the implementation).
/// @param radialSubdivisions Level of detail in the radial direction (may be clamped in the implementation).
/// @param[out] vertexBufferOut Used with indexBufferOut to define triangles to be displayed.
/// @param[out] indexBufferOut Used with vertexBufferOut to define triangles to be displayed.
/// @param[out] lineBufferOut Used to define lines to be displayed.
/// @param[out] lineValidityBufferOut Whether each line in the line buffer is part of a valid or violated limit.
virtual void GenerateJointLimitVisualizationData(
float scale,
AZ::u32 angularSubdivisions,
AZ::u32 radialSubdivisions,
AZStd::vector<AZ::Vector3>& vertexBufferOut,
AZStd::vector<AZ::u32>& indexBufferOut,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut) = 0;
};
} // namespace Physics
@@ -16,6 +16,8 @@
#include <AzFramework/Physics/Common/PhysicsSimulatedBody.h>
#include <AzFramework/Physics/Common/PhysicsSceneQueries.h>
#include <AzFramework/Physics/Common/PhysicsTypes.h>
#include <AzFramework/Physics/Common/PhysicsJoint.h>
#include <AzFramework/Physics/Configuration/JointConfiguration.h>
#include <AzFramework/Physics/Configuration/SimulatedBodyConfiguration.h>
namespace AzPhysics
@@ -103,6 +105,26 @@ namespace AzPhysics
virtual void EnableSimulationOfBody(SceneHandle sceneHandle, SimulatedBodyHandle bodyHandle) = 0;
virtual void DisableSimulationOfBody(SceneHandle sceneHandle, SimulatedBodyHandle bodyHandle) = 0;
//! Add a joint to the Scene.
//! @param sceneHandle A handle to the scene to add / remove the joint.
//! @param jointConfig The config of the joint.
//! @param parentBody The parent body of the joint.
//! @param childBody The child body of the joint
//! @return Returns a handle to the created joint. Will return AzPhyiscs::InvalidJointHandle if it fails.
virtual JointHandle AddJoint(SceneHandle sceneHandle, const JointConfiguration* jointConfig,
SimulatedBodyHandle parentBody, SimulatedBodyHandle childBody) = 0;
//! Get the Raw pointer to the requested joint.
//! @param sceneHandle A handle to the scene to get the simulated bodies from.
//! @param jointHandle A handle to the joint to retrieve the raw pointer.
//! @return A raw pointer to the Joint body. If the either handle is invalid this will return null.
virtual Joint* GetJointFromHandle(SceneHandle sceneHandle, JointHandle jointHandle) = 0;
//! Remove a joint from the Scene.
//! @param sceneHandle A handle to the scene to add / remove the joint.
//! @param jointHandle A handle to the joint being removed.
virtual void RemoveJoint(SceneHandle sceneHandle, JointHandle jointHandle) = 0;
//! Make a blocking query into the scene.
//! @param sceneHandle A handle to the scene to make the scene query with.
//! @param request The request to make. Should be one of RayCastRequest || ShapeCastRequest || OverlapRequest
@@ -299,6 +321,23 @@ namespace AzPhysics
virtual void EnableSimulationOfBody(SimulatedBodyHandle bodyHandle) = 0;
virtual void DisableSimulationOfBody(SimulatedBodyHandle bodyHandle) = 0;
//! Add a joint to the Scene.
//! @param jointConfig The config of the joint.
//! @param parentBody The parent body of the joint.
//! @param childBody The child body of the joint
//! @return Returns a handle to the created joint. Will return AzPhyiscs::InvalidJointHandle if it fails.
virtual JointHandle AddJoint(const JointConfiguration* jointConfig,
SimulatedBodyHandle parentBody, SimulatedBodyHandle childBody) = 0;
//! Get the Raw pointer to the requested joint.
//! @param jointHandle A handle to the joint to retrieve the raw pointer.
//! @return A raw pointer to the Joint body. If the either handle is invalid this will return null.
virtual Joint* GetJointFromHandle(JointHandle jointHandle) = 0;
//! Remove a joint from the Scene.
//! @param jointHandle A handle to the joint being removed.
virtual void RemoveJoint(JointHandle jointHandle) = 0;
//! Make a blocking query into the scene.
//! @param request The request to make. Should be one of RayCastRequest || ShapeCastRequest || OverlapRequest
//! @return Returns a structure that contains a list of Hits. Depending on flags set in the request, this may only contain 1 result.
@@ -36,8 +36,8 @@ namespace Physics
if (serializeContext)
{
serializeContext->Class<RagdollNodeConfiguration, RigidBodyConfiguration>()
->Version(4, &ClassConverters::RagdollNodeConfigConverter)
->Field("JointLimit", &RagdollNodeConfiguration::m_jointLimit)
->Version(5, &ClassConverters::RagdollNodeConfigConverter)
->Field("JointConfig", &RagdollNodeConfiguration::m_jointConfig)
;
AZ::EditContext* editContext = serializeContext->GetEditContext();
@@ -17,10 +17,11 @@
#include <AzFramework/Physics/Shape.h>
#include <AzFramework/Physics/SimulatedBodies/RigidBody.h>
#include <AzFramework/Physics/RagdollPhysicsBus.h>
#include <AzFramework/Physics/Joint.h>
#include <AzFramework/Physics/Common/PhysicsSimulatedBody.h>
#include <AzFramework/Physics/Common/PhysicsJoint.h>
#include <AzFramework/Physics/Configuration/RigidBodyConfiguration.h>
#include <AzFramework/Physics/Configuration/SimulatedBodyConfiguration.h>
#include <AzFramework/Physics/Configuration/JointConfiguration.h>
namespace Physics
{
@@ -37,7 +38,7 @@ namespace Physics
RagdollNodeConfiguration();
RagdollNodeConfiguration(const RagdollNodeConfiguration& settings) = default;
AZStd::shared_ptr<JointLimitConfiguration> m_jointLimit;
AZStd::shared_ptr<AzPhysics::JointConfiguration> m_jointConfig;
};
class RagdollConfiguration
@@ -73,7 +74,7 @@ namespace Physics
virtual AzPhysics::RigidBody& GetRigidBody() = 0;
virtual ~RagdollNode() = default;
virtual const AZStd::shared_ptr<Physics::Joint>& GetJoint() const = 0;
virtual AzPhysics::Joint* GetJoint() = 0;
virtual bool IsSimulating() const = 0;
};
@@ -26,23 +26,15 @@ namespace AZ
namespace AzPhysics
{
struct SimulatedBody;
struct RigidBodyConfiguration;
struct RigidBody;
}
namespace Physics
{
class WorldBody;
class Shape;
class Material;
class MaterialSelection;
class MaterialConfiguration;
class ColliderConfiguration;
class ShapeConfiguration;
class JointLimitConfiguration;
class Joint;
class CharacterConfiguration;
class Character;
/// Represents a debug vertex (position & color).
struct DebugDrawVertex
@@ -148,51 +140,6 @@ namespace Physics
/// @param nativeMeshObject Pointer to the mesh object.
virtual void ReleaseNativeMeshObject(void* nativeMeshObject) = 0;
//////////////////////////////////////////////////////////////////////////
//// Joints
virtual AZStd::vector<AZ::TypeId> GetSupportedJointTypes() = 0;
virtual AZStd::shared_ptr<JointLimitConfiguration> CreateJointLimitConfiguration(AZ::TypeId jointType) = 0;
virtual AZStd::shared_ptr<Joint> CreateJoint(const AZStd::shared_ptr<JointLimitConfiguration>& configuration,
AzPhysics::SimulatedBody* parentBody, AzPhysics::SimulatedBody* childBody) = 0;
/// Generates joint limit visualization data in appropriate format to pass to DebugDisplayRequests draw functions.
/// @param configuration The joint configuration to generate visualization data for.
/// @param parentRotation The rotation of the joint's parent body (in the same frame as childRotation).
/// @param childRotation The rotation of the joint's child body (in the same frame as parentRotation).
/// @param scale Scale factor for the output display data.
/// @param angularSubdivisions Level of detail in the angular direction (may be clamped in the implementation).
/// @param radialSubdivisions Level of detail in the radial direction (may be clamped in the implementation).
/// @param[out] vertexBufferOut Used with indexBufferOut to define triangles to be displayed.
/// @param[out] indexBufferOut Used with vertexBufferOut to define triangles to be displayed.
/// @param[out] lineBufferOut Used to define lines to be displayed.
/// @param[out] lineValidityBufferOut Whether each line in the line buffer is part of a valid or violated limit.
virtual void GenerateJointLimitVisualizationData(
const JointLimitConfiguration& configuration,
const AZ::Quaternion& parentRotation,
const AZ::Quaternion& childRotation,
float scale,
AZ::u32 angularSubdivisions,
AZ::u32 radialSubdivisions,
AZStd::vector<AZ::Vector3>& vertexBufferOut,
AZStd::vector<AZ::u32>& indexBufferOut,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut) = 0;
/// Computes parameters such as joint limit local rotations to give the desired initial joint limit orientation.
/// @param jointLimitTypeId The type ID used to identify the particular kind of joint limit configuration to be created.
/// @param parentWorldRotation The rotation in world space of the parent world body associated with the joint.
/// @param childWorldRotation The rotation in world space of the child world body associated with the joint.
/// @param axis Axis used to define the centre for limiting angular degrees of freedom.
/// @param exampleLocalRotations A vector (which may be empty) containing example valid rotations in the local space
/// of the child world body relative to the parent world body, which may optionally be used to help estimate the extents
/// of the joint limit.
virtual AZStd::unique_ptr<JointLimitConfiguration> ComputeInitialJointLimitConfiguration(
const AZ::TypeId& jointLimitTypeId,
const AZ::Quaternion& parentWorldRotation,
const AZ::Quaternion& childWorldRotation,
const AZ::Vector3& axis,
const AZStd::vector<AZ::Quaternion>& exampleLocalRotations) = 0;
//////////////////////////////////////////////////////////////////////////
//// Cooking
@@ -34,6 +34,7 @@
#include <AzFramework/Physics/Configuration/SceneConfiguration.h>
#include <AzFramework/Physics/Configuration/SimulatedBodyConfiguration.h>
#include <AzFramework/Physics/SimulatedBodies/RigidBody.h>
#include <AzFramework/Physics/Common/PhysicsJoint.h>
namespace Physics
{
@@ -121,9 +122,9 @@ namespace Physics
DefaultMaterialConfiguration::Reflect(context);
MaterialLibraryAsset::Reflect(context);
MaterialInfoReflectionWrapper::Reflect(context);
JointLimitConfiguration::Reflect(context);
AzPhysics::SimulatedBodyConfiguration::Reflect(context);
AzPhysics::RigidBodyConfiguration::Reflect(context);
AzPhysics::JointConfiguration::Reflect(context);
RagdollNodeConfiguration::Reflect(context);
RagdollConfiguration::Reflect(context);
CharacterColliderNodeConfiguration::Reflect(context);
@@ -131,6 +132,7 @@ namespace Physics
AnimationConfiguration::Reflect(context);
CharacterConfiguration::Reflect(context);
AzPhysics::SimulatedBody::Reflect(context);
AzPhysics::Joint::Reflect(context);
ReflectSimulatedBodyComponentRequestsBus(context);
CollisionFilteringRequests::Reflect(context);
AzPhysics::SceneQuery::ReflectSceneQueryObjects(context);
@@ -204,6 +204,8 @@ set(FILES
Physics/Collision/CollisionLayers.cpp
Physics/Collision/CollisionGroups.h
Physics/Collision/CollisionGroups.cpp
Physics/Common/PhysicsJoint.h
Physics/Common/PhysicsJoint.cpp
Physics/Common/PhysicsSceneQueries.h
Physics/Common/PhysicsSceneQueries.cpp
Physics/Common/PhysicsEvents.h
@@ -215,6 +217,8 @@ set(FILES
Physics/Common/PhysicsSimulatedBodyEvents.cpp
Physics/Common/PhysicsTypes.h
Physics/Components/SimulatedBodyComponentBus.h
Physics/Configuration/JointConfiguration.h
Physics/Configuration/JointConfiguration.cpp
Physics/Configuration/CollisionConfiguration.h
Physics/Configuration/CollisionConfiguration.cpp
Physics/Configuration/RigidBodyConfiguration.h
@@ -259,8 +263,6 @@ set(FILES
Physics/Ragdoll.h
Physics/Utils.h
Physics/Utils.cpp
Physics/Joint.h
Physics/Joint.cpp
Physics/ClassConverters.cpp
Physics/ClassConverters.h
Physics/MaterialBus.h
@@ -210,6 +210,15 @@ namespace AzToolsFramework
//! Type to inherit to implement ViewportInteractionRequests.
using ViewportInteractionRequestBus = AZ::EBus<ViewportInteractionRequests, ViewportEBusTraits>;
//! An interface to notify when changes to viewport settings have happened.
class ViewportSettingNotifications
{
public:
virtual void OnGridSnappingChanged(bool enabled) = 0;
};
using ViewportSettingsNotificationBus = AZ::EBus<ViewportSettingNotifications, ViewportEBusTraits>;
//! Requests to freeze the Viewport Input
//! Added to prevent a bug with the legacy CryEngine Viewport code that would
//! keep doing raycast tests even when no level is loaded, causing a crash.
@@ -489,6 +489,16 @@ namespace AzToolsFramework
return buttonId;
}
void SnappingCluster::TrySetVisible(const bool visible)
{
bool snapping = false;
ViewportInteraction::ViewportInteractionRequestBus::EventResult(
snapping, ViewportUi::DefaultViewportId, &ViewportInteraction::ViewportInteractionRequestBus::Events::GridSnappingEnabled);
// show snapping viewport ui only if there are entities selected and snapping is enabled
SetViewportUiClusterVisible(m_clusterId, visible && snapping);
}
// return either center or entity pivot
static AZ::Vector3 CalculatePivotTranslation(const AZ::EntityId entityId, const EditorTransformComponentSelectionRequests::Pivot pivot)
{
@@ -1035,6 +1045,7 @@ namespace AzToolsFramework
EditorEntityLockComponentNotificationBus::Router::BusRouterConnect();
EditorManipulatorCommandUndoRedoRequestBus::Handler::BusConnect(entityContextId);
EditorContextMenuBus::Handler::BusConnect();
ViewportInteraction::ViewportSettingsNotificationBus::Handler::BusConnect(ViewportUi::DefaultViewportId);
CreateTransformModeSelectionCluster();
CreateSpaceSelectionCluster();
@@ -1058,6 +1069,7 @@ namespace AzToolsFramework
m_pivotOverrideFrame.Reset();
ViewportInteraction::ViewportSettingsNotificationBus::Handler::BusDisconnect();
EditorContextMenuBus::Handler::BusConnect();
EditorManipulatorCommandUndoRedoRequestBus::Handler::BusDisconnect();
EditorEntityLockComponentNotificationBus::Router::BusRouterDisconnect();
@@ -3253,7 +3265,7 @@ namespace AzToolsFramework
m_didSetSelectedEntities = false;
}
SetViewportUiClusterVisible(m_snappingCluster.m_clusterId, m_viewportUiVisible && !m_selectedEntityIds.empty());
m_snappingCluster.TrySetVisible(m_viewportUiVisible && !m_selectedEntityIds.empty());
RegenerateManipulators();
}
@@ -3717,6 +3729,11 @@ namespace AzToolsFramework
SetAllViewportUiVisible(true);
}
void EditorTransformComponentSelection::OnGridSnappingChanged([[maybe_unused]] const bool enabled)
{
m_snappingCluster.TrySetVisible(m_viewportUiVisible && !m_selectedEntityIds.empty());
}
namespace ETCS
{
// little raii wrapper to switch a value from true to false and back
@@ -131,6 +131,9 @@ namespace AzToolsFramework
SnappingCluster(const SnappingCluster&) = delete;
SnappingCluster& operator=(const SnappingCluster&) = delete;
//! Attempt to show the snapping cluster (will only succeed if snapping is enabled).
void TrySetVisible(bool visible);
ViewportUi::ClusterId m_clusterId; //!< The cluster id for all snapping buttons.
ViewportUi::ButtonId m_snapToWorldButtonId; //!< The button id for snapping all axes to the world.
AZ::Event<ViewportUi::ButtonId>::Handler m_snappingHandler; //!< Callback for when a snapping cluster button is pressed.
@@ -151,6 +154,7 @@ namespace AzToolsFramework
, private EditorEntityLockComponentNotificationBus::Router
, private EditorManipulatorCommandUndoRedoRequestBus::Handler
, private AZ::TransformNotificationBus::MultiHandler
, private ViewportInteraction::ViewportSettingsNotificationBus::Handler
{
public:
AZ_CLASS_ALLOCATOR_DECL
@@ -289,6 +293,9 @@ namespace AzToolsFramework
void OnStartPlayInEditor() override;
void OnStopPlayInEditor() override;
// ViewportSettingsNotificationBus overrides ...
void OnGridSnappingChanged(bool enabled) override;
// Helpers to safely interact with the TransformBus (requests).
void SetEntityWorldTranslation(AZ::EntityId entityId, const AZ::Vector3& worldTranslation);
void SetEntityLocalTranslation(AZ::EntityId entityId, const AZ::Vector3& localTranslation);
@@ -24,8 +24,6 @@
namespace AzToolsFramework::ViewportUi::Internal
{
// margin for the Viewport UI Overlay in pixels
const static int ViewportUiOverlayMargin = 5;
const static int HighlightBorderSize = 5;
const static int TopHighlightBorderSize = 25;
const static char* HighlightBorderColor = "#44B2F8";
@@ -387,7 +385,6 @@ namespace AzToolsFramework::ViewportUi::Internal
m_fullScreenLayout.setSpacing(0);
m_fullScreenLayout.setContentsMargins(0, 0, 0, 0);
m_fullScreenLayout.addLayout(&m_uiOverlayLayout, 0, 0, 1, 1);
m_uiOverlayLayout.setMargin(ViewportUiOverlayMargin);
// format the label which will appear on top of the highlight border
AZStd::string styleSheet = AZStd::string::format(
@@ -25,13 +25,15 @@ namespace AzToolsFramework::ViewportUi::Internal
: QGridLayout(parent)
{
// set margins and spacing for internal contents
setContentsMargins(0, 0, 0, 0);
setContentsMargins(
ViewportUiOverlayMargin, ViewportUiOverlayMargin + ViewportUiOverlayTopMarginPadding, ViewportUiOverlayMargin,
ViewportUiOverlayMargin);
setSpacing(ViewportUiDisplayLayoutSpacing);
// create a 3x2 map of sub layouts which will stack widgets according to their mapped alignment
m_internalLayouts = AZStd::unordered_map<Qt::Alignment, QBoxLayout*> {
CreateSubLayout(new QVBoxLayout(), 0, 0, Qt::AlignTop | Qt::AlignLeft),
CreateSubLayout(new QHBoxLayout(), 1, 0, Qt::AlignBottom | Qt::AlignLeft),
CreateSubLayout(new QVBoxLayout(), 1, 0, Qt::AlignBottom | Qt::AlignLeft),
CreateSubLayout(new QVBoxLayout(), 0, 1, Qt::AlignTop),
CreateSubLayout(new QHBoxLayout(), 1, 1, Qt::AlignBottom),
CreateSubLayout(new QVBoxLayout(), 0, 2, Qt::AlignTop | Qt::AlignRight),
@@ -50,9 +52,42 @@ namespace AzToolsFramework::ViewportUi::Internal
if (auto layoutForAlignment = m_internalLayouts.find(alignment);
layoutForAlignment != m_internalLayouts.end())
{
// place the widget before the invisible spacer
// spacer must be last item in layout to not interfere with positioning
int index = layoutForAlignment->second->count() - 1;
// place the widget before or after the invisible spacer
// depending on the layout alignment
int index = 0;
switch (alignment)
{
case Qt::AlignTop | Qt::AlignLeft:
case Qt::AlignTop:
index = layoutForAlignment->second->count() - 1;
break;
case Qt::AlignBottom | Qt::AlignRight:
case Qt::AlignBottom:
index = layoutForAlignment->second->count();
break;
// TopRight and BottomLeft are special cases
// place the spacer differently according to whether it's a vertical or horizontal layout
case Qt::AlignTop | Qt::AlignRight:
if (QVBoxLayout* vLayout = qobject_cast<QVBoxLayout*>(layoutForAlignment->second))
{
index = layoutForAlignment->second->count() - 1;
}
else if (QHBoxLayout* hLayout = qobject_cast<QHBoxLayout*>(layoutForAlignment->second))
{
index = layoutForAlignment->second->count();
}
break;
case Qt::AlignBottom | Qt::AlignLeft:
if (QVBoxLayout* vLayout = qobject_cast<QVBoxLayout*>(layoutForAlignment->second))
{
index = layoutForAlignment->second->count();
}
else if (QHBoxLayout* hLayout = qobject_cast<QHBoxLayout*>(layoutForAlignment->second))
{
index = layoutForAlignment->second->count() - 1;
}
break;
}
layoutForAlignment->second->insertWidget(index, widget);
}
}
@@ -19,6 +19,11 @@
namespace AzToolsFramework::ViewportUi::Internal
{
// margin for the Viewport UI Overlay in pixels
constexpr int ViewportUiOverlayMargin = 5;
// padding to make space for ImGui
constexpr int ViewportUiOverlayTopMarginPadding = 20;
//! QGridLayout implementation that uses a grid of QVBox/QHBoxLayouts internally to stack widgets.
class ViewportUiDisplayLayout : public QGridLayout
{
@@ -14,6 +14,7 @@
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/Settings/SettingsRegistry.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzCore/std/string/string_view.h>
namespace SandboxEditor
@@ -56,6 +57,39 @@ namespace SandboxEditor
return value;
}
struct EditorViewportSettingsCallbacksImpl : public EditorViewportSettingsCallbacks
{
EditorViewportSettingsCallbacksImpl()
{
if (auto* registry = AZ::SettingsRegistry::Get())
{
using AZ::SettingsRegistryMergeUtils::IsPathAncestorDescendantOrEqual;
m_notifyEventHandler = registry->RegisterNotifier(
[this](const AZStd::string_view path, [[maybe_unused]] const AZ::SettingsRegistryInterface::Type type)
{
if (IsPathAncestorDescendantOrEqual(GridSnappingSetting, path))
{
m_gridSnappingChanged.Signal(GridSnappingEnabled());
}
});
}
}
void SetGridSnappingChangedEvent(GridSnappingChangedEvent::Handler& handler) override
{
handler.Connect(m_gridSnappingChanged);
}
GridSnappingChangedEvent m_gridSnappingChanged;
AZ::SettingsRegistryInterface::NotifyEventHandler m_notifyEventHandler;
};
AZStd::unique_ptr<EditorViewportSettingsCallbacks> CreateEditorViewportSettingsCallbacks()
{
return AZStd::make_unique<EditorViewportSettingsCallbacksImpl>();
}
bool GridSnappingEnabled()
{
return GetRegistry(GridSnappingSetting, false);
@@ -14,8 +14,27 @@
#include <SandboxAPI.h>
#include <AzCore/Settings/SettingsRegistry.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
namespace SandboxEditor
{
using GridSnappingChangedEvent = AZ::Event<bool>;
//! Set callbacks to listen for editor settings change events.
class EditorViewportSettingsCallbacks
{
public:
virtual ~EditorViewportSettingsCallbacks() = default;
virtual void SetGridSnappingChangedEvent(GridSnappingChangedEvent::Handler& handler) = 0;
};
//! Create an instance of EditorViewportSettingsCallbacks
//! Note: EditorViewportSettingsCallbacks is implemented in EditorViewportSettings.cpp - a change
//! event will fire when a value in the settings registry (editorpreferences.setreg) is modified.
SANDBOX_API AZStd::unique_ptr<EditorViewportSettingsCallbacks> CreateEditorViewportSettingsCallbacks();
SANDBOX_API bool GridSnappingEnabled();
SANDBOX_API void SetGridSnapping(bool enabled);
+11 -1
View File
@@ -76,7 +76,6 @@
#include "EditorPreferencesPageGeneral.h"
#include "ViewportManipulatorController.h"
#include "LegacyViewportCameraController.h"
#include "EditorViewportSettings.h"
#include "ViewPane.h"
#include "CustomResolutionDlg.h"
@@ -1450,6 +1449,17 @@ void EditorViewportWidget::SetViewportId(int id)
{
SetAsActiveViewport();
}
m_editorViewportSettingsCallbacks = SandboxEditor::CreateEditorViewportSettingsCallbacks();
m_gridSnappingHandler = SandboxEditor::GridSnappingChangedEvent::Handler(
[id](const bool snapping)
{
AzToolsFramework::ViewportInteraction::ViewportSettingsNotificationBus::Event(
id, &AzToolsFramework::ViewportInteraction::ViewportSettingsNotificationBus::Events::OnGridSnappingChanged, snapping);
});
m_editorViewportSettingsCallbacks->SetGridSnappingChangedEvent(m_gridSnappingHandler);
}
void EditorViewportWidget::ConnectViewportInteractionRequestBus()
@@ -24,6 +24,7 @@
#include "Objects/DisplayContext.h"
#include "Undo/Undo.h"
#include "Util/PredefinedAspectRatios.h"
#include "EditorViewportSettings.h"
#include <AzCore/Component/EntityId.h>
#include <AzCore/std/optional.h>
@@ -571,6 +572,9 @@ private:
AzFramework::EntityVisibilityQuery m_entityVisibilityQuery;
SandboxEditor::GridSnappingChangedEvent::Handler m_gridSnappingHandler;
AZStd::unique_ptr<SandboxEditor::EditorViewportSettingsCallbacks> m_editorViewportSettingsCallbacks;
QSet<int> m_keyDown;
bool m_freezeViewportInput = false;
@@ -96,6 +96,13 @@ namespace AZ
RPI::AttachmentReadback::CallbackFunction readbackCallback = [&](const RPI::AttachmentReadback::ReadbackResult& result)
{
if (!result.m_dataBuffer)
{
AzToolsFramework::Thumbnailer::ThumbnailerRendererNotificationBus::Event(
m_context->GetData()->m_thumbnailKeyRendered,
&AzToolsFramework::Thumbnailer::ThumbnailerRendererNotifications::ThumbnailFailedToRender);
return;
}
uchar* data = result.m_dataBuffer.get()->data();
QImage image(
data, result.m_imageDescriptor.m_size.m_width, result.m_imageDescriptor.m_size.m_height, QImage::Format_RGBA8888);
-18
View File
@@ -15,7 +15,6 @@
#include <AzCore/Component/TransformBus.h>
#include <AzFramework/Entity/GameEntityContextBus.h>
#include <AzFramework/Physics/Common/PhysicsSceneQueries.h>
#include <AzFramework/Physics/Joint.h>
#include <AzFramework/Physics/RigidBodyBus.h>
#include <AzFramework/Physics/Shape.h>
#include <AzFramework/Physics/SystemBus.h>
@@ -221,23 +220,6 @@ namespace Blast
AZStd::vector<AZStd::shared_ptr<Physics::Material>>(const Physics::MaterialSelection&));
MOCK_METHOD2(
UpdateMaterialSelection, bool(const Physics::ShapeConfiguration&, Physics::ColliderConfiguration&));
MOCK_METHOD0(GetSupportedJointTypes, AZStd::vector<AZ::TypeId>());
MOCK_METHOD1(CreateJointLimitConfiguration, AZStd::shared_ptr<Physics::JointLimitConfiguration>(AZ::TypeId));
MOCK_METHOD3(
CreateJoint,
AZStd::shared_ptr<Physics::Joint>(
const AZStd::shared_ptr<Physics::JointLimitConfiguration>&, AzPhysics::SimulatedBody*, AzPhysics::SimulatedBody*));
MOCK_METHOD10(
GenerateJointLimitVisualizationData,
void(
const Physics::JointLimitConfiguration&, const AZ::Quaternion&, const AZ::Quaternion&, float, AZ::u32,
AZ::u32, AZStd::vector<AZ::Vector3>&, AZStd::vector<AZ::u32>&, AZStd::vector<AZ::Vector3>&,
AZStd::vector<bool>&));
MOCK_METHOD5(
ComputeInitialJointLimitConfiguration,
AZStd::unique_ptr<Physics::JointLimitConfiguration>(
const AZ::TypeId&, const AZ::Quaternion&, const AZ::Quaternion&, const AZ::Vector3&,
const AZStd::vector<AZ::Quaternion>&));
MOCK_METHOD3(CookConvexMeshToFile, bool(const AZStd::string&, const AZ::Vector3*, AZ::u32));
MOCK_METHOD3(CookConvexMeshToMemory, bool(const AZ::Vector3*, AZ::u32, AZStd::vector<AZ::u8>&));
MOCK_METHOD5(
@@ -71,12 +71,7 @@ namespace EMotionFX
newNodeConfig.m_debugName = jointName;
// Create joint limit on default.
AZStd::vector<AZ::TypeId> supportedJointLimitTypes;
Physics::SystemRequestBus::BroadcastResult(supportedJointLimitTypes, &Physics::SystemRequests::GetSupportedJointTypes);
if (!supportedJointLimitTypes.empty())
{
newNodeConfig.m_jointLimit = CommandRagdollHelpers::CreateJointLimitByType(supportedJointLimitTypes[0], skeleton, joint);
}
newNodeConfig.m_jointConfig = CommandRagdollHelpers::CreateJointLimitByType(AzPhysics::JointType::D6Joint, skeleton, joint);
if (index)
{
@@ -91,8 +86,8 @@ namespace EMotionFX
}
}
AZStd::unique_ptr<Physics::JointLimitConfiguration> CommandRagdollHelpers::CreateJointLimitByType(
const AZ::TypeId& typeId, const Skeleton* skeleton, const Node* node)
AZStd::unique_ptr<AzPhysics::JointConfiguration> CommandRagdollHelpers::CreateJointLimitByType(
AzPhysics::JointType jointType, const Skeleton* skeleton, const Node* node)
{
const Pose* bindPose = skeleton->GetBindPose();
const Transform& nodeBindTransform = bindPose->GetModelSpaceTransform(node->GetNodeIndex());
@@ -105,12 +100,20 @@ namespace EMotionFX
AZ::Vector3 boneDirection = GetBoneDirection(skeleton, node);
AZStd::vector<AZ::Quaternion> exampleRotationsLocal;
AZStd::unique_ptr<Physics::JointLimitConfiguration> jointLimitConfig =
AZ::Interface<Physics::System>::Get()->ComputeInitialJointLimitConfiguration(
typeId, parentBindRotationWorld, nodeBindRotationWorld, boneDirection, exampleRotationsLocal);
if (auto* jointHelpers = AZ::Interface<AzPhysics::JointHelpersInterface>::Get())
{
if (AZStd::optional<const AZ::TypeId> jointTypeId = jointHelpers->GetSupportedJointTypeId(jointType);
jointTypeId.has_value())
{
AZStd::unique_ptr<AzPhysics::JointConfiguration> jointLimitConfig = jointHelpers->ComputeInitialJointLimitConfiguration(
*jointTypeId, parentBindRotationWorld, nodeBindRotationWorld, boneDirection, exampleRotationsLocal);
AZ_Assert(jointLimitConfig, "Could not create joint limit configuration with type '%s'.", typeId.ToString<AZStd::string>().c_str());
return jointLimitConfig;
AZ_Assert(jointLimitConfig, "Could not create joint limit configuration.");
return jointLimitConfig;
}
}
AZ_Assert(false, "Could not create joint limit configuration.");
return nullptr;
}
void CommandRagdollHelpers::AddJointsToRagdoll(AZ::u32 actorId, const AZStd::vector<AZStd::string>& jointNames,
@@ -532,7 +535,7 @@ namespace EMotionFX
if (m_serializedJointLimits)
{
AZ::Outcome<AZStd::string> oldSerializedJointLimits = SerializeJointLimits(nodeConfig);
success |= MCore::ReflectionSerializer::DeserializeMembers(nodeConfig->m_jointLimit.get(), m_serializedJointLimits.value());
success |= MCore::ReflectionSerializer::DeserializeMembers(nodeConfig->m_jointConfig.get(), m_serializedJointLimits.value());
if (success && oldSerializedJointLimits.IsSuccess())
{
m_oldSerializedJointLimits = oldSerializedJointLimits.GetValue();
@@ -565,7 +568,7 @@ namespace EMotionFX
AZ::Outcome<AZStd::string> CommandAdjustRagdollJoint::SerializeJointLimits(const Physics::RagdollNodeConfiguration* ragdollNodeConfig)
{
return MCore::ReflectionSerializer::SerializeMembersExcept(
ragdollNodeConfig->m_jointLimit.get(),
ragdollNodeConfig->m_jointConfig.get(),
{"ParentLocalRotation", "ParentLocalPosition", "ChildLocalRotation", "ChildLocalPosition", }
);
}
@@ -45,8 +45,8 @@ namespace EMotionFX
Physics::RagdollConfiguration& ragdollConfig, const AZStd::optional<size_t>& index,
AZStd::string& outResult);
static AZStd::unique_ptr<Physics::JointLimitConfiguration> CreateJointLimitByType(const AZ::TypeId& typeId,
const Skeleton* skeleton, const Node* node);
static AZStd::unique_ptr<AzPhysics::JointConfiguration> CreateJointLimitByType(
AzPhysics::JointType jointType, const Skeleton* skeleton, const Node* node);
static void AddJointsToRagdoll(AZ::u32 actorId, const AZStd::vector<AZStd::string>& jointNames,
MCore::CommandGroup* commandGroup = nullptr, bool executeInsideCommand = false, bool addDefaultCollider = true);
@@ -90,12 +90,15 @@ namespace EMotionFX
if (serializeContext)
{
AZStd::vector<AZ::TypeId> supportedJointLimitTypes;
Physics::SystemRequestBus::BroadcastResult(supportedJointLimitTypes, &Physics::SystemRequests::GetSupportedJointTypes);
for (const AZ::TypeId& jointLimitType : supportedJointLimitTypes)
//D6 joint is the only currently supported joint for ragdoll
if (auto* jointHelpers = AZ::Interface<AzPhysics::JointHelpersInterface>::Get())
{
const char* jointLimitName = serializeContext->FindClassData(jointLimitType)->m_editData->m_name;
m_typeComboBox->addItem(jointLimitName, jointLimitType.ToString<AZStd::string>().c_str());
if (AZStd::optional<const AZ::TypeId> d6jointTypeId = jointHelpers->GetSupportedJointTypeId(AzPhysics::JointType::D6Joint);
d6jointTypeId.has_value())
{
const char* jointLimitName = serializeContext->FindClassData(*d6jointTypeId)->m_editData->m_name;
m_typeComboBox->addItem(jointLimitName, (*d6jointTypeId).ToString<AZStd::string>().c_str());
}
}
// Reflected property editor for joint limit
@@ -134,7 +137,7 @@ namespace EMotionFX
Physics::RagdollNodeConfiguration* ragdollNodeConfig = GetRagdollNodeConfig();
if (ragdollNodeConfig)
{
Physics::JointLimitConfiguration* jointLimitConfig = ragdollNodeConfig->m_jointLimit.get();
AzPhysics::JointConfiguration* jointLimitConfig = ragdollNodeConfig->m_jointConfig.get();
if (jointLimitConfig)
{
const AZ::TypeId& jointTypeId = jointLimitConfig->RTTI_GetType();
@@ -262,13 +265,14 @@ namespace EMotionFX
{
if (type.IsNull())
{
ragdollNodeConfig->m_jointLimit = nullptr;
ragdollNodeConfig->m_jointConfig = nullptr;
}
else
{
const Node* node = m_nodeIndex.data(SkeletonModel::ROLE_POINTER).value<Node*>();
const Skeleton* skeleton = m_nodeIndex.data(SkeletonModel::ROLE_ACTOR_POINTER).value<Actor*>()->GetSkeleton();
ragdollNodeConfig->m_jointLimit = CommandRagdollHelpers::CreateJointLimitByType(type, skeleton, node);
ragdollNodeConfig->m_jointConfig =
CommandRagdollHelpers::CreateJointLimitByType(AzPhysics::JointType::D6Joint, skeleton, node);
}
Update();
@@ -13,7 +13,6 @@
#pragma once
#if !defined(Q_MOC_RUN)
#include <AzFramework/Physics/Joint.h>
#include <AzFramework/Physics/Ragdoll.h>
#include <AzQtComponents/Components/Widgets/Card.h>
#include <QModelIndex>
@@ -514,7 +514,7 @@ namespace EMotionFX
if (renderJointLimits && jointSelected)
{
const AZStd::shared_ptr<Physics::JointLimitConfiguration>& jointLimitConfig = ragdollNode.m_jointLimit;
const AZStd::shared_ptr<AzPhysics::JointConfiguration>& jointLimitConfig = ragdollNode.m_jointConfig;
if (jointLimitConfig)
{
const Node* ragdollParentNode = physicsSetup->FindRagdollParentNode(joint);
@@ -528,7 +528,8 @@ namespace EMotionFX
}
}
void RagdollNodeInspectorPlugin::RenderJointLimit(const Physics::JointLimitConfiguration& configuration,
void RagdollNodeInspectorPlugin::RenderJointLimit(
const AzPhysics::JointConfiguration& configuration,
const ActorInstance* actorInstance,
const Node* node,
const Node* parentNode,
@@ -549,9 +550,12 @@ namespace EMotionFX
m_indexBuffer.clear();
m_lineBuffer.clear();
m_lineValidityBuffer.clear();
Physics::SystemRequestBus::Broadcast(&Physics::SystemRequests::GenerateJointLimitVisualizationData,
configuration, parentOrientation, childOrientation, s_scale, s_angularSubdivisions, s_radialSubdivisions,
m_vertexBuffer, m_indexBuffer, m_lineBuffer, m_lineValidityBuffer);
if(auto* jointHelpers = AZ::Interface<AzPhysics::JointHelpersInterface>::Get())
{
jointHelpers->GenerateJointLimitVisualizationData(
configuration, parentOrientation, childOrientation, s_scale, s_angularSubdivisions, s_radialSubdivisions, m_vertexBuffer,
m_indexBuffer, m_lineBuffer, m_lineValidityBuffer);
}
Transform jointModelSpaceTransform = currentPose->GetModelSpaceTransform(parentNodeIndex);
jointModelSpaceTransform.mPosition = currentPose->GetModelSpaceTransform(nodeIndex).mPosition;
@@ -572,7 +576,8 @@ namespace EMotionFX
}
}
void RagdollNodeInspectorPlugin::RenderJointFrame(const Physics::JointLimitConfiguration& configuration,
void RagdollNodeInspectorPlugin::RenderJointFrame(
const AzPhysics::JointConfiguration& configuration,
const ActorInstance* actorInstance,
const Node* node,
const Node* parentNode,
@@ -60,14 +60,16 @@ namespace EMotionFX
void Render(EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo) override;
void RenderRagdoll(ActorInstance* actorInstance, bool renderColliders, bool renderJointLimits, EMStudio::RenderPlugin* renderPlugin, RenderInfo* renderInfo);
void RenderJointLimit(const Physics::JointLimitConfiguration& jointConfiguration,
void RenderJointLimit(
const AzPhysics::JointConfiguration& jointConfiguration,
const ActorInstance* actorInstance,
const Node* node,
const Node* parentNode,
EMStudio::RenderPlugin* renderPlugin,
EMStudio::EMStudioPlugin::RenderInfo* renderInfo,
const MCore::RGBAColor& color);
void RenderJointFrame(const Physics::JointLimitConfiguration& jointConfiguration,
void RenderJointFrame(
const AzPhysics::JointConfiguration& jointConfiguration,
const ActorInstance* actorInstance,
const Node* node,
const Node* parentNode,
@@ -19,7 +19,7 @@ namespace EMotionFX
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<D6JointLimitConfiguration, Physics::JointLimitConfiguration>()
serializeContext->Class<D6JointLimitConfiguration, AzPhysics::JointConfiguration>()
->Version(1)
->Field("SwingLimitY", &D6JointLimitConfiguration::m_swingLimitY)
->Field("SwingLimitZ", &D6JointLimitConfiguration::m_swingLimitZ)
@@ -12,23 +12,22 @@
#pragma once
#include <AzFramework/Physics/Joint.h>
#include <AzFramework/Physics/Configuration/JointConfiguration.h>
namespace EMotionFX
{
// Add so that RagdollNodeInspectorPlugin::PhysXCharactersGemAvailable() will return the correct value
// We duplicated the D6JointLimitConfiguration because it doesn't exist in the test environment.
class D6JointLimitConfiguration
: public Physics::JointLimitConfiguration
: public AzPhysics::JointConfiguration
{
public:
AZ_CLASS_ALLOCATOR(D6JointLimitConfiguration, AZ::SystemAllocator, 0);
// This uses the same uuid as the production D6JointLimitConfiguration.
// The Ragdoll UI uses this UUID to see if physx is available.
AZ_RTTI(D6JointLimitConfiguration, "{90C5C23D-16C0-4F23-AD50-A190E402388E}", Physics::JointLimitConfiguration);
AZ_RTTI(D6JointLimitConfiguration, "{90C5C23D-16C0-4F23-AD50-A190E402388E}", AzPhysics::JointConfiguration);
static void Reflect(AZ::ReflectContext* context);
const char* GetTypeName() override { return "D6 Joint"; }
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.
@@ -35,11 +35,6 @@ namespace Physics
MOCK_METHOD2(CreateShape, AZStd::shared_ptr<Physics::Shape>(const Physics::ColliderConfiguration& colliderConfiguration, const Physics::ShapeConfiguration& configuration));
MOCK_METHOD1(ReleaseNativeMeshObject, void(void* nativeMeshObject));
MOCK_METHOD1(CreateMaterial, AZStd::shared_ptr<Physics::Material>(const Physics::MaterialConfiguration& materialConfiguration));
MOCK_METHOD0(GetSupportedJointTypes, AZStd::vector<AZ::TypeId>());
MOCK_METHOD1(CreateJointLimitConfiguration, AZStd::shared_ptr<Physics::JointLimitConfiguration>(AZ::TypeId jointType));
MOCK_METHOD3(CreateJoint, AZStd::shared_ptr<Physics::Joint>(const AZStd::shared_ptr<Physics::JointLimitConfiguration>& configuration, AzPhysics::SimulatedBody* parentBody, AzPhysics::SimulatedBody* childBody));
MOCK_METHOD10(GenerateJointLimitVisualizationData, void(const Physics::JointLimitConfiguration& configuration, const AZ::Quaternion& parentRotation, const AZ::Quaternion& childRotation, float scale, AZ::u32 angularSubdivisions, AZ::u32 radialSubdivisions, AZStd::vector<AZ::Vector3>& vertexBufferOut, AZStd::vector<AZ::u32>& indexBufferOut, AZStd::vector<AZ::Vector3>& lineBufferOut, AZStd::vector<bool>& lineValidityBufferOut));
MOCK_METHOD5(ComputeInitialJointLimitConfiguration, AZStd::unique_ptr<Physics::JointLimitConfiguration>(const AZ::TypeId& jointLimitTypeId, const AZ::Quaternion& parentWorldRotation, const AZ::Quaternion& childWorldRotation, const AZ::Vector3& axis, const AZStd::vector<AZ::Quaternion>& exampleLocalRotations));
MOCK_METHOD3(CookConvexMeshToFile, bool(const AZStd::string& filePath, const AZ::Vector3* vertices, AZ::u32 vertexCount));
MOCK_METHOD3(CookConvexMeshToMemory, bool(const AZ::Vector3* vertices, AZ::u32 vertexCount, AZStd::vector<AZ::u8>& result));
MOCK_METHOD5(CookTriangleMeshToFile, bool(const AZStd::string& filePath, const AZ::Vector3* vertices, AZ::u32 vertexCount, const AZ::u32* indices, AZ::u32 indexCount));
@@ -72,6 +67,36 @@ namespace Physics
MOCK_CONST_METHOD0(GetDefaultSceneConfiguration, const AzPhysics::SceneConfiguration& ());
};
class MockJointHelpersInterface : AZ::Interface<AzPhysics::JointHelpersInterface>::Registrar
{
public:
MOCK_CONST_METHOD0(GetSupportedJointTypeIds, const AZStd::vector<AZ::TypeId>());
MOCK_CONST_METHOD1(GetSupportedJointTypeId, AZStd::optional<const AZ::TypeId>(AzPhysics::JointType typeEnum));
MOCK_METHOD5(
ComputeInitialJointLimitConfiguration,
AZStd::unique_ptr<AzPhysics::JointConfiguration>(
const AZ::TypeId& jointLimitTypeId,
const AZ::Quaternion& parentWorldRotation,
const AZ::Quaternion& childWorldRotation,
const AZ::Vector3& axis,
const AZStd::vector<AZ::Quaternion>& exampleLocalRotations));
MOCK_METHOD10(
GenerateJointLimitVisualizationData,
void(
const AzPhysics::JointConfiguration& configuration,
const AZ::Quaternion& parentRotation,
const AZ::Quaternion& childRotation,
float scale,
AZ::u32 angularSubdivisions,
AZ::u32 radialSubdivisions,
AZStd::vector<AZ::Vector3>& vertexBufferOut,
AZStd::vector<AZ::u32>& indexBufferOut,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut));
};
//Mocked of the AzPhysics Scene Interface. To keep things simple just mocked functions that have a return value OR required for a test.
class MockPhysicsSceneInterface
: AZ::Interface<AzPhysics::SceneInterface>::Registrar
@@ -97,6 +122,9 @@ namespace Physics
void DisableSimulationOfBody(
[[maybe_unused]] AzPhysics::SceneHandle sceneHandle,
[[maybe_unused]] AzPhysics::SimulatedBodyHandle bodyHandle) override {}
void RemoveJoint(
[[maybe_unused]]AzPhysics::SceneHandle sceneHandle,
[[maybe_unused]] AzPhysics::JointHandle jointHandle) override {}
void SuppressCollisionEvents(
[[maybe_unused]] AzPhysics::SceneHandle sceneHandle,
[[maybe_unused]] const AzPhysics::SimulatedBodyHandle& bodyHandleA,
@@ -145,6 +173,9 @@ namespace Physics
MOCK_METHOD2(AddSimulatedBodies, AzPhysics::SimulatedBodyHandleList(AzPhysics::SceneHandle sceneHandle, const AzPhysics::SimulatedBodyConfigurationList& simulatedBodyConfigs));
MOCK_METHOD2(GetSimulatedBodyFromHandle, AzPhysics::SimulatedBody* (AzPhysics::SceneHandle sceneHandle, AzPhysics::SimulatedBodyHandle bodyHandle));
MOCK_METHOD2(GetSimulatedBodiesFromHandle, AzPhysics::SimulatedBodyList(AzPhysics::SceneHandle sceneHandle, const AzPhysics::SimulatedBodyHandleList& bodyHandles));
MOCK_METHOD4(AddJoint, AzPhysics::JointHandle(AzPhysics::SceneHandle sceneHandle, const AzPhysics::JointConfiguration* jointConfig,
AzPhysics::SimulatedBodyHandle parentBody, AzPhysics::SimulatedBodyHandle childBody));
MOCK_METHOD2(GetJointFromHandle, AzPhysics::Joint* (AzPhysics::SceneHandle sceneHandle, AzPhysics::JointHandle bodyHandle));
MOCK_CONST_METHOD1(GetGravity, AZ::Vector3(AzPhysics::SceneHandle sceneHandle));
MOCK_METHOD2(RegisterSceneSimulationFinishHandler, void(AzPhysics::SceneHandle sceneHandle, AzPhysics::SceneEvents::OnSceneSimulationFinishHandler& handler));
MOCK_CONST_METHOD2(GetLegacyBody, AzPhysics::SimulatedBody* (AzPhysics::SceneHandle sceneHandle, AzPhysics::SimulatedBodyHandle handle));
@@ -16,6 +16,7 @@
#include <AzCore/std/algorithm.h>
#include <AzFramework/Physics/Character.h>
#include <AzFramework/Physics/ShapeConfiguration.h>
#include <AzFramework/Physics/Common/PhysicsJoint.h>
#include <EMotionFX/CommandSystem/Source/ColliderCommands.h>
#include <EMotionFX/CommandSystem/Source/RagdollCommands.h>
@@ -44,10 +45,21 @@ namespace EMotionFX
D6JointLimitConfiguration::Reflect(GetSerializeContext());
const AZ::TypeId& jointLimitTypeId = azrtti_typeid<D6JointLimitConfiguration>();
EXPECT_CALL(m_physicsSystem, GetSupportedJointTypes)
.WillRepeatedly(testing::Return(AZStd::vector<AZ::TypeId>{jointLimitTypeId}));
EXPECT_CALL(m_physicsSystem, ComputeInitialJointLimitConfiguration(jointLimitTypeId, _, _, _, _))
EXPECT_CALL(m_jointHelpers, GetSupportedJointTypeIds)
.WillRepeatedly(testing::Return(AZStd::vector<AZ::TypeId>{ azrtti_typeid<D6JointLimitConfiguration>() }));
EXPECT_CALL(m_jointHelpers, GetSupportedJointTypeId(_))
.WillRepeatedly(
[](AzPhysics::JointType jointType) -> AZStd::optional<const AZ::TypeId>
{
if (jointType == AzPhysics::JointType::D6Joint)
{
return azrtti_typeid<D6JointLimitConfiguration>();
}
return AZStd::nullopt;
});
EXPECT_CALL(m_jointHelpers, ComputeInitialJointLimitConfiguration(_, _, _, _, _))
.WillRepeatedly([]([[maybe_unused]] const AZ::TypeId& jointLimitTypeId,
[[maybe_unused]] const AZ::Quaternion& parentWorldRotation,
[[maybe_unused]] const AZ::Quaternion& childWorldRotation,
@@ -59,6 +71,7 @@ namespace EMotionFX
private:
Physics::MockPhysicsSystem m_physicsSystem;
Physics::MockPhysicsInterface m_physicsInterface;
Physics::MockJointHelpersInterface m_jointHelpers;
};
#if AZ_TRAIT_DISABLE_FAILED_EMOTION_FX_EDITOR_TESTS
@@ -55,10 +55,27 @@ namespace EMotionFX
Physics::MockPhysicsSystem physicsSystem;
Physics::MockPhysicsInterface physicsInterface;
EXPECT_CALL(physicsSystem, GetSupportedJointTypes)
.WillRepeatedly(testing::Return(AZStd::vector<AZ::TypeId>{azrtti_typeid<D6JointLimitConfiguration>()}));
EXPECT_CALL(physicsSystem, ComputeInitialJointLimitConfiguration(azrtti_typeid<D6JointLimitConfiguration>(), _, _, _, _))
.WillRepeatedly([]([[maybe_unused]] const AZ::TypeId& jointLimitTypeId, [[maybe_unused]] const AZ::Quaternion& parentWorldRotation, [[maybe_unused]] const AZ::Quaternion& childWorldRotation, [[maybe_unused]] const AZ::Vector3& axis, [[maybe_unused]] const AZStd::vector<AZ::Quaternion>& exampleLocalRotations) { return AZStd::make_unique<D6JointLimitConfiguration>(); });
Physics::MockJointHelpersInterface jointHelpers;
EXPECT_CALL(jointHelpers, GetSupportedJointTypeIds)
.WillRepeatedly(testing::Return(AZStd::vector<AZ::TypeId>{ azrtti_typeid<D6JointLimitConfiguration>() }));
EXPECT_CALL(jointHelpers, GetSupportedJointTypeId(_))
.WillRepeatedly(
[](AzPhysics::JointType jointType) -> AZStd::optional<const AZ::TypeId>
{
if (jointType == AzPhysics::JointType::D6Joint)
{
return azrtti_typeid<D6JointLimitConfiguration>();
}
return AZStd::nullopt;
});
EXPECT_CALL(jointHelpers, ComputeInitialJointLimitConfiguration(_, _, _, _, _))
.WillRepeatedly(
[]([[maybe_unused]] const AZ::TypeId& jointLimitTypeId,
[[maybe_unused]] const AZ::Quaternion& parentWorldRotation, [[maybe_unused]] const AZ::Quaternion& childWorldRotation,
[[maybe_unused]] const AZ::Vector3& axis, [[maybe_unused]] const AZStd::vector<AZ::Quaternion>& exampleLocalRotations)
{
return AZStd::make_unique<D6JointLimitConfiguration>();
});
AutoRegisteredActor actor {ActorFactory::CreateAndInit<SimpleJointChainActor>(4)};
@@ -70,7 +87,7 @@ namespace EMotionFX
CommandRagdollHelpers::AddJointsToRagdoll(actor->GetID(), {"rootJoint", "joint1", "joint2", "joint3"});
const Physics::RagdollConfiguration& ragdollConfig = actor->GetPhysicsSetup()->GetRagdollConfig();
ASSERT_EQ(ragdollConfig.m_nodes.size(), 4);
AZStd::shared_ptr<D6JointLimitConfiguration> rootJointLimit = AZStd::rtti_pointer_cast<D6JointLimitConfiguration>(ragdollConfig.FindNodeConfigByName("rootJoint")->m_jointLimit);
AZStd::shared_ptr<D6JointLimitConfiguration> rootJointLimit = AZStd::rtti_pointer_cast<D6JointLimitConfiguration>(ragdollConfig.FindNodeConfigByName("rootJoint")->m_jointConfig);
ASSERT_TRUE(rootJointLimit);
// Set the initial joint limits on the rootJoint to be something different
rootJointLimit->m_swingLimitY = 1.0f;
@@ -119,7 +136,8 @@ namespace EMotionFX
selectionModel.select(joint1Index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
// Verify initial state of joint1's limits
const AZStd::shared_ptr<D6JointLimitConfiguration> joint1Limit = AZStd::rtti_pointer_cast<D6JointLimitConfiguration>(ragdollConfig.FindNodeConfigByName("joint1")->m_jointLimit);
const AZStd::shared_ptr<D6JointLimitConfiguration> joint1Limit =
AZStd::rtti_pointer_cast<D6JointLimitConfiguration>(ragdollConfig.FindNodeConfigByName("joint1")->m_jointConfig);
EXPECT_EQ(joint1Limit->m_swingLimitY, 45.0f);
EXPECT_EQ(joint1Limit->m_swingLimitZ, 45.0f);
@@ -141,10 +159,12 @@ namespace EMotionFX
selectionModel.select(joint2Index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
selectionModel.select(joint3Index, QItemSelectionModel::Select | QItemSelectionModel::Rows);
const AZStd::shared_ptr<D6JointLimitConfiguration> joint2Limit = AZStd::rtti_pointer_cast<D6JointLimitConfiguration>(ragdollConfig.FindNodeConfigByName("joint2")->m_jointLimit);
const AZStd::shared_ptr<D6JointLimitConfiguration> joint2Limit =
AZStd::rtti_pointer_cast<D6JointLimitConfiguration>(ragdollConfig.FindNodeConfigByName("joint2")->m_jointConfig);
EXPECT_EQ(joint2Limit->m_swingLimitY, 45.0f);
EXPECT_EQ(joint2Limit->m_swingLimitZ, 45.0f);
const AZStd::shared_ptr<D6JointLimitConfiguration> joint3Limit = AZStd::rtti_pointer_cast<D6JointLimitConfiguration>(ragdollConfig.FindNodeConfigByName("joint3")->m_jointLimit);
const AZStd::shared_ptr<D6JointLimitConfiguration> joint3Limit =
AZStd::rtti_pointer_cast<D6JointLimitConfiguration>(ragdollConfig.FindNodeConfigByName("joint3")->m_jointConfig);
EXPECT_EQ(joint3Limit->m_swingLimitY, 45.0f);
EXPECT_EQ(joint3Limit->m_swingLimitZ, 45.0f);
@@ -18,11 +18,47 @@
#include <EMotionFX/CommandSystem/Source/CommandManager.h>
#include <EMotionFX/CommandSystem/Source/RagdollCommands.h>
#include <EMotionFX/CommandSystem/Source/ColliderCommands.h>
#include <Tests/D6JointLimitConfiguration.h>
#include <Tests/Mocks/PhysicsSystem.h>
namespace EMotionFX
{
using RagdollCommandTests = ActorFixture;
class RagdollCommandTests : public ActorFixture
{
public:
void SetUp() override
{
using ::testing::_;
ActorFixture::SetUp();
D6JointLimitConfiguration::Reflect(GetSerializeContext());
EXPECT_CALL(m_jointHelpers, GetSupportedJointTypeIds)
.WillRepeatedly(testing::Return(AZStd::vector<AZ::TypeId>{ azrtti_typeid<D6JointLimitConfiguration>() }));
EXPECT_CALL(m_jointHelpers, GetSupportedJointTypeId(_))
.WillRepeatedly(
[](AzPhysics::JointType jointType) -> AZStd::optional<const AZ::TypeId>
{
if (jointType == AzPhysics::JointType::D6Joint)
{
return azrtti_typeid<D6JointLimitConfiguration>();
}
return AZStd::nullopt;
});
EXPECT_CALL(m_jointHelpers, ComputeInitialJointLimitConfiguration(_, _, _, _, _))
.WillRepeatedly([]([[maybe_unused]] const AZ::TypeId& jointLimitTypeId,
[[maybe_unused]] const AZ::Quaternion& parentWorldRotation,
[[maybe_unused]] const AZ::Quaternion& childWorldRotation,
[[maybe_unused]] const AZ::Vector3& axis,
[[maybe_unused]] const AZStd::vector<AZ::Quaternion>& exampleLocalRotations)
{ return AZStd::make_unique<D6JointLimitConfiguration>(); });
}
protected:
Physics::MockJointHelpersInterface m_jointHelpers;
};
AZStd::vector<AZStd::string> GetRagdollJointNames(const Actor* actor)
{
@@ -10,6 +10,7 @@
*
*/
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <QPushButton>
@@ -29,6 +30,7 @@
#include <Tests/UI/ModalPopupHandler.h>
#include <Tests/UI/UIFixture.h>
#include <Tests/D6JointLimitConfiguration.h>
#include <Tests/Mocks/PhysicsSystem.h>
namespace EMotionFX
{
@@ -140,6 +142,31 @@ namespace EMotionFX
TEST_F(CanAddToSimulatedObjectFixture, CanAddCollidersfromRagdoll)
{
using ::testing::_;
Physics::MockJointHelpersInterface jointHelpers;
EXPECT_CALL(jointHelpers, GetSupportedJointTypeIds)
.WillRepeatedly(testing::Return(AZStd::vector<AZ::TypeId>{ azrtti_typeid<D6JointLimitConfiguration>() }));
EXPECT_CALL(jointHelpers, GetSupportedJointTypeId(_))
.WillRepeatedly(
[](AzPhysics::JointType jointType) -> AZStd::optional<const AZ::TypeId>
{
if (jointType == AzPhysics::JointType::D6Joint)
{
return azrtti_typeid<D6JointLimitConfiguration>();
}
return AZStd::nullopt;
});
EXPECT_CALL(jointHelpers, ComputeInitialJointLimitConfiguration(_, _, _, _, _))
.WillRepeatedly(
[]([[maybe_unused]] const AZ::TypeId& jointLimitTypeId, [[maybe_unused]] const AZ::Quaternion& parentWorldRotation,
[[maybe_unused]] const AZ::Quaternion& childWorldRotation, [[maybe_unused]] const AZ::Vector3& axis,
[[maybe_unused]] const AZStd::vector<AZ::Quaternion>& exampleLocalRotations)
{
return AZStd::make_unique<D6JointLimitConfiguration>();
});
RecordProperty("test_case_id", "C13291807");
AutoRegisteredActor actor = ActorFactory::CreateAndInit<SimpleJointChainActor>(7, "CanAddToSimulatedObjectActor");
@@ -10,6 +10,7 @@
*
*/
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <QtTest>
@@ -27,6 +28,7 @@
#include <Editor/ReselectingTreeView.h>
#include <Tests/D6JointLimitConfiguration.h>
#include <Tests/Mocks/PhysicsSystem.h>
namespace EMotionFX
{
@@ -35,6 +37,8 @@ namespace EMotionFX
public:
void SetUp() override
{
using ::testing::_;
SetupQtAndFixtureBase();
AZ::SerializeContext* serializeContext = nullptr;
@@ -42,6 +46,29 @@ namespace EMotionFX
D6JointLimitConfiguration::Reflect(serializeContext);
EXPECT_CALL(m_jointHelpers, GetSupportedJointTypeIds)
.WillRepeatedly(testing::Return(AZStd::vector<AZ::TypeId>{ azrtti_typeid<D6JointLimitConfiguration>() }));
EXPECT_CALL(m_jointHelpers, GetSupportedJointTypeId(_))
.WillRepeatedly(
[](AzPhysics::JointType jointType) -> AZStd::optional<const AZ::TypeId>
{
if (jointType == AzPhysics::JointType::D6Joint)
{
return azrtti_typeid<D6JointLimitConfiguration>();
}
return AZStd::nullopt;
});
EXPECT_CALL(m_jointHelpers, ComputeInitialJointLimitConfiguration(_, _, _, _, _))
.WillRepeatedly(
[]([[maybe_unused]] const AZ::TypeId& jointLimitTypeId, [[maybe_unused]] const AZ::Quaternion& parentWorldRotation,
[[maybe_unused]] const AZ::Quaternion& childWorldRotation, [[maybe_unused]] const AZ::Vector3& axis,
[[maybe_unused]] const AZStd::vector<AZ::Quaternion>& exampleLocalRotations)
{
return AZStd::make_unique<D6JointLimitConfiguration>();
});
SetupPluginWindows();
}
@@ -73,6 +100,7 @@ namespace EMotionFX
QModelIndexList m_indexList;
ReselectingTreeView* m_treeView;
EMotionFX::SkeletonOutlinerPlugin* m_skeletonOutliner;
Physics::MockJointHelpersInterface m_jointHelpers;
};
@@ -63,8 +63,6 @@ set(FILES
Tests/Integration/CanDeleteJackEntity.cpp
Tests/Bugs/CanDeleteMotionWhenMotionIsBeingBlended.cpp
Tests/Bugs/CanUndoParameterDeletionAndRestoreBlendTreeConnections.cpp
Tests/D6JointLimitConfiguration.cpp
Tests/D6JointLimitConfiguration.h
Tests/Editor/FileManagerTests.cpp
Tests/Editor/ParametersGroupDefaultValues.cpp
Tests/Editor/MotionSetLoadEscalation.cpp
@@ -21,4 +21,6 @@ set(FILES
Tests/TestAssetCode/AnimGraphAssetFactory.h
Tests/TestAssetCode/ActorAssetFactory.h
Tests/TestAssetCode/MotionSetAssetFactory.h
Tests/D6JointLimitConfiguration.cpp
Tests/D6JointLimitConfiguration.h
)
+11
View File
@@ -156,6 +156,8 @@ endif()
################################################################################
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_add_target(
NAME PhysX.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
NAMESPACE Gem
@@ -174,6 +176,15 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
RUNTIME_DEPENDENCIES
Gem::LmbrCentral
)
if(PAL_TRAIT_JOINTS_TYPED_TEST_CASE)
ly_add_source_properties(
SOURCES Tests/PhysXJointsTest.cpp
PROPERTY COMPILE_DEFINITIONS
VALUES ENABLE_JOINTS_TYPED_TEST_CASE
)
endif()
ly_add_googletest(
NAME Gem::PhysX.Tests
)
@@ -144,11 +144,12 @@ namespace PhysX
{
return m_standardLimitConfig.m_isLimited;
}
GenericJointLimitsConfiguration EditorJointLimitPairConfig::ToGameTimeConfig() const
JointLimitProperties EditorJointLimitPairConfig::ToGameTimeConfig() const
{
return GenericJointLimitsConfiguration(m_standardLimitConfig.m_damping
, m_standardLimitConfig.m_isLimited
return JointLimitProperties(m_standardLimitConfig.m_isLimited
, m_standardLimitConfig.m_isSoftLimit
, m_standardLimitConfig.m_damping
, m_limitPositive, m_limitNegative
, m_standardLimitConfig.m_stiffness
, m_standardLimitConfig.m_tolerance);
@@ -193,11 +194,11 @@ namespace PhysX
return m_standardLimitConfig.m_isLimited;
}
GenericJointLimitsConfiguration EditorJointLimitConeConfig::ToGameTimeConfig() const
JointLimitProperties EditorJointLimitConeConfig::ToGameTimeConfig() const
{
return GenericJointLimitsConfiguration(m_standardLimitConfig.m_damping
, m_standardLimitConfig.m_isLimited
return JointLimitProperties(m_standardLimitConfig.m_isLimited
, m_standardLimitConfig.m_isSoftLimit
, m_standardLimitConfig.m_damping
, m_limitY
, m_limitZ
, m_standardLimitConfig.m_stiffness
@@ -275,27 +276,31 @@ namespace PhysX
, AzToolsFramework::Refresh_AttributesAndValues);
}
GenericJointConfiguration EditorJointConfig::ToGameTimeConfig() const
JointGenericProperties EditorJointConfig::ToGenericProperties() const
{
GenericJointConfiguration::GenericJointFlag flags = GenericJointConfiguration::GenericJointFlag::None;
JointGenericProperties::GenericJointFlag flags = JointGenericProperties::GenericJointFlag::None;
if (m_breakable)
{
flags |= GenericJointConfiguration::GenericJointFlag::Breakable;
flags |= JointGenericProperties::GenericJointFlag::Breakable;
}
if (m_selfCollide)
{
flags |= GenericJointConfiguration::GenericJointFlag::SelfCollide;
flags |= JointGenericProperties::GenericJointFlag::SelfCollide;
}
return JointGenericProperties(flags, m_forceMax, m_torqueMax);
}
JointComponentConfiguration EditorJointConfig::ToGameTimeConfig() const
{
AZ::Vector3 localRotation(m_localRotation);
return GenericJointConfiguration(m_forceMax
, m_torqueMax
, AZ::Transform::CreateFromQuaternionAndTranslation(AZ::Quaternion::CreateFromEulerAnglesDegrees(localRotation),
m_localPosition)
, m_leadEntity
, m_followerEntity
, flags);
return JointComponentConfiguration(
AZ::Transform::CreateFromQuaternionAndTranslation(
AZ::Quaternion::CreateFromEulerAnglesDegrees(localRotation),
m_localPosition),
m_leadEntity,
m_followerEntity);
}
bool EditorJointConfig::IsInComponentMode() const
@@ -15,7 +15,7 @@
#include <AzCore/Component/EntityId.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <Source/Joint.h>
#include <Source/JointComponent.h>
namespace PhysX
{
@@ -68,7 +68,7 @@ namespace PhysX
static void Reflect(AZ::ReflectContext* context);
bool IsLimited() const;
GenericJointLimitsConfiguration ToGameTimeConfig() const;
JointLimitProperties ToGameTimeConfig() const;
EditorJointLimitConfig m_standardLimitConfig;
float m_limitPositive = 45.0f;
@@ -87,7 +87,7 @@ namespace PhysX
static void Reflect(AZ::ReflectContext* context);
bool IsLimited() const;
GenericJointLimitsConfiguration ToGameTimeConfig() const;
JointLimitProperties ToGameTimeConfig() const;
EditorJointLimitConfig m_standardLimitConfig;
float m_limitY = 45.0f;
@@ -105,7 +105,8 @@ namespace PhysX
static void Reflect(AZ::ReflectContext* context);
void SetLeadEntityId(AZ::EntityId leadEntityId);
GenericJointConfiguration ToGameTimeConfig() const;
JointGenericProperties ToGenericProperties() const;
JointComponentConfiguration ToGameTimeConfig() const;
bool m_breakable = false;
bool m_displayJointSetup = false;
@@ -0,0 +1,107 @@
/*
* 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 <AzFramework/Physics/Configuration/JointConfiguration.h>
namespace PhysX
{
struct D6JointLimitConfiguration
: public AzPhysics::JointConfiguration
{
AZ_CLASS_ALLOCATOR(D6JointLimitConfiguration, AZ::SystemAllocator, 0);
AZ_RTTI(D6JointLimitConfiguration, "{88E067B4-21E8-4FFA-9142-6C52605B704C}", AzPhysics::JointConfiguration);
static void Reflect(AZ::ReflectContext* context);
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.
};
//! Properties that are common for several types of joints.
struct JointGenericProperties
{
enum class GenericJointFlag : AZ::u16
{
None = 0,
Breakable = 1,
SelfCollide = 1 << 1
};
AZ_CLASS_ALLOCATOR(JointGenericProperties, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(JointGenericProperties, "{6CB15399-24F6-4F03-AAEF-1AE013B683E0}");
static void Reflect(AZ::ReflectContext* context);
JointGenericProperties() = default;
JointGenericProperties(GenericJointFlag flags, float forceMax, float torqueMax);
bool IsFlagSet(GenericJointFlag flag) const; ///< Returns if a particular flag is set as a bool.
/// Flags that indicates if joint is breakable, self-colliding, etc.
/// Converting joint between breakable/non-breakable at game time is allowed.
GenericJointFlag m_flags = GenericJointFlag::None;
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_DEFINE_ENUM_BITWISE_OPERATORS(PhysX::JointGenericProperties::GenericJointFlag)
struct JointLimitProperties
{
AZ_CLASS_ALLOCATOR(JointLimitProperties, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(JointLimitProperties, "{31F941CB-6699-48BB-B12D-61874B52B984}");
static void Reflect(AZ::ReflectContext* context);
JointLimitProperties() = default;
JointLimitProperties(
bool isLimited, bool isSoftLimit,
float damping, 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.
};
struct FixedJointConfiguration : public AzPhysics::JointConfiguration
{
AZ_CLASS_ALLOCATOR(FixedJointConfiguration, AZ::SystemAllocator, 0);
AZ_RTTI(FixedJointConfiguration, "{9BCB368B-8D71-4928-B231-0225907E3BD9}", AzPhysics::JointConfiguration);
static void Reflect(AZ::ReflectContext* context);
JointGenericProperties m_genericProperties;
};
struct BallJointConfiguration : public AzPhysics::JointConfiguration
{
AZ_CLASS_ALLOCATOR(BallJointConfiguration, AZ::SystemAllocator, 0);
AZ_RTTI(BallJointConfiguration, "{C2DE2479-B752-469D-BE05-900CD2CD8481}", AzPhysics::JointConfiguration);
static void Reflect(AZ::ReflectContext* context);
JointGenericProperties m_genericProperties;
JointLimitProperties m_limitProperties;
};
struct HingeJointConfiguration : public AzPhysics::JointConfiguration
{
AZ_CLASS_ALLOCATOR(HingeJointConfiguration, AZ::SystemAllocator, 0);
AZ_RTTI(HingeJointConfiguration, "{FB04198E-0BA5-45C2-8343-66DA28ED45EA}", AzPhysics::JointConfiguration);
static void Reflect(AZ::ReflectContext* context);
JointGenericProperties m_genericProperties;
JointLimitProperties m_limitProperties;
};
} // namespace PhysX
+23 -45
View File
@@ -16,8 +16,10 @@
#include <PhysX/MathConversion.h>
#include <PhysX/PhysXLocks.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Interface/Interface.h>
#include <AzFramework/Physics/SimulatedBodies/RigidBody.h>
#include <AzFramework/Physics/RigidBodyBus.h>
#include <AzFramework/Physics/PhysicsScene.h>
#include <PxPhysicsAPI.h>
@@ -33,15 +35,17 @@ namespace PhysX
}
}
BallJointComponent::BallJointComponent(const GenericJointConfiguration& config
, const GenericJointLimitsConfiguration& swingLimit)
: JointComponent(config, swingLimit)
BallJointComponent::BallJointComponent(
const JointComponentConfiguration& configuration,
const JointGenericProperties& genericProperties,
const JointLimitProperties& limitProperties)
: JointComponent(configuration, genericProperties, limitProperties)
{
}
void BallJointComponent::InitNativeJoint()
{
if (m_joint)
if (m_jointHandle != AzPhysics::InvalidJointHandle)
{
return;
}
@@ -52,50 +56,24 @@ namespace PhysX
{
return;
}
PHYSX_SCENE_READ_LOCK(leadFollowerInfo.m_followerActor->getScene());
m_joint = AZStd::make_shared<BallJoint>(physx::PxSphericalJointCreate(
PxGetPhysics(),
leadFollowerInfo.m_leadActor,
leadFollowerInfo.m_leadLocal,
leadFollowerInfo.m_followerActor,
leadFollowerInfo.m_followerLocal),
leadFollowerInfo.m_leadBody,
leadFollowerInfo.m_followerBody);
InitSwingLimits();
}
BallJointConfiguration configuration;
configuration.m_parentLocalPosition = leadFollowerInfo.m_leadLocal.GetTranslation();
configuration.m_parentLocalRotation = leadFollowerInfo.m_leadLocal.GetRotation();
configuration.m_childLocalPosition = leadFollowerInfo.m_followerLocal.GetTranslation();
configuration.m_childLocalRotation = leadFollowerInfo.m_followerLocal.GetRotation();
void BallJointComponent::InitSwingLimits()
{
if (!m_joint)
configuration.m_genericProperties = m_genericProperties;
configuration.m_limitProperties = m_limits;
if (auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get())
{
return;
m_jointHandle = sceneInterface->AddJoint(
leadFollowerInfo.m_followerBody->m_sceneOwner,
&configuration,
leadFollowerInfo.m_leadBody->m_bodyHandle,
leadFollowerInfo.m_followerBody->m_bodyHandle);
m_jointSceneOwner = leadFollowerInfo.m_followerBody->m_sceneOwner;
}
physx::PxSphericalJoint* ballJointNative = static_cast<physx::PxSphericalJoint*>(m_joint->GetNativePointer());
if (!ballJointNative)
{
return;
}
if (!m_limits.m_isLimited)
{
ballJointNative->setSphericalJointFlag(physx::PxSphericalJointFlag::eLIMIT_ENABLED, false);
return;
}
// Hard limit uses a tolerance value (distance to limit at which limit becomes active).
// Soft limit allows angle to exceed limit but springs back with configurable spring stiffness and damping.
physx::PxJointLimitCone swingLimit(AZ::DegToRad(m_limits.m_limitFirst)
, AZ::DegToRad(m_limits.m_limitSecond)
, m_limits.m_tolerance);
if (m_limits.m_isSoftLimit)
{
swingLimit.stiffness = m_limits.m_stiffness;
swingLimit.damping = m_limits.m_damping;
}
ballJointNative->setLimitCone(swingLimit);
ballJointNative->setSphericalJointFlag(physx::PxSphericalJointFlag::eLIMIT_ENABLED, true);
}
} // namespace PhysX
+4 -5
View File
@@ -25,15 +25,14 @@ namespace PhysX
static void Reflect(AZ::ReflectContext* context);
BallJointComponent() = default;
BallJointComponent(const GenericJointConfiguration& config
, const GenericJointLimitsConfiguration& swingLimit);
BallJointComponent(
const JointComponentConfiguration& configuration,
const JointGenericProperties& genericProperties,
const JointLimitProperties& limitProperties);
~BallJointComponent() = default;
protected:
// JointComponent
void InitNativeJoint() override;
private:
void InitSwingLimits();
};
} // namespace PhysX
@@ -99,6 +99,7 @@ namespace PhysX
m_config.m_followerEntity = GetEntityId(); // joint is always in the same entity as the follower body.
gameEntity->CreateComponent<BallJointComponent>(
m_config.ToGameTimeConfig(),
m_config.ToGenericProperties(),
m_swingLimit.ToGameTimeConfig());
}
@@ -13,7 +13,6 @@
#pragma once
#include <AzFramework/Physics/Joint.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <AzToolsFramework/API/ComponentEntitySelectionBus.h>
#include <AzToolsFramework/ComponentMode/ComponentModeDelegate.h>
@@ -94,6 +94,6 @@ namespace PhysX
void EditorFixedJointComponent::BuildGameEntity(AZ::Entity* gameEntity)
{
m_config.m_followerEntity = GetEntityId(); // joint is always in the same entity as the follower body.
gameEntity->CreateComponent<FixedJointComponent>(m_config.ToGameTimeConfig());
gameEntity->CreateComponent<FixedJointComponent>(m_config.ToGameTimeConfig(), m_config.ToGenericProperties());
}
}
@@ -13,7 +13,6 @@
#pragma once
#include <AzFramework/Physics/Joint.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <AzToolsFramework/API/ComponentEntitySelectionBus.h>
#include <AzToolsFramework/ComponentMode/ComponentModeDelegate.h>
@@ -99,6 +99,7 @@ namespace PhysX
m_config.m_followerEntity = GetEntityId(); // joint is always in the same entity as the follower body.
gameEntity->CreateComponent<HingeJointComponent>(
m_config.ToGameTimeConfig(),
m_config.ToGenericProperties(),
m_angularLimit.ToGameTimeConfig());
}
@@ -13,7 +13,6 @@
#pragma once
#include <AzFramework/Physics/Joint.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <AzToolsFramework/API/ComponentEntitySelectionBus.h>
#include <AzToolsFramework/ComponentMode/ComponentModeDelegate.h>
@@ -13,7 +13,6 @@
#pragma once
#include <AzFramework/Physics/Joint.h>
#include <AzFramework/Visibility/BoundsBus.h>
#include <AzToolsFramework/API/ComponentEntitySelectionBus.h>
+31 -15
View File
@@ -17,6 +17,9 @@
#include <AzCore/Component/TransformBus.h>
#include <AzFramework/Physics/SimulatedBodies/RigidBody.h>
#include <AzFramework/Physics/RigidBodyBus.h>
#include <PhysX/Joint/Configuration/PhysXJointConfiguration.h>
#include <AzFramework/Physics/PhysicsScene.h>
#include <AzCore/Interface/Interface.h>
#include <PxPhysicsAPI.h>
@@ -33,20 +36,24 @@ namespace PhysX
}
}
FixedJointComponent::FixedJointComponent(const GenericJointConfiguration& config)
: JointComponent(config)
FixedJointComponent::FixedJointComponent(
const JointComponentConfiguration& configuration,
const JointGenericProperties& genericProperties)
: JointComponent(configuration, genericProperties)
{
}
FixedJointComponent::FixedJointComponent(const GenericJointConfiguration& config,
const GenericJointLimitsConfiguration& limitConfig)
: JointComponent(config, limitConfig)
FixedJointComponent::FixedJointComponent(
const JointComponentConfiguration& configuration,
const JointGenericProperties& genericProperties,
const JointLimitProperties& limitProperties)
: JointComponent(configuration, genericProperties, limitProperties)
{
}
void FixedJointComponent::InitNativeJoint()
{
if (m_joint)
if (m_jointHandle != AzPhysics::InvalidJointHandle)
{
return;
}
@@ -57,14 +64,23 @@ namespace PhysX
{
return;
}
PHYSX_SCENE_READ_LOCK(leadFollowerInfo.m_followerActor->getScene());
m_joint = AZStd::make_shared<FixedJoint>(physx::PxFixedJointCreate(
PxGetPhysics(),
leadFollowerInfo.m_leadActor,
leadFollowerInfo.m_leadLocal,
leadFollowerInfo.m_followerActor,
leadFollowerInfo.m_followerLocal),
leadFollowerInfo.m_leadBody,
leadFollowerInfo.m_followerBody);
FixedJointConfiguration configuration;
configuration.m_parentLocalPosition = leadFollowerInfo.m_leadLocal.GetTranslation();
configuration.m_parentLocalRotation = leadFollowerInfo.m_leadLocal.GetRotation();
configuration.m_childLocalPosition = leadFollowerInfo.m_followerLocal.GetTranslation();
configuration.m_childLocalRotation = leadFollowerInfo.m_followerLocal.GetRotation();
configuration.m_genericProperties = m_genericProperties;
if (auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get())
{
m_jointHandle = sceneInterface->AddJoint(
leadFollowerInfo.m_followerBody->m_sceneOwner,
&configuration,
leadFollowerInfo.m_leadBody->m_bodyHandle,
leadFollowerInfo.m_followerBody->m_bodyHandle);
m_jointSceneOwner = leadFollowerInfo.m_followerBody->m_sceneOwner;
}
}
} // namespace PhysX
+7 -3
View File
@@ -25,9 +25,13 @@ namespace PhysX
static void Reflect(AZ::ReflectContext* context);
FixedJointComponent() = default;
explicit FixedJointComponent(const GenericJointConfiguration& config);
FixedJointComponent(const GenericJointConfiguration& config,
const GenericJointLimitsConfiguration& limitConfig);
FixedJointComponent(
const JointComponentConfiguration& configuration,
const JointGenericProperties& genericProperties);
FixedJointComponent(
const JointComponentConfiguration& configuration,
const JointGenericProperties& genericProperties,
const JointLimitProperties& limitProperties);
~FixedJointComponent() = default;
protected:
+23 -43
View File
@@ -16,8 +16,10 @@
#include <PhysX/MathConversion.h>
#include <PhysX/PhysXLocks.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Interface/Interface.h>
#include <AzFramework/Physics/RigidBodyBus.h>
#include <AzFramework/Physics/SimulatedBodies/RigidBody.h>
#include <AzFramework/Physics/PhysicsScene.h>
#include <PxPhysicsAPI.h>
@@ -34,67 +36,45 @@ namespace PhysX
}
}
HingeJointComponent::HingeJointComponent(const GenericJointConfiguration& config
, const GenericJointLimitsConfiguration& angularLimitConfig)
: JointComponent(config, angularLimitConfig)
HingeJointComponent::HingeJointComponent(
const JointComponentConfiguration& configuration,
const JointGenericProperties& genericProperties,
const JointLimitProperties& limitProperties)
: JointComponent(configuration, genericProperties, limitProperties)
{
}
void HingeJointComponent::InitNativeJoint()
{
if (m_joint)
if (m_jointHandle != AzPhysics::InvalidJointHandle)
{
return;
}
JointComponent::LeadFollowerInfo leadFollowerInfo;
ObtainLeadFollowerInfo(leadFollowerInfo);
if (!leadFollowerInfo.m_followerActor)
{
return;
}
PHYSX_SCENE_READ_LOCK(leadFollowerInfo.m_followerActor->getScene());
m_joint = AZStd::make_shared<HingeJoint>(physx::PxRevoluteJointCreate(
PxGetPhysics(),
leadFollowerInfo.m_leadActor,
leadFollowerInfo.m_leadLocal,
leadFollowerInfo.m_followerActor,
leadFollowerInfo.m_followerLocal),
leadFollowerInfo.m_leadBody,
leadFollowerInfo.m_followerBody);
InitAngularLimits();
}
void HingeJointComponent::InitAngularLimits()
{
if (!m_joint)
if (leadFollowerInfo.m_followerActor == nullptr ||
leadFollowerInfo.m_leadBody == nullptr ||
leadFollowerInfo.m_followerBody == nullptr)
{
return;
}
physx::PxRevoluteJoint* revoluteJointNative = static_cast<physx::PxRevoluteJoint*>(m_joint->GetNativePointer());
if (!revoluteJointNative)
{
return;
}
HingeJointConfiguration configuration;
configuration.m_parentLocalPosition = leadFollowerInfo.m_leadLocal.GetTranslation();
configuration.m_parentLocalRotation = leadFollowerInfo.m_leadLocal.GetRotation();
configuration.m_childLocalPosition = leadFollowerInfo.m_followerLocal.GetTranslation();
configuration.m_childLocalRotation = leadFollowerInfo.m_followerLocal.GetRotation();
if (!m_limits.m_isLimited)
{
revoluteJointNative->setRevoluteJointFlag(physx::PxRevoluteJointFlag::eLIMIT_ENABLED, false);
return;
}
configuration.m_genericProperties = m_genericProperties;
configuration.m_limitProperties = m_limits;
physx::PxJointAngularLimitPair limitPair(AZ::DegToRad(m_limits.m_limitSecond)
, AZ::DegToRad(m_limits.m_limitFirst)
, m_limits.m_tolerance);
if (m_limits.m_isSoftLimit)
if (auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get())
{
limitPair.stiffness = m_limits.m_stiffness;
limitPair.damping = m_limits.m_damping;
m_jointHandle = sceneInterface->AddJoint(
leadFollowerInfo.m_followerBody->m_sceneOwner, &configuration, leadFollowerInfo.m_leadBody->m_bodyHandle,
leadFollowerInfo.m_followerBody->m_bodyHandle);
m_jointSceneOwner = leadFollowerInfo.m_followerBody->m_sceneOwner;
}
revoluteJointNative->setLimit(limitPair);
revoluteJointNative->setRevoluteJointFlag(physx::PxRevoluteJointFlag::eLIMIT_ENABLED, true);
}
} // namespace PhysX
+4 -5
View File
@@ -25,15 +25,14 @@ namespace PhysX
static void Reflect(AZ::ReflectContext* context);
HingeJointComponent() = default;
explicit HingeJointComponent(const GenericJointConfiguration& config
, const GenericJointLimitsConfiguration& angularLimit);
HingeJointComponent(
const JointComponentConfiguration& configuration,
const JointGenericProperties& genericProperties,
const JointLimitProperties& limitProperties);
~HingeJointComponent() = default;
protected:
// JointComponent
void InitNativeJoint() override;
private:
void InitAngularLimits();
};
} // namespace PhysX
-646
View File
@@ -1,646 +0,0 @@
/*
* 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.
*
*/
#include <PhysX_precompiled.h>
#include <Joint.h>
#include <AzCore/Serialization/EditContext.h>
#include <Include/PhysX/NativeTypeIdentifiers.h>
#include <AzCore/Math/MathUtils.h>
#include <PhysX/PhysXLocks.h>
#include <AzFramework/Physics/Common/PhysicsSimulatedBody.h>
namespace PhysX
{
namespace JointConstants
{
// Setting swing limits to very small values can cause extreme stability problems, so clamp above a small
// threshold.
static const float MinSwingLimitDegrees = 1.0f;
} // namespace JointConstants
AzPhysics::SimulatedBody* Joint::GetParentBody() const
{
return m_parentBody;
}
AzPhysics::SimulatedBody* Joint::GetChildBody() const
{
return m_childBody;
}
bool IsAtLeastOneDynamic(AzPhysics::SimulatedBody* body0,
AzPhysics::SimulatedBody* body1)
{
for (const AzPhysics::SimulatedBody* body : { body0, body1 })
{
if (body)
{
if (body->GetNativeType() == NativeTypeIdentifiers::RigidBody ||
body->GetNativeType() == NativeTypeIdentifiers::ArticulationLink)
{
return true;
}
}
}
return false;
}
physx::PxRigidActor* GetPxRigidActor(AzPhysics::SimulatedBody* worldBody)
{
if (worldBody && static_cast<physx::PxBase*>(worldBody->GetNativePointer())->is<physx::PxRigidActor>())
{
return static_cast<physx::PxRigidActor*>(worldBody->GetNativePointer());
}
return nullptr;
}
void releasePxJoint(physx::PxJoint* joint)
{
PHYSX_SCENE_WRITE_LOCK(joint->getScene());
joint->userData = nullptr;
joint->release();
}
Joint::Joint(physx::PxJoint* pxJoint, AzPhysics::SimulatedBody* parentBody,
AzPhysics::SimulatedBody* childBody)
: m_parentBody(parentBody)
, m_childBody(childBody)
{
m_pxJoint = PxJointUniquePtr(pxJoint, releasePxJoint);
}
bool Joint::SetPxActors()
{
physx::PxRigidActor* parentActor = GetPxRigidActor(m_parentBody);
physx::PxRigidActor* childActor = GetPxRigidActor(m_childBody);
if (!parentActor && !childActor)
{
AZ_Error("PhysX Joint", false, "Invalid PhysX actors in joint - at least one must be a PxRigidActor.");
return false;
}
m_pxJoint->setActors(parentActor, childActor);
return true;
}
void Joint::SetParentBody(AzPhysics::SimulatedBody* parentBody)
{
if (IsAtLeastOneDynamic(parentBody, m_childBody))
{
m_parentBody = parentBody;
SetPxActors();
}
else
{
AZ_Warning("PhysX Joint", false, "Call to SetParentBody would result in invalid joint - at least one "
"body in a joint must be dynamic.");
}
}
void Joint::SetChildBody(AzPhysics::SimulatedBody* childBody)
{
if (IsAtLeastOneDynamic(m_parentBody, childBody))
{
m_childBody = childBody;
SetPxActors();
}
else
{
AZ_Warning("PhysX Joint", false, "Call to SetChildBody would result in invalid joint - at least one "
"body in a joint must be dynamic.");
}
}
const AZStd::string& Joint::GetName() const
{
return m_name;
}
void Joint::SetName(const AZStd::string& name)
{
m_name = name;
}
void* Joint::GetNativePointer()
{
return m_pxJoint.get();
}
const AZ::Crc32 D6Joint::GetNativeType() const
{
return NativeTypeIdentifiers::D6Joint;
}
void D6Joint::GenerateJointLimitVisualizationData(
float scale,
AZ::u32 angularSubdivisions,
AZ::u32 radialSubdivisions,
[[maybe_unused]] AZStd::vector<AZ::Vector3>& vertexBufferOut,
[[maybe_unused]] AZStd::vector<AZ::u32>& indexBufferOut,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut)
{
const AZ::u32 angularSubdivisionsClamped = AZ::GetClamp(angularSubdivisions, 4u, 32u);
const AZ::u32 radialSubdivisionsClamped = AZ::GetClamp(radialSubdivisions, 1u, 4u);
const physx::PxD6Joint* joint = static_cast<physx::PxD6Joint*>(m_pxJoint.get());
const AZ::Quaternion parentLocalRotation = PxMathConvert(joint->getLocalPose(physx::PxJointActorIndex::eACTOR0).q);
const AZ::Quaternion parentWorldRotation = m_parentBody ? m_parentBody->GetOrientation() : AZ::Quaternion::CreateIdentity();
const AZ::Quaternion childLocalRotation = PxMathConvert(joint->getLocalPose(physx::PxJointActorIndex::eACTOR1).q);
const AZ::Quaternion childWorldRotation = m_childBody ? m_childBody->GetOrientation() : AZ::Quaternion::CreateIdentity();
const float swingAngleY = joint->getSwingYAngle();
const float swingAngleZ = joint->getSwingZAngle();
const float swingLimitY = joint->getSwingLimit().yAngle;
const float swingLimitZ = joint->getSwingLimit().zAngle;
const float twistAngle = joint->getTwist();
const float twistLimitLower = joint->getTwistLimit().lower;
const float twistLimitUpper = joint->getTwistLimit().upper;
JointUtils::AppendD6SwingConeToLineBuffer(parentLocalRotation, swingAngleY, swingAngleZ, swingLimitY, swingLimitZ,
scale, angularSubdivisionsClamped, radialSubdivisionsClamped, lineBufferOut, lineValidityBufferOut);
JointUtils::AppendD6TwistArcToLineBuffer(parentLocalRotation, twistAngle, twistLimitLower, twistLimitUpper,
scale, angularSubdivisionsClamped, radialSubdivisionsClamped, lineBufferOut, lineValidityBufferOut);
JointUtils::AppendD6CurrentTwistToLineBuffer(parentLocalRotation, twistAngle, twistLimitLower, twistLimitUpper,
scale, lineBufferOut, lineValidityBufferOut);
// draw the X-axis of the child joint frame
// make the axis slightly longer than the radius of the twist arc so that it is easy to see
float axisLength = 1.25f * scale;
AZ::Vector3 childAxis = (parentWorldRotation.GetConjugate() * childWorldRotation * childLocalRotation).TransformVector(
AZ::Vector3::CreateAxisX(axisLength));
lineBufferOut.push_back(AZ::Vector3::CreateZero());
lineBufferOut.push_back(childAxis);
}
const AZ::Crc32 FixedJoint::GetNativeType() const
{
return NativeTypeIdentifiers::FixedJoint;
}
const AZ::Crc32 HingeJoint::GetNativeType() const
{
return NativeTypeIdentifiers::HingeJoint;
}
const AZ::Crc32 BallJoint::GetNativeType() const
{
return NativeTypeIdentifiers::BallJoint;
}
void GenericJointConfiguration::Reflect(AZ::ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<GenericJointConfiguration>()
->Version(2, &VersionConverter)
->Field("Follower Local Transform", &GenericJointConfiguration::m_localTransformFromFollower)
->Field("Maximum Force", &GenericJointConfiguration::m_forceMax)
->Field("Maximum Torque", &GenericJointConfiguration::m_torqueMax)
->Field("Lead Entity", &GenericJointConfiguration::m_leadEntity)
->Field("Follower Entity", &GenericJointConfiguration::m_followerEntity)
->Field("Flags", &GenericJointConfiguration::m_flags)
;
}
}
bool GenericJointConfiguration::VersionConverter(
AZ::SerializeContext& context,
AZ::SerializeContext::DataElementNode& classElement)
{
if (classElement.GetVersion() <= 1)
{
// Convert bool breakable to GenericJointConfiguration::GenericJointFlag
const int breakableElementIndex = classElement.FindElement(AZ_CRC("Breakable", 0xb274ecd4));
if (breakableElementIndex >= 0)
{
bool breakable = false;
AZ::SerializeContext::DataElementNode& breakableNode = classElement.GetSubElement(breakableElementIndex);
breakableNode.GetData(breakable);
if (!breakableNode.GetData<bool>(breakable))
{
return false;
}
classElement.RemoveElement(breakableElementIndex);
GenericJointConfiguration::GenericJointFlag flags = breakable ? GenericJointConfiguration::GenericJointFlag::Breakable : GenericJointConfiguration::GenericJointFlag::None;
classElement.AddElementWithData(context, "Flags", flags);
}
}
return true;
}
GenericJointConfiguration::GenericJointConfiguration(float forceMax,
float torqueMax,
AZ::Transform localTransformFromFollower,
AZ::EntityId leadEntity,
AZ::EntityId followerEntity,
GenericJointFlag flags)
: m_forceMax(forceMax)
, m_torqueMax(torqueMax)
, m_localTransformFromFollower(localTransformFromFollower)
, m_leadEntity(leadEntity)
, m_followerEntity(followerEntity)
, m_flags(flags)
{
}
bool GenericJointConfiguration::GetFlag(GenericJointFlag flag)
{
return static_cast<bool>(m_flags & flag);
}
void GenericJointLimitsConfiguration::Reflect(AZ::ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<GenericJointLimitsConfiguration>()
->Version(1)
->Field("First Limit", &GenericJointLimitsConfiguration::m_limitFirst)
->Field("Second Limit", &GenericJointLimitsConfiguration::m_limitSecond)
->Field("Tolerance", &GenericJointLimitsConfiguration::m_tolerance)
->Field("Is Limited", &GenericJointLimitsConfiguration::m_isLimited)
->Field("Is Soft Limit", &GenericJointLimitsConfiguration::m_isSoftLimit)
->Field("Damping", &GenericJointLimitsConfiguration::m_damping)
->Field("Spring", &GenericJointLimitsConfiguration::m_stiffness)
;
}
}
GenericJointLimitsConfiguration::GenericJointLimitsConfiguration(float damping
, bool isLimited
, bool isSoftLimit
, float limitFirst
, float limitSecond
, float stiffness
, float tolerance)
: m_damping(damping)
, m_isLimited(isLimited)
, m_isSoftLimit(isSoftLimit)
, m_limitFirst(limitFirst)
, m_limitSecond(limitSecond)
, m_stiffness(stiffness)
, m_tolerance(tolerance)
{
}
AZStd::vector<AZ::TypeId> JointUtils::GetSupportedJointTypes()
{
return AZStd::vector<AZ::TypeId>
{
D6JointLimitConfiguration::RTTI_Type()
};
}
AZStd::shared_ptr<Physics::JointLimitConfiguration> JointUtils::CreateJointLimitConfiguration([[maybe_unused]] AZ::TypeId jointType)
{
return AZStd::make_shared<D6JointLimitConfiguration>();
}
AZStd::shared_ptr<Physics::Joint> JointUtils::CreateJoint(const AZStd::shared_ptr<Physics::JointLimitConfiguration>& configuration,
AzPhysics::SimulatedBody* parentBody, AzPhysics::SimulatedBody* childBody)
{
if (!configuration)
{
AZ_Warning("PhysX Joint", false, "CreateJoint failed - configuration was nullptr.");
return nullptr;
}
if (auto d6Config = AZStd::rtti_pointer_cast<D6JointLimitConfiguration>(configuration))
{
if (!IsAtLeastOneDynamic(parentBody, childBody))
{
AZ_Warning("PhysX Joint", false, "CreateJoint failed - at least one body must be dynamic.");
return nullptr;
}
physx::PxRigidActor* parentActor = GetPxRigidActor(parentBody);
physx::PxRigidActor* childActor = GetPxRigidActor(childBody);
if (!parentActor && !childActor)
{
AZ_Warning("PhysX Joint", false, "CreateJoint failed - at least one body must be a PxRigidActor.");
return nullptr;
}
const physx::PxTransform parentWorldTransform = parentActor ? parentActor->getGlobalPose() : physx::PxTransform(physx::PxIdentity);
const physx::PxTransform childWorldTransform = childActor ? childActor->getGlobalPose() : physx::PxTransform(physx::PxIdentity);
const physx::PxVec3 childOffset = childWorldTransform.p - parentWorldTransform.p;
physx::PxTransform parentLocalTransform(PxMathConvert(d6Config->m_parentLocalRotation).getNormalized());
const physx::PxTransform childLocalTransform(PxMathConvert(d6Config->m_childLocalRotation).getNormalized());
parentLocalTransform.p = parentWorldTransform.q.rotateInv(childOffset);
physx::PxD6Joint* joint = PxD6JointCreate(PxGetPhysics(), parentActor, parentLocalTransform,
childActor, childLocalTransform);
joint->setMotion(physx::PxD6Axis::eTWIST, physx::PxD6Motion::eLIMITED);
joint->setMotion(physx::PxD6Axis::eSWING1, physx::PxD6Motion::eLIMITED);
joint->setMotion(physx::PxD6Axis::eSWING2, physx::PxD6Motion::eLIMITED);
AZ_Warning("PhysX Joint",
d6Config->m_swingLimitY >= JointConstants::MinSwingLimitDegrees && d6Config->m_swingLimitZ >= JointConstants::MinSwingLimitDegrees,
"Very small swing limit requested for joint between \"%s\" and \"%s\", increasing to %f degrees to improve stability",
parentActor ? parentActor->getName() : "world", childActor ? childActor->getName() : "world",
JointConstants::MinSwingLimitDegrees);
float swingLimitY = AZ::DegToRad(AZ::GetMax(JointConstants::MinSwingLimitDegrees, d6Config->m_swingLimitY));
float swingLimitZ = AZ::DegToRad(AZ::GetMax(JointConstants::MinSwingLimitDegrees, d6Config->m_swingLimitZ));
physx::PxJointLimitCone limitCone(swingLimitY, swingLimitZ);
joint->setSwingLimit(limitCone);
float twistLower = AZ::DegToRad(AZStd::GetMin(d6Config->m_twistLimitLower, d6Config->m_twistLimitUpper));
float twistUpper = AZ::DegToRad(AZStd::GetMax(d6Config->m_twistLimitLower, d6Config->m_twistLimitUpper));
physx::PxJointAngularLimitPair twistLimitPair(twistLower, twistUpper);
joint->setTwistLimit(twistLimitPair);
return AZStd::make_shared<D6Joint>(joint, parentBody, childBody);
}
else
{
AZ_Warning("PhysX Joint", false, "Unrecognized joint limit configuration.");
return nullptr;
}
}
D6JointState JointUtils::CalculateD6JointState(
const AZ::Quaternion& parentWorldRotation,
const AZ::Quaternion& parentLocalRotation,
const AZ::Quaternion& childWorldRotation,
const AZ::Quaternion& childLocalRotation)
{
D6JointState result;
const AZ::Quaternion parentRotation = parentWorldRotation * parentLocalRotation;
const AZ::Quaternion childRotation = childWorldRotation * childLocalRotation;
const AZ::Quaternion relativeRotation = parentRotation.GetConjugate() * childRotation;
AZ::Quaternion twistQuat = AZ::IsClose(relativeRotation.GetX(), 0.0f, AZ::Constants::FloatEpsilon)
? AZ::Quaternion::CreateIdentity()
: AZ::Quaternion(relativeRotation.GetX(), 0.0f, 0.0f, relativeRotation.GetW()).GetNormalized();
AZ::Quaternion swingQuat = relativeRotation * twistQuat.GetConjugate();
// make sure the twist angle has the correct sign for the rotation
twistQuat *= AZ::GetSign(twistQuat.GetX());
// make sure we get the shortest arcs for the swing degrees of freedom
swingQuat *= AZ::GetSign(swingQuat.GetW());
// the PhysX swing limits work in terms of tan quarter angles
result.m_swingAngleY = 4.0f * atan2f(swingQuat.GetY(), 1.0f + swingQuat.GetW());
result.m_swingAngleZ = 4.0f * atan2f(swingQuat.GetZ(), 1.0f + swingQuat.GetW());
const float twistAngle = twistQuat.GetAngle();
// GetAngle returns an angle in the range 0..2 pi, but the twist limits work in the range -pi..pi
const float wrappedTwistAngle = twistAngle > AZ::Constants::Pi ? twistAngle - AZ::Constants::TwoPi : twistAngle;
result.m_twistAngle = wrappedTwistAngle;
return result;
}
bool JointUtils::IsD6SwingValid(
float swingAngleY,
float swingAngleZ,
float swingLimitY,
float swingLimitZ)
{
const float epsilon = AZ::Constants::FloatEpsilon;
const float yFactor = tanf(0.25f * swingAngleY) / AZStd::GetMax(epsilon, tanf(0.25f * swingLimitY));
const float zFactor = tanf(0.25f * swingAngleZ) / AZStd::GetMax(epsilon, tanf(0.25f * swingLimitZ));
return (yFactor * yFactor + zFactor * zFactor <= 1.0f + epsilon);
}
void JointUtils::AppendD6SwingConeToLineBuffer(
const AZ::Quaternion& parentLocalRotation,
float swingAngleY,
float swingAngleZ,
float swingLimitY,
float swingLimitZ,
float scale,
AZ::u32 angularSubdivisions,
AZ::u32 radialSubdivisions,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut)
{
const AZ::u32 numLinesSwingCone = angularSubdivisions * (1u + radialSubdivisions);
lineBufferOut.reserve(lineBufferOut.size() + 2u * numLinesSwingCone);
lineValidityBufferOut.reserve(lineValidityBufferOut.size() + numLinesSwingCone);
// the orientation quat for a radial line in the cone can be represented in terms of sin and cos half angles
// these expressions can be efficiently calculated using tan quarter angles as follows:
// writing t = tan(x / 4)
// sin(x / 2) = 2 * t / (1 + t * t)
// cos(x / 2) = (1 - t * t) / (1 + t * t)
const float tanQuarterSwingZ = tanf(0.25f * swingLimitZ);
const float tanQuarterSwingY = tanf(0.25f * swingLimitY);
AZ::Vector3 previousRadialVector = AZ::Vector3::CreateZero();
for (AZ::u32 angularIndex = 0; angularIndex <= angularSubdivisions; angularIndex++)
{
const float angle = AZ::Constants::TwoPi / angularSubdivisions * angularIndex;
// the axis about which to rotate the x-axis to get the radial vector for this segment of the cone
const AZ::Vector3 rotationAxis(0, -tanQuarterSwingY * sinf(angle), tanQuarterSwingZ * cosf(angle));
const float normalizationFactor = rotationAxis.GetLengthSq();
const AZ::Quaternion radialVectorRotation = 1.0f / (1.0f + normalizationFactor) *
AZ::Quaternion::CreateFromVector3AndValue(2.0f * rotationAxis, 1.0f - normalizationFactor);
const AZ::Vector3 radialVector = (parentLocalRotation * radialVectorRotation).TransformVector(AZ::Vector3::CreateAxisX(scale));
if (angularIndex > 0)
{
for (AZ::u32 radialIndex = 1; radialIndex <= radialSubdivisions; radialIndex++)
{
float radiusFraction = 1.0f / radialSubdivisions * radialIndex;
lineBufferOut.push_back(radiusFraction * radialVector);
lineBufferOut.push_back(radiusFraction * previousRadialVector);
}
}
if (angularIndex < angularSubdivisions)
{
lineBufferOut.push_back(AZ::Vector3::CreateZero());
lineBufferOut.push_back(radialVector);
}
previousRadialVector = radialVector;
}
const bool swingValid = IsD6SwingValid(swingAngleY, swingAngleZ, swingLimitY, swingLimitZ);
lineValidityBufferOut.insert(lineValidityBufferOut.end(), numLinesSwingCone, swingValid);
}
void JointUtils::AppendD6TwistArcToLineBuffer(
const AZ::Quaternion& parentLocalRotation,
float twistAngle,
float twistLimitLower,
float twistLimitUpper,
float scale,
AZ::u32 angularSubdivisions,
AZ::u32 radialSubdivisions,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut)
{
const AZ::u32 numLinesTwistArc = angularSubdivisions * (1u + radialSubdivisions) + 1u;
lineBufferOut.reserve(lineBufferOut.size() + 2u * numLinesTwistArc);
AZ::Vector3 previousRadialVector = AZ::Vector3::CreateZero();
const float twistRange = twistLimitUpper - twistLimitLower;
for (AZ::u32 angularIndex = 0; angularIndex <= angularSubdivisions; angularIndex++)
{
const float angle = twistLimitLower + twistRange / angularSubdivisions * angularIndex;
const AZ::Vector3 radialVector = parentLocalRotation.TransformVector(scale * AZ::Vector3(0.0f, cosf(angle), sinf(angle)));
if (angularIndex > 0)
{
for (AZ::u32 radialIndex = 1; radialIndex <= radialSubdivisions; radialIndex++)
{
const float radiusFraction = 1.0f / radialSubdivisions * radialIndex;
lineBufferOut.push_back(radiusFraction * radialVector);
lineBufferOut.push_back(radiusFraction * previousRadialVector);
}
}
lineBufferOut.push_back(AZ::Vector3::CreateZero());
lineBufferOut.push_back(radialVector);
previousRadialVector = radialVector;
}
const bool twistValid = (twistAngle >= twistLimitLower && twistAngle <= twistLimitUpper);
lineValidityBufferOut.insert(lineValidityBufferOut.end(), numLinesTwistArc, twistValid);
}
void JointUtils::AppendD6CurrentTwistToLineBuffer(
const AZ::Quaternion& parentLocalRotation,
float twistAngle,
[[maybe_unused]] float twistLimitLower,
[[maybe_unused]] float twistLimitUpper,
float scale,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut
)
{
const AZ::Vector3 twistVector = parentLocalRotation.TransformVector(1.25f * scale * AZ::Vector3(0.0f, cosf(twistAngle), sinf(twistAngle)));
lineBufferOut.push_back(AZ::Vector3::CreateZero());
lineBufferOut.push_back(twistVector);
lineValidityBufferOut.push_back(true);
}
void JointUtils::GenerateJointLimitVisualizationData(
const Physics::JointLimitConfiguration& configuration,
const AZ::Quaternion& parentRotation,
const AZ::Quaternion& childRotation,
float scale,
AZ::u32 angularSubdivisions,
AZ::u32 radialSubdivisions,
[[maybe_unused]] AZStd::vector<AZ::Vector3>& vertexBufferOut,
[[maybe_unused]] AZStd::vector<AZ::u32>& indexBufferOut,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut)
{
if (const auto d6JointConfiguration = azrtti_cast<const D6JointLimitConfiguration*>(&configuration))
{
const AZ::u32 angularSubdivisionsClamped = AZ::GetClamp(angularSubdivisions, 4u, 32u);
const AZ::u32 radialSubdivisionsClamped = AZ::GetClamp(radialSubdivisions, 1u, 4u);
const D6JointState jointState = CalculateD6JointState(parentRotation, d6JointConfiguration->m_parentLocalRotation,
childRotation, d6JointConfiguration->m_childLocalRotation);
const float swingAngleY = jointState.m_swingAngleY;
const float swingAngleZ = jointState.m_swingAngleZ;
const float twistAngle = jointState.m_twistAngle;
const float swingLimitY = AZ::DegToRad(d6JointConfiguration->m_swingLimitY);
const float swingLimitZ = AZ::DegToRad(d6JointConfiguration->m_swingLimitZ);
const float twistLimitLower = AZ::DegToRad(d6JointConfiguration->m_twistLimitLower);
const float twistLimitUpper = AZ::DegToRad(d6JointConfiguration->m_twistLimitUpper);
AppendD6SwingConeToLineBuffer(d6JointConfiguration->m_parentLocalRotation, swingAngleY, swingAngleZ, swingLimitY,
swingLimitZ, scale, angularSubdivisionsClamped, radialSubdivisionsClamped, lineBufferOut, lineValidityBufferOut);
AppendD6TwistArcToLineBuffer(d6JointConfiguration->m_parentLocalRotation, twistAngle, twistLimitLower, twistLimitUpper,
scale, angularSubdivisionsClamped, radialSubdivisionsClamped, lineBufferOut, lineValidityBufferOut);
AppendD6CurrentTwistToLineBuffer(d6JointConfiguration->m_parentLocalRotation, twistAngle, twistLimitLower,
twistLimitUpper, scale, lineBufferOut, lineValidityBufferOut);
}
}
AZStd::unique_ptr<Physics::JointLimitConfiguration> JointUtils::ComputeInitialJointLimitConfiguration(
const AZ::TypeId& jointLimitTypeId,
const AZ::Quaternion& parentWorldRotation,
const AZ::Quaternion& childWorldRotation,
const AZ::Vector3& axis,
const AZStd::vector<AZ::Quaternion>& exampleLocalRotations)
{
AZ_UNUSED(exampleLocalRotations);
if (jointLimitTypeId == D6JointLimitConfiguration::RTTI_Type())
{
const AZ::Vector3& normalizedAxis = axis.IsZero()
? AZ::Vector3::CreateAxisX()
: axis.GetNormalized();
D6JointLimitConfiguration d6JointLimitConfig;
const AZ::Quaternion childLocalRotation = AZ::Quaternion::CreateShortestArc(AZ::Vector3::CreateAxisX(),
childWorldRotation.GetConjugate().TransformVector(normalizedAxis));
d6JointLimitConfig.m_childLocalRotation = childLocalRotation;
d6JointLimitConfig.m_parentLocalRotation = parentWorldRotation.GetConjugate() * childWorldRotation * childLocalRotation;
return AZStd::make_unique<D6JointLimitConfiguration>(d6JointLimitConfig);
}
AZ_Warning("PhysX Joint Utils", false, "Unsupported joint type in ComputeInitialJointLimitConfiguration");
return nullptr;
}
const char* D6JointLimitConfiguration::GetTypeName()
{
return "D6 Joint";
}
void D6JointLimitConfiguration::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<D6JointLimitConfiguration, Physics::JointLimitConfiguration>()
->Version(1)
->Field("SwingLimitY", &D6JointLimitConfiguration::m_swingLimitY)
->Field("SwingLimitZ", &D6JointLimitConfiguration::m_swingLimitZ)
->Field("TwistLowerLimit", &D6JointLimitConfiguration::m_twistLimitLower)
->Field("TwistUpperLimit", &D6JointLimitConfiguration::m_twistLimitUpper)
;
AZ::EditContext* editContext = serializeContext->GetEditContext();
if (editContext)
{
editContext->Class<D6JointLimitConfiguration>(
"PhysX D6 Joint Configuration", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->DataElement(AZ::Edit::UIHandlers::Default, &D6JointLimitConfiguration::m_swingLimitY, "Swing limit Y",
"Maximum angle from the Y axis of the joint frame")
->Attribute(AZ::Edit::Attributes::Suffix, " degrees")
->Attribute(AZ::Edit::Attributes::Min, JointConstants::MinSwingLimitDegrees)
->Attribute(AZ::Edit::Attributes::Max, 180.0f)
->DataElement(AZ::Edit::UIHandlers::Default, &D6JointLimitConfiguration::m_swingLimitZ, "Swing limit Z",
"Maximum angle from the Z axis of the joint frame")
->Attribute(AZ::Edit::Attributes::Suffix, " degrees")
->Attribute(AZ::Edit::Attributes::Min, JointConstants::MinSwingLimitDegrees)
->Attribute(AZ::Edit::Attributes::Max, 180.0f)
->DataElement(AZ::Edit::UIHandlers::Default, &D6JointLimitConfiguration::m_twistLimitLower, "Twist lower limit",
"Lower limit for rotation about the X axis of the joint frame")
->Attribute(AZ::Edit::Attributes::Suffix, " degrees")
->Attribute(AZ::Edit::Attributes::Min, -180.0f)
->Attribute(AZ::Edit::Attributes::Max, 180.0f)
->DataElement(AZ::Edit::UIHandlers::Default, &D6JointLimitConfiguration::m_twistLimitUpper, "Twist upper limit",
"Upper limit for rotation about the X axis of the joint frame")
->Attribute(AZ::Edit::Attributes::Suffix, " degrees")
->Attribute(AZ::Edit::Attributes::Min, -180.0f)
->Attribute(AZ::Edit::Attributes::Max, 180.0f)
;
}
}
}
} // namespace PhysX
-311
View File
@@ -1,311 +0,0 @@
/*
* 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 <AzFramework/Physics/Joint.h>
namespace AzPhysics
{
struct SimulatedBody;
}
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, AzPhysics::SimulatedBody* parentBody,
AzPhysics::SimulatedBody* childBody);
virtual ~Joint() = default;
AzPhysics::SimulatedBody* GetParentBody() const override;
AzPhysics::SimulatedBody* GetChildBody() const override;
void SetParentBody(AzPhysics::SimulatedBody* parentBody) override;
void SetChildBody(AzPhysics::SimulatedBody* 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<physx::PxJoint, AZStd::function<void(physx::PxJoint*)>>;
PxJointUniquePtr m_pxJoint;
AzPhysics::SimulatedBody* m_parentBody;
AzPhysics::SimulatedBody* 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, AzPhysics::SimulatedBody* parentBody,
AzPhysics::SimulatedBody* 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<AZ::Vector3>& vertexBufferOut,
AZStd::vector<AZ::u32>& indexBufferOut,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& 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, AzPhysics::SimulatedBody* parentBody,
AzPhysics::SimulatedBody* childBody)
: Joint(pxJoint, parentBody, childBody)
{
}
const AZ::Crc32 GetNativeType() const override;
void GenerateJointLimitVisualizationData(
float /*scale*/,
AZ::u32 /*angularSubdivisions*/,
AZ::u32 /*radialSubdivisions*/,
AZStd::vector<AZ::Vector3>& /*vertexBufferOut*/,
AZStd::vector<AZ::u32>& /*indexBufferOut*/,
AZStd::vector<AZ::Vector3>& /*lineBufferOut*/,
AZStd::vector<bool>& /*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, AzPhysics::SimulatedBody* parentBody,
AzPhysics::SimulatedBody* childBody)
: Joint(pxJoint, parentBody, childBody)
{
}
const AZ::Crc32 GetNativeType() const override;
void GenerateJointLimitVisualizationData(
float /*scale*/,
AZ::u32 /*angularSubdivisions*/,
AZ::u32 /*radialSubdivisions*/,
AZStd::vector<AZ::Vector3>& /*vertexBufferOut*/,
AZStd::vector<AZ::u32>& /*indexBufferOut*/,
AZStd::vector<AZ::Vector3>& /*lineBufferOut*/,
AZStd::vector<bool>& /*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, AzPhysics::SimulatedBody* parentBody,
AzPhysics::SimulatedBody* childBody)
: Joint(pxJoint, parentBody, childBody)
{
}
const AZ::Crc32 GetNativeType() const override;
void GenerateJointLimitVisualizationData(
float /*scale*/,
AZ::u32 /*angularSubdivisions*/,
AZ::u32 /*radialSubdivisions*/,
AZStd::vector<AZ::Vector3>& /*vertexBufferOut*/,
AZStd::vector<AZ::u32>& /*indexBufferOut*/,
AZStd::vector<AZ::Vector3>& /*lineBufferOut*/,
AZStd::vector<bool>& /*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<AZ::TypeId> GetSupportedJointTypes();
static AZStd::shared_ptr<Physics::JointLimitConfiguration> CreateJointLimitConfiguration(AZ::TypeId jointType);
static AZStd::shared_ptr<Physics::Joint> CreateJoint(const AZStd::shared_ptr<Physics::JointLimitConfiguration>& configuration,
AzPhysics::SimulatedBody* parentBody, AzPhysics::SimulatedBody* 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<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut);
static void AppendD6TwistArcToLineBuffer(
const AZ::Quaternion& parentLocalRotation,
float twistAngle,
float twistLimitLower,
float twistLimitUpper,
float scale,
AZ::u32 angularSubdivisions,
AZ::u32 radialSubdivisions,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut);
static void AppendD6CurrentTwistToLineBuffer(
const AZ::Quaternion& parentLocalRotation,
float twistAngle,
float twistLimitLower,
float twistLimitUpper,
float scale,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& 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<AZ::Vector3>& vertexBufferOut,
AZStd::vector<AZ::u32>& indexBufferOut,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut);
static AZStd::unique_ptr<Physics::JointLimitConfiguration> ComputeInitialJointLimitConfiguration(
const AZ::TypeId& jointLimitTypeId,
const AZ::Quaternion& parentWorldRotation,
const AZ::Quaternion& childWorldRotation,
const AZ::Vector3& axis,
const AZStd::vector<AZ::Quaternion>& exampleLocalRotations);
};
} // namespace PhysX
@@ -0,0 +1,155 @@
/*
* 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.
*
*/
#include <PhysX_precompiled.h>
#include <PhysX/Joint/Configuration/PhysXJointConfiguration.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzFramework/Physics/Common/PhysicsSimulatedBody.h>
#include <Joint/PhysXJointUtils.h>
namespace PhysX
{
JointGenericProperties::JointGenericProperties(GenericJointFlag flags, float forceMax, float torqueMax)
: m_flags(flags)
, m_forceMax(forceMax)
, m_torqueMax(torqueMax)
{
}
JointLimitProperties::JointLimitProperties(
bool isLimited, bool isSoftLimit,
float damping, float limitFirst, float limitSecond, float stiffness, float tolerance)
: m_isLimited(isLimited)
, m_isSoftLimit(isSoftLimit)
, m_damping(damping)
, m_limitFirst(limitFirst)
, m_limitSecond(limitSecond)
, m_stiffness(stiffness)
, m_tolerance(tolerance)
{
}
bool JointGenericProperties::IsFlagSet(GenericJointFlag flag) const
{
return static_cast<bool>(m_flags & flag);
}
void D6JointLimitConfiguration::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<D6JointLimitConfiguration, AzPhysics::JointConfiguration>()
->Version(1)
->Field("SwingLimitY", &D6JointLimitConfiguration::m_swingLimitY)
->Field("SwingLimitZ", &D6JointLimitConfiguration::m_swingLimitZ)
->Field("TwistLowerLimit", &D6JointLimitConfiguration::m_twistLimitLower)
->Field("TwistUpperLimit", &D6JointLimitConfiguration::m_twistLimitUpper)
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<D6JointLimitConfiguration>(
"PhysX D6 Joint Configuration", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
->DataElement(AZ::Edit::UIHandlers::Default, &D6JointLimitConfiguration::m_swingLimitY, "Swing limit Y",
"Maximum angle from the Y axis of the joint frame")
->Attribute(AZ::Edit::Attributes::Suffix, " degrees")
->Attribute(AZ::Edit::Attributes::Min, JointConstants::MinSwingLimitDegrees)
->Attribute(AZ::Edit::Attributes::Max, 180.0f)
->DataElement(AZ::Edit::UIHandlers::Default, &D6JointLimitConfiguration::m_swingLimitZ, "Swing limit Z",
"Maximum angle from the Z axis of the joint frame")
->Attribute(AZ::Edit::Attributes::Suffix, " degrees")
->Attribute(AZ::Edit::Attributes::Min, JointConstants::MinSwingLimitDegrees)
->Attribute(AZ::Edit::Attributes::Max, 180.0f)
->DataElement(AZ::Edit::UIHandlers::Default, &D6JointLimitConfiguration::m_twistLimitLower, "Twist lower limit",
"Lower limit for rotation about the X axis of the joint frame")
->Attribute(AZ::Edit::Attributes::Suffix, " degrees")
->Attribute(AZ::Edit::Attributes::Min, -180.0f)
->Attribute(AZ::Edit::Attributes::Max, 180.0f)
->DataElement(AZ::Edit::UIHandlers::Default, &D6JointLimitConfiguration::m_twistLimitUpper, "Twist upper limit",
"Upper limit for rotation about the X axis of the joint frame")
->Attribute(AZ::Edit::Attributes::Suffix, " degrees")
->Attribute(AZ::Edit::Attributes::Min, -180.0f)
->Attribute(AZ::Edit::Attributes::Max, 180.0f)
;
}
}
}
void JointGenericProperties::Reflect(AZ::ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<JointGenericProperties>()
->Version(1)
->Field("Maximum Force", &JointGenericProperties::m_forceMax)
->Field("Maximum Torque", &JointGenericProperties::m_torqueMax)
->Field("Flags", &JointGenericProperties::m_flags)
;
}
}
void JointLimitProperties::Reflect(AZ::ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<JointLimitProperties>()
->Version(1)
->Field("First Limit", &JointLimitProperties::m_limitFirst)
->Field("Second Limit", &JointLimitProperties::m_limitSecond)
->Field("Tolerance", &JointLimitProperties::m_tolerance)
->Field("Is Limited", &JointLimitProperties::m_isLimited)
->Field("Is Soft Limit", &JointLimitProperties::m_isSoftLimit)
->Field("Damping", &JointLimitProperties::m_damping)
->Field("Spring", &JointLimitProperties::m_stiffness)
;
}
}
void FixedJointConfiguration::Reflect(AZ::ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<FixedJointConfiguration, AzPhysics::JointConfiguration>()
->Version(1)
->Field("Generic Properties", &FixedJointConfiguration::m_genericProperties)
;
}
}
void BallJointConfiguration::Reflect(AZ::ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<BallJointConfiguration, AzPhysics::JointConfiguration>()
->Version(1)
->Field("Generic Properties", &BallJointConfiguration::m_genericProperties)
->Field("Limit Properties", &BallJointConfiguration::m_limitProperties)
;
}
}
void HingeJointConfiguration::Reflect(AZ::ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<HingeJointConfiguration, AzPhysics::JointConfiguration>()
->Version(1)
->Field("Generic Properties", &HingeJointConfiguration::m_genericProperties)
->Field("Limit Properties", &HingeJointConfiguration::m_limitProperties)
;
}
}
} // namespace PhysX
+200
View File
@@ -0,0 +1,200 @@
/*
* 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.
*
*/
#include <PhysX_precompiled.h>
#include <Joint/PhysXJoint.h>
#include <AzCore/Serialization/EditContext.h>
#include <Include/PhysX/NativeTypeIdentifiers.h>
#include <AzCore/Math/MathUtils.h>
#include <AzFramework/Physics/Common/PhysicsSimulatedBody.h>
#include <Source/Joint/PhysXJointUtils.h>
namespace PhysX
{
AzPhysics::SimulatedBodyHandle PhysXJoint::GetParentBodyHandle() const
{
return m_parentBodyHandle;
}
AzPhysics::SimulatedBodyHandle PhysXJoint::GetChildBodyHandle() const
{
return m_childBodyHandle;
}
PhysXJoint::PhysXJoint(
AzPhysics::SceneHandle sceneHandle,
AzPhysics::SimulatedBodyHandle parentBodyHandle,
AzPhysics::SimulatedBodyHandle childBodyHandle)
: m_sceneHandle(sceneHandle)
, m_parentBodyHandle(parentBodyHandle)
, m_childBodyHandle(childBodyHandle)
{
}
bool PhysXJoint::SetPxActors()
{
physx::PxRigidActor* parentActor = Utils::GetPxRigidActor(m_sceneHandle, m_parentBodyHandle);
physx::PxRigidActor* childActor = Utils::GetPxRigidActor(m_sceneHandle, m_childBodyHandle);
if (!parentActor && !childActor)
{
AZ_Error("PhysX Joint", false, "Invalid PhysX actors in joint - at least one must be a PxRigidActor.");
return false;
}
m_pxJoint->setActors(parentActor, childActor);
return true;
}
void PhysXJoint::SetParentBody(AzPhysics::SimulatedBodyHandle parentBodyHandle)
{
auto* parentBody = Utils::GetSimulatedBodyFromHandle(m_sceneHandle, parentBodyHandle);
auto* childBody = Utils::GetSimulatedBodyFromHandle(m_sceneHandle, m_childBodyHandle);
if (Utils::IsAtLeastOneDynamic(parentBody, childBody))
{
m_parentBodyHandle = parentBodyHandle;
SetPxActors();
}
else
{
AZ_Warning("PhysX Joint", false, "Call to SetParentBody would result in invalid joint - at least one "
"body in a joint must be dynamic.");
}
}
void PhysXJoint::SetChildBody(AzPhysics::SimulatedBodyHandle childBodyHandle)
{
auto* parentBody = Utils::GetSimulatedBodyFromHandle(m_sceneHandle, m_parentBodyHandle);
auto* childBody = Utils::GetSimulatedBodyFromHandle(m_sceneHandle, childBodyHandle);
if (Utils::IsAtLeastOneDynamic(parentBody, childBody))
{
m_childBodyHandle = childBodyHandle;
SetPxActors();
}
else
{
AZ_Warning("PhysX Joint", false, "Call to SetChildBody would result in invalid joint - at least one "
"body in a joint must be dynamic.");
}
}
void* PhysXJoint::GetNativePointer() const
{
return m_pxJoint.get();
}
PhysXD6Joint::PhysXD6Joint(const D6JointLimitConfiguration& configuration,
AzPhysics::SceneHandle sceneHandle,
AzPhysics::SimulatedBodyHandle parentBodyHandle,
AzPhysics::SimulatedBodyHandle childBodyHandle)
: PhysXJoint(sceneHandle, parentBodyHandle, childBodyHandle)
{
m_pxJoint = Utils::PxJointFactories::CreatePxD6Joint(configuration, sceneHandle, parentBodyHandle, childBodyHandle);
}
PhysXFixedJoint::PhysXFixedJoint(const FixedJointConfiguration& configuration,
AzPhysics::SceneHandle sceneHandle,
AzPhysics::SimulatedBodyHandle parentBodyHandle,
AzPhysics::SimulatedBodyHandle childBodyHandle)
: PhysXJoint(sceneHandle, parentBodyHandle, childBodyHandle)
{
m_pxJoint = Utils::PxJointFactories::CreatePxFixedJoint(configuration, sceneHandle, parentBodyHandle, childBodyHandle);
}
PhysXBallJoint::PhysXBallJoint(const BallJointConfiguration& configuration,
AzPhysics::SceneHandle sceneHandle,
AzPhysics::SimulatedBodyHandle parentBodyHandle,
AzPhysics::SimulatedBodyHandle childBodyHandle)
: PhysXJoint(sceneHandle, parentBodyHandle, childBodyHandle)
{
m_pxJoint = Utils::PxJointFactories::CreatePxBallJoint(configuration, sceneHandle, parentBodyHandle, childBodyHandle);
}
PhysXHingeJoint::PhysXHingeJoint(const HingeJointConfiguration& configuration,
AzPhysics::SceneHandle sceneHandle,
AzPhysics::SimulatedBodyHandle parentBodyHandle,
AzPhysics::SimulatedBodyHandle childBodyHandle)
: PhysXJoint(sceneHandle, parentBodyHandle, childBodyHandle)
{
m_pxJoint = Utils::PxJointFactories::CreatePxHingeJoint(configuration, sceneHandle, parentBodyHandle, childBodyHandle);
}
AZ::Crc32 PhysXD6Joint::GetNativeType() const
{
return NativeTypeIdentifiers::D6Joint;
}
AZ::Crc32 PhysXFixedJoint::GetNativeType() const
{
return NativeTypeIdentifiers::FixedJoint;
}
AZ::Crc32 PhysXBallJoint::GetNativeType() const
{
return NativeTypeIdentifiers::BallJoint;
}
AZ::Crc32 PhysXHingeJoint::GetNativeType() const
{
return NativeTypeIdentifiers::HingeJoint;
}
void PhysXD6Joint::GenerateJointLimitVisualizationData(
float scale,
AZ::u32 angularSubdivisions,
AZ::u32 radialSubdivisions,
[[maybe_unused]] AZStd::vector<AZ::Vector3>& vertexBufferOut,
[[maybe_unused]] AZStd::vector<AZ::u32>& indexBufferOut,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut)
{
auto* parentBody = Utils::GetSimulatedBodyFromHandle(m_sceneHandle, m_parentBodyHandle);
auto* childBody = Utils::GetSimulatedBodyFromHandle(m_sceneHandle, m_childBodyHandle);
const AZ::u32 angularSubdivisionsClamped = AZ::GetClamp(angularSubdivisions, 4u, 32u);
const AZ::u32 radialSubdivisionsClamped = AZ::GetClamp(radialSubdivisions, 1u, 4u);
const physx::PxD6Joint* joint = static_cast<physx::PxD6Joint*>(m_pxJoint.get());
const AZ::Quaternion parentLocalRotation = PxMathConvert(joint->getLocalPose(physx::PxJointActorIndex::eACTOR0).q);
const AZ::Quaternion parentWorldRotation = parentBody ? parentBody->GetOrientation() : AZ::Quaternion::CreateIdentity();
const AZ::Quaternion childLocalRotation = PxMathConvert(joint->getLocalPose(physx::PxJointActorIndex::eACTOR1).q);
const AZ::Quaternion childWorldRotation = childBody ? childBody->GetOrientation() : AZ::Quaternion::CreateIdentity();
const float swingAngleY = joint->getSwingYAngle();
const float swingAngleZ = joint->getSwingZAngle();
const float swingLimitY = joint->getSwingLimit().yAngle;
const float swingLimitZ = joint->getSwingLimit().zAngle;
const float twistAngle = joint->getTwist();
const float twistLimitLower = joint->getTwistLimit().lower;
const float twistLimitUpper = joint->getTwistLimit().upper;
Utils::Joints::AppendD6SwingConeToLineBuffer(
parentLocalRotation, swingAngleY, swingAngleZ, swingLimitY, swingLimitZ,
scale, angularSubdivisionsClamped, radialSubdivisionsClamped, lineBufferOut, lineValidityBufferOut);
Utils::Joints::AppendD6TwistArcToLineBuffer(
parentLocalRotation, twistAngle, twistLimitLower, twistLimitUpper,
scale, angularSubdivisionsClamped, radialSubdivisionsClamped, lineBufferOut, lineValidityBufferOut);
Utils::Joints::AppendD6CurrentTwistToLineBuffer(
parentLocalRotation, twistAngle, twistLimitLower, twistLimitUpper,
scale, lineBufferOut, lineValidityBufferOut);
// draw the X-axis of the child joint frame
// make the axis slightly longer than the radius of the twist arc so that it is easy to see
float axisLength = 1.25f * scale;
AZ::Vector3 childAxis = (parentWorldRotation.GetConjugate() * childWorldRotation * childLocalRotation).TransformVector(
AZ::Vector3::CreateAxisX(axisLength));
lineBufferOut.push_back(AZ::Vector3::CreateZero());
lineBufferOut.push_back(childAxis);
}
} // namespace PhysX
+126
View File
@@ -0,0 +1,126 @@
/*
* 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 <AzFramework/Physics/Common/PhysicsJoint.h>
#include <PhysX/Joint/Configuration/PhysXJointConfiguration.h>
#include <Joint/PhysXJointUtils.h>
namespace PhysX
{
class PhysXJoint
: public AzPhysics::Joint
{
public:
AZ_CLASS_ALLOCATOR(PhysXJoint, AZ::SystemAllocator, 0);
AZ_RTTI(PhysXJoint, "{DBE1D185-E318-407D-A5A1-AC1DE7F4A62D}", AzPhysics::Joint);
PhysXJoint(
AzPhysics::SceneHandle sceneHandle,
AzPhysics::SimulatedBodyHandle parentBodyHandle,
AzPhysics::SimulatedBodyHandle childBodyHandle);
virtual ~PhysXJoint() = default;
AzPhysics::SimulatedBodyHandle GetParentBodyHandle() const override;
AzPhysics::SimulatedBodyHandle GetChildBodyHandle() const override;
void SetParentBody(AzPhysics::SimulatedBodyHandle parentBody) override;
void SetChildBody(AzPhysics::SimulatedBodyHandle childBody) override;
void* GetNativePointer() const override;
protected:
bool SetPxActors();
Utils::PxJointUniquePtr m_pxJoint;
AzPhysics::SceneHandle m_sceneHandle;
AzPhysics::SimulatedBodyHandle m_parentBodyHandle;
AzPhysics::SimulatedBodyHandle m_childBodyHandle;
AZStd::string m_name;
};
class PhysXD6Joint
: public PhysXJoint
{
public:
AZ_CLASS_ALLOCATOR(PhysXD6Joint, AZ::SystemAllocator, 0);
AZ_RTTI(PhysXD6Joint, "{144B2FAF-A3EE-4FE1-9328-2C44FE1E3676}", PhysX::PhysXJoint);
PhysXD6Joint(const D6JointLimitConfiguration& configuration,
AzPhysics::SceneHandle sceneHandle,
AzPhysics::SimulatedBodyHandle parentBodyHandle,
AzPhysics::SimulatedBodyHandle childBodyHandle);
virtual ~PhysXD6Joint() = default;
AZ::Crc32 GetNativeType() const override;
void GenerateJointLimitVisualizationData(
float scale,
AZ::u32 angularSubdivisions,
AZ::u32 radialSubdivisions,
AZStd::vector<AZ::Vector3>& vertexBufferOut,
AZStd::vector<AZ::u32>& indexBufferOut,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut) override;
};
//! A fixed joint locks 2 bodies relative to one another on all axes of freedom.
class PhysXFixedJoint : public PhysXJoint
{
public:
AZ_CLASS_ALLOCATOR(PhysXFixedJoint, AZ::SystemAllocator, 0);
AZ_RTTI(PhysXFixedJoint, "{B821D6D8-7B41-479D-9325-F9BC9754C5F8}", PhysX::PhysXJoint);
PhysXFixedJoint(const FixedJointConfiguration& configuration,
AzPhysics::SceneHandle sceneHandle,
AzPhysics::SimulatedBodyHandle parentBodyHandle,
AzPhysics::SimulatedBodyHandle childBodyHandle);
virtual ~PhysXFixedJoint() = default;
AZ::Crc32 GetNativeType() const override;
};
//! A ball joint locks 2 bodies relative to one another except about the y and z axes of the joint between them.
class PhysXBallJoint : public PhysXJoint
{
public:
AZ_CLASS_ALLOCATOR(PhysXBallJoint, AZ::SystemAllocator, 0);
AZ_RTTI(PhysXBallJoint, "{9494CE43-3AE2-40AB-ADF7-FDC5F8B0F15A}", PhysX::PhysXJoint);
PhysXBallJoint(const BallJointConfiguration& configuration,
AzPhysics::SceneHandle sceneHandle,
AzPhysics::SimulatedBodyHandle parentBodyHandle,
AzPhysics::SimulatedBodyHandle childBodyHandle);
virtual ~PhysXBallJoint() = default;
AZ::Crc32 GetNativeType() const override;
};
//! A hinge joint locks 2 bodies relative to one another except about the x-axis of the joint between them.
class PhysXHingeJoint : public PhysXJoint
{
public:
AZ_CLASS_ALLOCATOR(PhysXHingeJoint, AZ::SystemAllocator, 0);
AZ_RTTI(PhysXHingeJoint, "{9C5B955C-6C80-45FA-855D-DDA449C85313}", PhysX::PhysXJoint);
PhysXHingeJoint(const HingeJointConfiguration& configuration,
AzPhysics::SceneHandle sceneHandle,
AzPhysics::SimulatedBodyHandle parentBodyHandle,
AzPhysics::SimulatedBodyHandle childBodyHandle);
virtual ~PhysXHingeJoint() = default;
AZ::Crc32 GetNativeType() const override;
};
} // namespace PhysX
@@ -0,0 +1,470 @@
/*
* 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.
*
*/
#include <PhysX_precompiled.h>
#include <AzFramework/Physics/PhysicsScene.h>
#include <AzFramework/Physics/PhysicsSystem.h>
#include <AzFramework/Physics/Common/PhysicsSimulatedBody.h>
#include <AzCore/EBus/EBus.h>
#include <PhysX/Joint/Configuration/PhysXJointConfiguration.h>
#include <PhysX/PhysXLocks.h>
#include <Source/Joint/PhysXJointUtils.h>
#include <Include/PhysX/NativeTypeIdentifiers.h>
namespace PhysX {
namespace Utils
{
struct PxJointActorData
{
static PxJointActorData InvalidPxJointActorData;
physx::PxRigidActor* parentActor = nullptr;
physx::PxRigidActor* childActor = nullptr;
};
PxJointActorData PxJointActorData::InvalidPxJointActorData;
PxJointActorData GetJointPxActors(
AzPhysics::SceneHandle sceneHandle,
AzPhysics::SimulatedBodyHandle parentBodyHandle,
AzPhysics::SimulatedBodyHandle childBodyHandle)
{
auto* parentBody = GetSimulatedBodyFromHandle(sceneHandle, parentBodyHandle);
auto* childBody = GetSimulatedBodyFromHandle(sceneHandle, childBodyHandle);
if (!IsAtLeastOneDynamic(parentBody, childBody))
{
AZ_Warning("PhysX Joint", false, "CreateJoint failed - at least one body must be dynamic.");
return PxJointActorData::InvalidPxJointActorData;
}
physx::PxRigidActor* parentActor = GetPxRigidActor(sceneHandle, parentBodyHandle);
physx::PxRigidActor* childActor = GetPxRigidActor(sceneHandle, childBodyHandle);
if (!parentActor && !childActor)
{
AZ_Warning("PhysX Joint", false, "CreateJoint failed - at least one body must be a PxRigidActor.");
return PxJointActorData::InvalidPxJointActorData;
}
return PxJointActorData{
parentActor,
childActor
};
}
bool IsAtLeastOneDynamic(AzPhysics::SimulatedBody* body0,
AzPhysics::SimulatedBody* body1)
{
for (const AzPhysics::SimulatedBody* body : { body0, body1 })
{
if (body)
{
if (body->GetNativeType() == NativeTypeIdentifiers::RigidBody ||
body->GetNativeType() == NativeTypeIdentifiers::ArticulationLink)
{
return true;
}
}
}
return false;
}
physx::PxRigidActor* GetPxRigidActor(AzPhysics::SceneHandle sceneHandle, AzPhysics::SimulatedBodyHandle worldBodyHandle)
{
auto* worldBody = GetSimulatedBodyFromHandle(sceneHandle, worldBodyHandle);
if (worldBody != nullptr
&& static_cast<physx::PxBase*>(worldBody->GetNativePointer())->is<physx::PxRigidActor>())
{
return static_cast<physx::PxRigidActor*>(worldBody->GetNativePointer());
}
return nullptr;
}
void ReleasePxJoint(physx::PxJoint* joint)
{
PHYSX_SCENE_WRITE_LOCK(joint->getScene());
joint->userData = nullptr;
joint->release();
}
AzPhysics::SimulatedBody* GetSimulatedBodyFromHandle(AzPhysics::SceneHandle sceneHandle,
AzPhysics::SimulatedBodyHandle bodyHandle)
{
if (auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get())
{
return sceneInterface->GetSimulatedBodyFromHandle(sceneHandle, bodyHandle);
}
return nullptr;
}
void InitializeGenericProperties(const JointGenericProperties& properties, physx::PxJoint* nativeJoint)
{
if (!nativeJoint)
{
return;
}
PHYSX_SCENE_WRITE_LOCK(nativeJoint->getScene());
nativeJoint->setConstraintFlag(
physx::PxConstraintFlag::eCOLLISION_ENABLED,
properties.IsFlagSet(JointGenericProperties::GenericJointFlag::SelfCollide));
if (properties.IsFlagSet(JointGenericProperties::GenericJointFlag::Breakable))
{
nativeJoint->setBreakForce(properties.m_forceMax, properties.m_torqueMax);
}
}
void InitializeSphericalLimitProperties(const JointLimitProperties& properties, physx::PxSphericalJoint* nativeJoint)
{
if (!nativeJoint)
{
return;
}
if (!properties.m_isLimited)
{
nativeJoint->setSphericalJointFlag(physx::PxSphericalJointFlag::eLIMIT_ENABLED, false);
return;
}
// Hard limit uses a tolerance value (distance to limit at which limit becomes active).
// Soft limit allows angle to exceed limit but springs back with configurable spring stiffness and damping.
physx::PxJointLimitCone swingLimit(
AZ::DegToRad(properties.m_limitFirst),
AZ::DegToRad(properties.m_limitSecond),
properties.m_tolerance);
if (properties.m_isSoftLimit)
{
swingLimit.stiffness = properties.m_stiffness;
swingLimit.damping = properties.m_damping;
}
nativeJoint->setLimitCone(swingLimit);
nativeJoint->setSphericalJointFlag(physx::PxSphericalJointFlag::eLIMIT_ENABLED, true);
}
void InitializeRevoluteLimitProperties(const JointLimitProperties& properties, physx::PxRevoluteJoint* nativeJoint)
{
if (!nativeJoint)
{
return;
}
if (!properties.m_isLimited)
{
nativeJoint->setRevoluteJointFlag(physx::PxRevoluteJointFlag::eLIMIT_ENABLED, false);
return;
}
physx::PxJointAngularLimitPair limitPair(
AZ::DegToRad(properties.m_limitSecond),
AZ::DegToRad(properties.m_limitFirst),
properties.m_tolerance);
if (properties.m_isSoftLimit)
{
limitPair.stiffness = properties.m_stiffness;
limitPair.damping = properties.m_damping;
}
nativeJoint->setLimit(limitPair);
nativeJoint->setRevoluteJointFlag(physx::PxRevoluteJointFlag::eLIMIT_ENABLED, true);
}
namespace PxJointFactories
{
PxJointUniquePtr CreatePxD6Joint(
const PhysX::D6JointLimitConfiguration& configuration,
AzPhysics::SceneHandle sceneHandle,
AzPhysics::SimulatedBodyHandle parentBodyHandle,
AzPhysics::SimulatedBodyHandle childBodyHandle)
{
PxJointActorData actorData = GetJointPxActors(sceneHandle, parentBodyHandle, childBodyHandle);
if (!actorData.parentActor || !actorData.childActor)
{
return nullptr;
}
const physx::PxTransform parentWorldTransform =
actorData.parentActor ? actorData.parentActor->getGlobalPose() : physx::PxTransform(physx::PxIdentity);
const physx::PxTransform childWorldTransform =
actorData.childActor ? actorData.childActor->getGlobalPose() : physx::PxTransform(physx::PxIdentity);
const physx::PxVec3 childOffset = childWorldTransform.p - parentWorldTransform.p;
physx::PxTransform parentLocalTransform(PxMathConvert(configuration.m_parentLocalRotation).getNormalized());
const physx::PxTransform childLocalTransform(PxMathConvert(configuration.m_childLocalRotation).getNormalized());
parentLocalTransform.p = parentWorldTransform.q.rotateInv(childOffset);
physx::PxD6Joint* joint = PxD6JointCreate(PxGetPhysics(),
actorData.parentActor, parentLocalTransform, actorData.childActor, childLocalTransform);
joint->setMotion(physx::PxD6Axis::eTWIST, physx::PxD6Motion::eLIMITED);
joint->setMotion(physx::PxD6Axis::eSWING1, physx::PxD6Motion::eLIMITED);
joint->setMotion(physx::PxD6Axis::eSWING2, physx::PxD6Motion::eLIMITED);
AZ_Warning("PhysX Joint",
configuration.m_swingLimitY >= JointConstants::MinSwingLimitDegrees && configuration.m_swingLimitZ >= JointConstants::MinSwingLimitDegrees,
"Very small swing limit requested for joint between \"%s\" and \"%s\", increasing to %f degrees to improve stability",
actorData.parentActor ? actorData.parentActor->getName() : "world",
actorData.childActor ? actorData.childActor->getName() : "world",
JointConstants::MinSwingLimitDegrees);
const float swingLimitY = AZ::DegToRad(AZ::GetMax(JointConstants::MinSwingLimitDegrees, configuration.m_swingLimitY));
const float swingLimitZ = AZ::DegToRad(AZ::GetMax(JointConstants::MinSwingLimitDegrees, configuration.m_swingLimitZ));
physx::PxJointLimitCone limitCone(swingLimitY, swingLimitZ);
joint->setSwingLimit(limitCone);
const float twistLower = AZ::DegToRad(AZStd::GetMin(configuration.m_twistLimitLower, configuration.m_twistLimitUpper));
const float twistUpper = AZ::DegToRad(AZStd::GetMax(configuration.m_twistLimitLower, configuration.m_twistLimitUpper));
physx::PxJointAngularLimitPair twistLimitPair(twistLower, twistUpper);
joint->setTwistLimit(twistLimitPair);
return Utils::PxJointUniquePtr(joint, ReleasePxJoint);
}
PxJointUniquePtr CreatePxFixedJoint(
const PhysX::FixedJointConfiguration& configuration,
AzPhysics::SceneHandle sceneHandle,
AzPhysics::SimulatedBodyHandle parentBodyHandle,
AzPhysics::SimulatedBodyHandle childBodyHandle)
{
PxJointActorData actorData = GetJointPxActors(sceneHandle, parentBodyHandle, childBodyHandle);
if (!actorData.parentActor || !actorData.childActor)
{
return nullptr;
}
physx::PxFixedJoint* joint;
const AZ::Transform parentLocalTM = AZ::Transform::CreateFromQuaternionAndTranslation(
configuration.m_parentLocalRotation, configuration.m_parentLocalPosition);
const AZ::Transform childLocalTM = AZ::Transform::CreateFromQuaternionAndTranslation(
configuration.m_childLocalRotation, configuration.m_childLocalPosition);
{
PHYSX_SCENE_READ_LOCK(actorData.childActor->getScene());
joint = physx::PxFixedJointCreate(PxGetPhysics(),
actorData.parentActor, PxMathConvert(parentLocalTM),
actorData.childActor, PxMathConvert(childLocalTM));
}
InitializeGenericProperties(
configuration.m_genericProperties,
static_cast<physx::PxJoint*>(joint));
return Utils::PxJointUniquePtr(joint, ReleasePxJoint);
}
PxJointUniquePtr CreatePxBallJoint(
const PhysX::BallJointConfiguration& configuration,
AzPhysics::SceneHandle sceneHandle,
AzPhysics::SimulatedBodyHandle parentBodyHandle,
AzPhysics::SimulatedBodyHandle childBodyHandle)
{
PxJointActorData actorData = GetJointPxActors(sceneHandle, parentBodyHandle, childBodyHandle);
if (!actorData.parentActor || !actorData.childActor)
{
return nullptr;
}
physx::PxSphericalJoint* joint;
const AZ::Transform parentLocalTM = AZ::Transform::CreateFromQuaternionAndTranslation(
configuration.m_parentLocalRotation, configuration.m_parentLocalPosition);
const AZ::Transform childLocalTM = AZ::Transform::CreateFromQuaternionAndTranslation(
configuration.m_childLocalRotation, configuration.m_childLocalPosition);
{
PHYSX_SCENE_READ_LOCK(actorData.childActor->getScene());
joint = physx::PxSphericalJointCreate(PxGetPhysics(),
actorData.parentActor, PxMathConvert(parentLocalTM),
actorData.childActor, PxMathConvert(childLocalTM));
}
InitializeSphericalLimitProperties(configuration.m_limitProperties, joint);
InitializeGenericProperties(
configuration.m_genericProperties,
static_cast<physx::PxJoint*>(joint));
return Utils::PxJointUniquePtr(joint, ReleasePxJoint);
}
PxJointUniquePtr CreatePxHingeJoint(
const PhysX::HingeJointConfiguration& configuration,
AzPhysics::SceneHandle sceneHandle,
AzPhysics::SimulatedBodyHandle parentBodyHandle,
AzPhysics::SimulatedBodyHandle childBodyHandle)
{
PxJointActorData actorData = GetJointPxActors(sceneHandle, parentBodyHandle, childBodyHandle);
if (!actorData.parentActor || !actorData.childActor)
{
return nullptr;
}
physx::PxRevoluteJoint* joint;
const AZ::Transform parentLocalTM = AZ::Transform::CreateFromQuaternionAndTranslation(
configuration.m_parentLocalRotation, configuration.m_parentLocalPosition);
const AZ::Transform childLocalTM = AZ::Transform::CreateFromQuaternionAndTranslation(
configuration.m_childLocalRotation, configuration.m_childLocalPosition);
{
PHYSX_SCENE_READ_LOCK(actorData.childActor->getScene());
joint = physx::PxRevoluteJointCreate(PxGetPhysics(),
actorData.parentActor, PxMathConvert(parentLocalTM),
actorData.childActor, PxMathConvert(childLocalTM));
}
InitializeRevoluteLimitProperties(configuration.m_limitProperties, joint);
InitializeGenericProperties(
configuration.m_genericProperties,
static_cast<physx::PxJoint*>(joint));
return Utils::PxJointUniquePtr(joint, ReleasePxJoint);
}
} // namespace PxJointFactories
namespace Joints
{
bool IsD6SwingValid(float swingAngleY, float swingAngleZ, float swingLimitY, float swingLimitZ)
{
const float epsilon = AZ::Constants::FloatEpsilon;
const float yFactor = AZStd::tan(0.25f * swingAngleY) / AZStd::GetMax(epsilon, AZStd::tan(0.25f * swingLimitY));
const float zFactor = AZStd::tan(0.25f * swingAngleZ) / AZStd::GetMax(epsilon, AZStd::tan(0.25f * swingLimitZ));
return (yFactor * yFactor + zFactor * zFactor <= 1.0f + epsilon);
}
void AppendD6SwingConeToLineBuffer(
const AZ::Quaternion& parentLocalRotation,
float swingAngleY,
float swingAngleZ,
float swingLimitY,
float swingLimitZ,
float scale,
AZ::u32 angularSubdivisions,
AZ::u32 radialSubdivisions,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut)
{
const AZ::u32 numLinesSwingCone = angularSubdivisions * (1u + radialSubdivisions);
lineBufferOut.reserve(lineBufferOut.size() + 2u * numLinesSwingCone);
lineValidityBufferOut.reserve(lineValidityBufferOut.size() + numLinesSwingCone);
// the orientation quat for a radial line in the cone can be represented in terms of sin and cos half angles
// these expressions can be efficiently calculated using tan quarter angles as follows:
// writing t = tan(x / 4)
// sin(x / 2) = 2 * t / (1 + t * t)
// cos(x / 2) = (1 - t * t) / (1 + t * t)
const float tanQuarterSwingZ = AZStd::tan(0.25f * swingLimitZ);
const float tanQuarterSwingY = AZStd::tan(0.25f * swingLimitY);
AZ::Vector3 previousRadialVector = AZ::Vector3::CreateZero();
for (AZ::u32 angularIndex = 0; angularIndex <= angularSubdivisions; angularIndex++)
{
const float angle = AZ::Constants::TwoPi / angularSubdivisions * angularIndex;
// the axis about which to rotate the x-axis to get the radial vector for this segment of the cone
const AZ::Vector3 rotationAxis(0, -tanQuarterSwingY * sinf(angle), tanQuarterSwingZ * cosf(angle));
const float normalizationFactor = rotationAxis.GetLengthSq();
const AZ::Quaternion radialVectorRotation = 1.0f / (1.0f + normalizationFactor) *
AZ::Quaternion::CreateFromVector3AndValue(2.0f * rotationAxis, 1.0f - normalizationFactor);
const AZ::Vector3 radialVector =
(parentLocalRotation * radialVectorRotation).TransformVector(AZ::Vector3::CreateAxisX(scale));
if (angularIndex > 0)
{
for (AZ::u32 radialIndex = 1; radialIndex <= radialSubdivisions; radialIndex++)
{
float radiusFraction = 1.0f / radialSubdivisions * radialIndex;
lineBufferOut.push_back(radiusFraction * radialVector);
lineBufferOut.push_back(radiusFraction * previousRadialVector);
}
}
if (angularIndex < angularSubdivisions)
{
lineBufferOut.push_back(AZ::Vector3::CreateZero());
lineBufferOut.push_back(radialVector);
}
previousRadialVector = radialVector;
}
const bool swingValid = IsD6SwingValid(swingAngleY, swingAngleZ, swingLimitY, swingLimitZ);
lineValidityBufferOut.insert(lineValidityBufferOut.end(), numLinesSwingCone, swingValid);
}
void AppendD6TwistArcToLineBuffer(
const AZ::Quaternion& parentLocalRotation,
float twistAngle,
float twistLimitLower,
float twistLimitUpper,
float scale,
AZ::u32 angularSubdivisions,
AZ::u32 radialSubdivisions,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut)
{
const AZ::u32 numLinesTwistArc = angularSubdivisions * (1u + radialSubdivisions) + 1u;
lineBufferOut.reserve(lineBufferOut.size() + 2u * numLinesTwistArc);
AZ::Vector3 previousRadialVector = AZ::Vector3::CreateZero();
const float twistRange = twistLimitUpper - twistLimitLower;
for (AZ::u32 angularIndex = 0; angularIndex <= angularSubdivisions; angularIndex++)
{
const float angle = twistLimitLower + twistRange / angularSubdivisions * angularIndex;
const AZ::Vector3 radialVector =
parentLocalRotation.TransformVector(scale * AZ::Vector3(0.0f, cosf(angle), sinf(angle)));
if (angularIndex > 0)
{
for (AZ::u32 radialIndex = 1; radialIndex <= radialSubdivisions; radialIndex++)
{
const float radiusFraction = 1.0f / radialSubdivisions * radialIndex;
lineBufferOut.push_back(radiusFraction * radialVector);
lineBufferOut.push_back(radiusFraction * previousRadialVector);
}
}
lineBufferOut.push_back(AZ::Vector3::CreateZero());
lineBufferOut.push_back(radialVector);
previousRadialVector = radialVector;
}
const bool twistValid = (twistAngle >= twistLimitLower && twistAngle <= twistLimitUpper);
lineValidityBufferOut.insert(lineValidityBufferOut.end(), numLinesTwistArc, twistValid);
}
void AppendD6CurrentTwistToLineBuffer(
const AZ::Quaternion& parentLocalRotation,
float twistAngle,
[[maybe_unused]] float twistLimitLower,
[[maybe_unused]] float twistLimitUpper,
float scale,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut)
{
const AZ::Vector3 twistVector =
parentLocalRotation.TransformVector(1.25f * scale * AZ::Vector3(0.0f, cosf(twistAngle), sinf(twistAngle)));
lineBufferOut.push_back(AZ::Vector3::CreateZero());
lineBufferOut.push_back(twistVector);
lineValidityBufferOut.push_back(true);
}
} // namespace Joints
} // namespace Utils
} // namespace PhysX
@@ -0,0 +1,101 @@
/*
* 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 <AzCore/Math/Quaternion.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/Math/Vector3.h>
#include <PxPhysicsAPI.h>
namespace PhysX
{
namespace JointConstants
{
// Setting swing limits to very small values can cause extreme stability problems, so clamp above a small
// threshold.
static const float MinSwingLimitDegrees = 1.0f;
} // namespace JointConstants
namespace Utils
{
using PxJointUniquePtr = AZStd::unique_ptr<physx::PxJoint, AZStd::function<void(physx::PxJoint*)>>;
bool IsAtLeastOneDynamic(AzPhysics::SimulatedBody* body0, AzPhysics::SimulatedBody* body1);
physx::PxRigidActor* GetPxRigidActor(AzPhysics::SceneHandle sceneHandle, AzPhysics::SimulatedBodyHandle worldBodyHandle);
AzPhysics::SimulatedBody* GetSimulatedBodyFromHandle(
AzPhysics::SceneHandle sceneHandle, AzPhysics::SimulatedBodyHandle bodyHandle);
namespace PxJointFactories
{
PxJointUniquePtr CreatePxD6Joint(const PhysX::D6JointLimitConfiguration& configuration,
AzPhysics::SceneHandle sceneHandle,
AzPhysics::SimulatedBodyHandle parentBodyHandle,
AzPhysics::SimulatedBodyHandle childBodyHandle);
PxJointUniquePtr CreatePxFixedJoint(const PhysX::FixedJointConfiguration& configuration,
AzPhysics::SceneHandle sceneHandle,
AzPhysics::SimulatedBodyHandle parentBodyHandle,
AzPhysics::SimulatedBodyHandle childBodyHandle);
PxJointUniquePtr CreatePxBallJoint(const PhysX::BallJointConfiguration& configuration,
AzPhysics::SceneHandle sceneHandle,
AzPhysics::SimulatedBodyHandle parentBodyHandle,
AzPhysics::SimulatedBodyHandle childBodyHandle);
PxJointUniquePtr CreatePxHingeJoint(const PhysX::HingeJointConfiguration& configuration,
AzPhysics::SceneHandle sceneHandle,
AzPhysics::SimulatedBodyHandle parentBodyHandle,
AzPhysics::SimulatedBodyHandle childBodyHandle);
} // namespace PxActorFactories
namespace Joints
{
bool IsD6SwingValid(float swingAngleY, float swingAngleZ, float swingLimitY, float swingLimitZ);
void AppendD6SwingConeToLineBuffer(
const AZ::Quaternion& parentLocalRotation,
float swingAngleY,
float swingAngleZ,
float swingLimitY,
float swingLimitZ,
float scale,
AZ::u32 angularSubdivisions,
AZ::u32 radialSubdivisions,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut);
void AppendD6TwistArcToLineBuffer(
const AZ::Quaternion& parentLocalRotation,
float twistAngle,
float twistLimitLower,
float twistLimitUpper,
float scale,
AZ::u32 angularSubdivisions,
AZ::u32 radialSubdivisions,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut);
void AppendD6CurrentTwistToLineBuffer(
const AZ::Quaternion& parentLocalRotation,
float twistAngle,
float twistLimitLower,
float twistLimitUpper,
float scale,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut);
} // namespace Joints
} // namespace Utils
} // namespace PhysX
+56 -44
View File
@@ -18,33 +18,65 @@
#include <AzFramework/Physics/SimulatedBodies/RigidBody.h>
#include <PhysX/NativeTypeIdentifiers.h>
#include <PhysX/PhysXLocks.h>
#include <Source/Joint.h>
#include <Source/JointComponent.h>
#include <Source/Utils.h>
#include <AzFramework/Physics/PhysicsSystem.h>
namespace PhysX
{
void JointComponent::Reflect(AZ::ReflectContext* context)
JointComponentConfiguration::JointComponentConfiguration(
AZ::Transform localTransformFromFollower,
AZ::EntityId leadEntity,
AZ::EntityId followerEntity)
: m_localTransformFromFollower(localTransformFromFollower)
, m_leadEntity(leadEntity)
, m_followerEntity(followerEntity)
{
}
void JointComponentConfiguration::Reflect(AZ::ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<JointComponentConfiguration>()
->Version(2)
->Field("Follower Local Transform", &JointComponentConfiguration::m_localTransformFromFollower)
->Field("Lead Entity", &JointComponentConfiguration::m_leadEntity)
->Field("Follower Entity", &JointComponentConfiguration::m_followerEntity)
;
}
}
void JointComponent::Reflect(AZ::ReflectContext* context)
{
JointComponentConfiguration::Reflect(context);
if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<JointComponent, AZ::Component>()
->Version(1)
->Version(2)
->Field("Joint Configuration", &JointComponent::m_configuration)
->Field("Joint Generic Properties", &JointComponent::m_genericProperties)
->Field("Joint Limits", &JointComponent::m_limits)
;
}
}
JointComponent::JointComponent(const GenericJointConfiguration& config)
: m_configuration(config)
JointComponent::JointComponent(
const JointComponentConfiguration& configuration,
const JointGenericProperties& genericProperties)
: m_configuration(configuration)
, m_genericProperties(genericProperties)
{
}
JointComponent::JointComponent(const GenericJointConfiguration& config
, const GenericJointLimitsConfiguration& limits)
: m_configuration(AZStd::move(config))
, m_limits(limits)
JointComponent::JointComponent(
const JointComponentConfiguration& configuration,
const JointGenericProperties& genericProperties,
const JointLimitProperties& limitProperties)
: m_configuration(configuration)
, m_genericProperties(genericProperties)
, m_limits(limitProperties)
{
}
@@ -67,16 +99,22 @@ namespace PhysX
void JointComponent::Deactivate()
{
AZ::EntityBus::Handler::BusDisconnect();
m_joint.reset();
if (auto* physicsSystem = AZ::Interface<AzPhysics::SystemInterface>::Get())
{
if (auto* scene = physicsSystem->GetScene(m_jointSceneOwner))
{
scene->RemoveJoint(m_jointHandle);
m_jointSceneOwner = AzPhysics::InvalidSceneHandle;
}
}
}
physx::PxTransform JointComponent::GetJointLocalPose(const physx::PxRigidActor* actor
, const physx::PxTransform& jointPose)
AZ::Transform JointComponent::GetJointLocalPose(const physx::PxRigidActor* actor, const AZ::Transform& jointPose)
{
if (!actor)
{
AZ_Error("JointComponent::GetJointLocalPose", false, "Can't get pose for invalid actor pointer.");
return physx::PxTransform();
return AZ::Transform::CreateIdentity();
}
PHYSX_SCENE_READ_LOCK(actor->getScene());
@@ -84,41 +122,17 @@ namespace PhysX
physx::PxTransform actorTranslateInv(-actorPose.p);
physx::PxTransform actorRotateInv(actorPose.q);
actorRotateInv = actorRotateInv.getInverse();
return actorRotateInv * actorTranslateInv * jointPose;
return PxMathConvert(actorRotateInv * actorTranslateInv) * jointPose;
}
AZ::Transform JointComponent::GetJointTransform(AZ::EntityId entityId
, const GenericJointConfiguration& jointConfig)
, const JointComponentConfiguration& jointConfig)
{
AZ::Transform jointTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(entityId);
jointTransform = jointTransform * jointConfig.m_localTransformFromFollower;
return jointTransform;
}
void JointComponent::InitGenericProperties()
{
if (!m_joint)
{
return;
}
physx::PxJoint* jointNative = static_cast<physx::PxJoint*>(m_joint->GetNativePointer());
if (!jointNative)
{
return;
}
PHYSX_SCENE_WRITE_LOCK(jointNative->getScene());
jointNative->setConstraintFlag(
physx::PxConstraintFlag::eCOLLISION_ENABLED,
m_configuration.GetFlag(GenericJointConfiguration::GenericJointFlag::SelfCollide));
if (m_configuration.GetFlag(GenericJointConfiguration::GenericJointFlag::Breakable))
{
jointNative->setBreakForce(m_configuration.m_forceMax
, m_configuration.m_torqueMax);
}
}
void JointComponent::ObtainLeadFollowerInfo(JointComponent::LeadFollowerInfo& info)
{
info = LeadFollowerInfo();
@@ -160,16 +174,15 @@ namespace PhysX
const AZ::Transform jointTransform = GetJointTransform(GetEntityId(), m_configuration);
physx::PxTransform jointPose = PxMathConvert(jointTransform);
if (info.m_leadActor)
{
info.m_leadLocal = GetJointLocalPose(info.m_leadActor, jointPose); // joint position & orientation in lead actor's frame.
info.m_leadLocal = GetJointLocalPose(info.m_leadActor, jointTransform); // joint position & orientation in lead actor's frame.
}
else
{
info.m_leadLocal = jointPose; // lead is null, attaching follower to global position of joint.
info.m_leadLocal = jointTransform; // lead is null, attaching follower to global position of joint.
}
info.m_followerLocal = PxMathConvert(m_configuration.m_localTransformFromFollower);// joint position & orientation in follower actor's frame.
info.m_followerLocal = m_configuration.m_localTransformFromFollower;// joint position & orientation in follower actor's frame.
}
void JointComponent::WarnInvalidJointSetup(AZ::EntityId entityId, const AZStd::string& message)
@@ -189,7 +202,6 @@ namespace PhysX
if (!m_configuration.m_leadEntity.IsValid() || entityId == m_configuration.m_leadEntity)
{
InitNativeJoint(); // Invoke overriden specific joint type instantiation
InitGenericProperties();
}
// Else, follower entity is activated, subscribe to be notified that lead entity is activated.
else
+36 -15
View File
@@ -18,7 +18,7 @@
#include <AzCore/Component/EntityId.h>
#include <AzCore/Component/TransformBus.h>
#include <Source/Joint.h>
#include <PhysX/Joint/Configuration/PhysXJointConfiguration.h>
namespace AzPhysics
{
@@ -27,6 +27,24 @@ namespace AzPhysics
namespace PhysX
{
class JointComponentConfiguration
{
public:
AZ_CLASS_ALLOCATOR(JointComponentConfiguration, AZ::SystemAllocator, 0);
AZ_TYPE_INFO(JointComponentConfiguration, "{1454F33F-AA6E-424B-A70C-9E463FBDEA19}");
static void Reflect(AZ::ReflectContext* context);
JointComponentConfiguration() = default;
JointComponentConfiguration(
AZ::Transform localTransformFromFollower,
AZ::EntityId leadEntity,
AZ::EntityId followerEntity);
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.
};
/// Base class for game-time generic joint components.
class JointComponent: public AZ::Component
, protected AZ::EntityBus::Handler
@@ -36,9 +54,13 @@ namespace PhysX
static void Reflect(AZ::ReflectContext* context);
JointComponent() = default;
explicit JointComponent(const GenericJointConfiguration& config);
JointComponent(const GenericJointConfiguration& config
, const GenericJointLimitsConfiguration& limits);
JointComponent(
const JointComponentConfiguration& configuration,
const JointGenericProperties& genericProperties);
JointComponent(
const JointComponentConfiguration& configuration,
const JointGenericProperties& genericProperties,
const JointLimitProperties& limitProperties);
protected:
/// Struct to provide subclasses with native pointers during joint initialization.
@@ -47,8 +69,8 @@ namespace PhysX
{
physx::PxRigidActor* m_leadActor = nullptr;
physx::PxRigidActor* m_followerActor = nullptr;
physx::PxTransform m_leadLocal = physx::PxTransform(physx::PxIdentity);
physx::PxTransform m_followerLocal = physx::PxTransform(physx::PxIdentity);
AZ::Transform m_leadLocal = AZ::Transform::CreateIdentity();
AZ::Transform m_followerLocal = AZ::Transform::CreateIdentity();
AzPhysics::SimulatedBody* m_leadBody = nullptr;
AzPhysics::SimulatedBody* m_followerBody = nullptr;
};
@@ -63,14 +85,10 @@ namespace PhysX
/// Invoked in JointComponent::OnEntityActivated for specific joint types to instantiate native joint pointer.
virtual void InitNativeJoint() {};
physx::PxTransform GetJointLocalPose(const physx::PxRigidActor* actor,
const physx::PxTransform& jointPose);
AZ::Transform GetJointLocalPose(const physx::PxRigidActor* actor, const AZ::Transform& jointPose);
AZ::Transform GetJointTransform(AZ::EntityId entityId,
const GenericJointConfiguration& jointConfig);
/// Initializes joint properties common to all native joint types after native joint creation.
void InitGenericProperties();
const JointComponentConfiguration& jointConfig);
/// Used on initialization by sub-classes to get native pointers from entity IDs.
/// This allows sub-classes to instantiate specific native types. This base class does not need knowledge of any specific joint type.
@@ -79,8 +97,11 @@ namespace PhysX
/// Issues warnings for invalid scenarios when initializing a joint from entity IDs.
void WarnInvalidJointSetup(AZ::EntityId entityId, const AZStd::string& message);
GenericJointConfiguration m_configuration;
GenericJointLimitsConfiguration m_limits;
AZStd::shared_ptr<PhysX::Joint> m_joint = nullptr;
JointComponentConfiguration m_configuration;
JointGenericProperties m_genericProperties;
JointLimitProperties m_limits;
AzPhysics::JointHandle m_jointHandle = AzPhysics::InvalidJointHandle;
AzPhysics::SceneHandle m_jointSceneOwner = AzPhysics::InvalidSceneHandle;
};
} // namespace PhysX
@@ -18,10 +18,10 @@
#include <AzFramework/Physics/MaterialBus.h>
#include <cfloat>
#include <PhysX/PhysXLocks.h>
#include <PhysX/Joint/Configuration/PhysXJointConfiguration.h>
#include <Source/RigidBody.h>
#include <Source/Scene/PhysXScene.h>
#include <Source/Shape.h>
#include <Source/Joint.h>
namespace PhysX
{
@@ -262,21 +262,24 @@ namespace PhysX
physx::PxTransform parentTM(parentOffset);
physx::PxTransform childTM(physx::PxIdentity);
AZStd::shared_ptr<Physics::JointLimitConfiguration> jointLimitConfig = configuration.m_nodes[nodeIndex].m_jointLimit;
if (!jointLimitConfig)
AZStd::shared_ptr<AzPhysics::JointConfiguration> jointConfig = configuration.m_nodes[nodeIndex].m_jointConfig;
if (!jointConfig)
{
AZStd::vector<AZ::TypeId> supportedJointLimitTypes = JointUtils::GetSupportedJointTypes();
if (!supportedJointLimitTypes.empty())
{
jointLimitConfig = JointUtils::CreateJointLimitConfiguration(supportedJointLimitTypes[0]);
}
jointConfig = AZStd::make_shared<D6JointLimitConfiguration>();
}
AzPhysics::JointHandle jointHandle = sceneInterface->AddJoint(
sceneHandle, jointConfig.get(),
ragdoll->GetNode(parentIndex)->GetRigidBody().m_bodyHandle,
ragdoll->GetNode(nodeIndex)->GetRigidBody().m_bodyHandle);
AZStd::shared_ptr<Physics::Joint> joint = JointUtils::CreateJoint(
jointLimitConfig,
&ragdoll->GetNode(parentIndex)->GetRigidBody(),
&ragdoll->GetNode(nodeIndex)->GetRigidBody());
AzPhysics::Joint* joint = sceneInterface->GetJointFromHandle(sceneHandle, jointHandle);
if (!joint)
{
AZ_Error("PhysX Ragdoll", false, "Failed to create joint for node index %i.", nodeIndex);
return nullptr;
}
// Moving from PhysX 3.4 to 4.1, the allowed range of the twist angle was expanded from -pi..pi
// to -2*pi..2*pi.
@@ -378,8 +378,8 @@ namespace PhysX
else
{
actor->setRigidBodyFlag(physx::PxRigidBodyFlag::eKINEMATIC, false);
const AZStd::shared_ptr<Physics::Joint>& joint = m_nodes[nodeIndex]->GetJoint();
if (joint)
if (AzPhysics::Joint* joint = m_nodes[nodeIndex]->GetJoint())
{
if (physx::PxD6Joint* pxJoint = static_cast<physx::PxD6Joint*>(joint->GetNativePointer()))
{
@@ -38,11 +38,17 @@ namespace PhysX
RagdollNode::~RagdollNode()
{
DestroyJoint();
DestroyPhysicsBody();
}
void RagdollNode::SetJoint(const AZStd::shared_ptr<Physics::Joint>& joint)
void RagdollNode::SetJoint(AzPhysics::Joint* joint)
{
if (m_joint)
{
return;
}
m_joint = joint;
}
@@ -52,7 +58,7 @@ namespace PhysX
return *m_rigidBody;
}
const AZStd::shared_ptr<Physics::Joint>& RagdollNode::GetJoint() const
AzPhysics::Joint* RagdollNode::GetJoint()
{
return m_joint;
}
@@ -167,4 +173,16 @@ namespace PhysX
}
}
void RagdollNode::DestroyJoint()
{
if (m_joint != nullptr && m_sceneOwner != AzPhysics::InvalidSceneHandle)
{
if (auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get())
{
sceneInterface->RemoveJoint(m_sceneOwner, m_joint->m_jointHandle);
}
m_joint = nullptr;
}
}
} // namespace PhysX
@@ -32,11 +32,11 @@ namespace PhysX
explicit RagdollNode(AzPhysics::SceneHandle sceneHandle, Physics::RagdollNodeConfiguration& nodeConfig);
~RagdollNode();
void SetJoint(const AZStd::shared_ptr<Physics::Joint>& joint);
void SetJoint(AzPhysics::Joint* joint);
// Physics::RagdollNode
AzPhysics::RigidBody& GetRigidBody() override;
const AZStd::shared_ptr<Physics::Joint>& GetJoint() const override;
AzPhysics::Joint* GetJoint() override;
bool IsSimulating() const override;
// AzPhysics::SimulatedBody
@@ -60,9 +60,10 @@ namespace PhysX
private:
void CreatePhysicsBody(AzPhysics::SceneHandle sceneHandle, Physics::RagdollNodeConfiguration& nodeConfig);
void DestroyPhysicsBody();
void DestroyJoint();
AZStd::shared_ptr<Physics::Joint> m_joint;
AzPhysics::RigidBody* m_rigidBody;
AzPhysics::Joint* m_joint = nullptr;
AzPhysics::RigidBody* m_rigidBody = nullptr;
AzPhysics::SimulatedBodyHandle m_rigidBodyHandle = AzPhysics::InvalidSimulatedBodyHandle;
AzPhysics::SceneHandle m_sceneOwner = AzPhysics::InvalidSceneHandle;
PhysX::ActorData m_actorUserData;
@@ -379,7 +379,7 @@ namespace PhysX
for (size_t nodeIndex = 0; nodeIndex < numNodes; nodeIndex++)
{
if (const AZStd::shared_ptr<Physics::Joint>& joint = ragdoll->GetNode(nodeIndex)->GetJoint())
if (const AzPhysics::Joint* joint = ragdoll->GetNode(nodeIndex)->GetJoint())
{
if (auto* pxJoint = static_cast<physx::PxD6Joint*>(joint->GetNativePointer()))
{
@@ -10,3 +10,5 @@
#
set(PAL_TRAIT_PHYSX_SUPPORTED TRUE)
set(PAL_TRAIT_JOINTS_TYPED_TEST_CASE FALSE)
@@ -10,3 +10,4 @@
#
set(PAL_TRAIT_PHYSX_SUPPORTED TRUE)
set(PAL_TRAIT_JOINTS_TYPED_TEST_CASE FALSE)
@@ -10,3 +10,4 @@
#
set(PAL_TRAIT_PHYSX_SUPPORTED TRUE)
set(PAL_TRAIT_JOINTS_TYPED_TEST_CASE TRUE)
@@ -10,3 +10,4 @@
#
set(PAL_TRAIT_PHYSX_SUPPORTED TRUE)
set(PAL_TRAIT_JOINTS_TYPED_TEST_CASE TRUE)
@@ -10,3 +10,4 @@
#
set(PAL_TRAIT_PHYSX_SUPPORTED TRUE)
set(PAL_TRAIT_JOINTS_TYPED_TEST_CASE TRUE)
+105
View File
@@ -31,6 +31,8 @@
#include <PhysXCharacters/API/CharacterController.h>
#include <PhysXCharacters/API/CharacterUtils.h>
#include <System/PhysXSystem.h>
#include <PhysX/Joint/Configuration/PhysXJointConfiguration.h>
#include <Joint/PhysXJoint.h>
namespace PhysX
{
@@ -232,6 +234,18 @@ namespace PhysX
scene->GetSceneHandle());
}
template<class JointType, class ConfigurationType>
AzPhysics::Joint* CreateJoint(const ConfigurationType* configuration,
AzPhysics::SceneHandle sceneHandle,
AzPhysics::SimulatedBodyHandle parentBodyHandle,
AzPhysics::SimulatedBodyHandle childBodyHandle,
AZ::Crc32& crc)
{
JointType* newBody = aznew JointType(*configuration, sceneHandle, parentBodyHandle, childBodyHandle);
crc = AZ::Crc32(newBody, sizeof(*newBody));
return newBody;
}
//helper to perform a ray cast
AzPhysics::SceneQueryHits RayCast(const AzPhysics::RayCastRequest* raycastRequest,
AZStd::vector<physx::PxRaycastHit>& raycastBuffer,
@@ -813,6 +827,90 @@ namespace PhysX
}
}
AzPhysics::JointHandle PhysXScene::AddJoint(const AzPhysics::JointConfiguration* jointConfig,
AzPhysics::SimulatedBodyHandle parentBody, AzPhysics::SimulatedBodyHandle childBody)
{
AzPhysics::Joint* newJoint = nullptr;
AZ::Crc32 newJointCrc;
if (azrtti_istypeof<PhysX::D6JointLimitConfiguration>(jointConfig))
{
newJoint = Internal::CreateJoint<PhysXD6Joint, D6JointLimitConfiguration>(
azdynamic_cast<const D6JointLimitConfiguration*>(jointConfig),
m_sceneHandle, parentBody, childBody, newJointCrc);
}
else if (azrtti_istypeof<PhysX::FixedJointConfiguration*>(jointConfig))
{
newJoint = Internal::CreateJoint<PhysXFixedJoint, FixedJointConfiguration>(
azdynamic_cast<const FixedJointConfiguration*>(jointConfig),
m_sceneHandle, parentBody, childBody, newJointCrc);
}
else if (azrtti_istypeof<PhysX::BallJointConfiguration*>(jointConfig))
{
newJoint = Internal::CreateJoint<PhysXBallJoint, BallJointConfiguration>(
azdynamic_cast<const BallJointConfiguration*>(jointConfig),
m_sceneHandle, parentBody, childBody, newJointCrc);
}
else if (azrtti_istypeof<PhysX::HingeJointConfiguration*>(jointConfig))
{
newJoint = Internal::CreateJoint<PhysXHingeJoint, HingeJointConfiguration>(
azdynamic_cast<const HingeJointConfiguration*>(jointConfig),
m_sceneHandle, parentBody, childBody, newJointCrc);
}
else
{
AZ_Warning("PhysXScene", false, "Unknown JointConfiguration.");
return AzPhysics::InvalidJointHandle;
}
if (newJoint != nullptr)
{
AzPhysics::JointIndex index = index = m_joints.size();
m_joints.emplace_back(newJointCrc, newJoint);
const AzPhysics::JointHandle newJointHandle(newJointCrc, index);
newJoint->m_sceneOwner = m_sceneHandle;
newJoint->m_jointHandle = newJointHandle;
return newJointHandle;
}
return AzPhysics::InvalidJointHandle;
}
AzPhysics::Joint* PhysXScene::GetJointFromHandle(AzPhysics::JointHandle jointHandle)
{
if (jointHandle == AzPhysics::InvalidJointHandle)
{
return nullptr;
}
AzPhysics::JointIndex index = AZStd::get<AzPhysics::HandleTypeIndex::Index>(jointHandle);
if (index < m_joints.size()
&& m_joints[index].first == AZStd::get<AzPhysics::HandleTypeIndex::Crc>(jointHandle))
{
return m_joints[index].second;
}
return nullptr;
}
void PhysXScene::RemoveJoint(AzPhysics::JointHandle jointHandle)
{
if (jointHandle == AzPhysics::InvalidJointHandle)
{
return;
}
AzPhysics::JointIndex index = AZStd::get<AzPhysics::HandleTypeIndex::Index>(jointHandle);
if (index < m_joints.size()
&& m_joints[index].first == AZStd::get<AzPhysics::HandleTypeIndex::Crc>(jointHandle))
{
m_deferredDeletionsJoints.push_back(m_joints[index].second);
m_joints[index] = AZStd::make_pair(AZ::Crc32(), nullptr);
m_freeJointSlots.push(index);
jointHandle = AzPhysics::InvalidJointHandle;
}
}
AzPhysics::SceneQueryHits PhysXScene::QueryScene(const AzPhysics::SceneQueryRequest* request)
{
if (request == nullptr)
@@ -996,6 +1094,13 @@ namespace PhysX
{
delete simulatedBody;
}
AZStd::vector<AzPhysics::Joint*> jointDeletions;
jointDeletions.swap(m_deferredDeletionsJoints);
for (auto* joint : jointDeletions)
{
delete joint;
}
}
void PhysXScene::ProcessTriggerEvents()
@@ -12,6 +12,7 @@
#pragma once
#include <AzFramework/Physics/PhysicsScene.h>
#include <AzFramework/Physics/Common/PhysicsJoint.h>
#include <AzFramework/Physics/Common/PhysicsEvents.h>
#include <AzFramework/Physics/Common/PhysicsSimulatedBody.h>
#include <AzFramework/Physics/Configuration/SceneConfiguration.h>
@@ -52,6 +53,10 @@ namespace PhysX
void RemoveSimulatedBodies(AzPhysics::SimulatedBodyHandleList& bodyHandles) override;
void EnableSimulationOfBody(AzPhysics::SimulatedBodyHandle bodyHandle) override;
void DisableSimulationOfBody(AzPhysics::SimulatedBodyHandle bodyHandle) override;
AzPhysics::JointHandle AddJoint(const AzPhysics::JointConfiguration* jointConfig,
AzPhysics::SimulatedBodyHandle parentBody, AzPhysics::SimulatedBodyHandle childBody) override;
AzPhysics::Joint* GetJointFromHandle(AzPhysics::JointHandle jointHandle) override;
void RemoveJoint(AzPhysics::JointHandle jointHandle) override;
AzPhysics::SceneQueryHits QueryScene(const AzPhysics::SceneQueryRequest* request) override;
AzPhysics::SceneQueryHitsList QuerySceneBatch(const AzPhysics::SceneQueryRequests& requests) override;
[[nodiscard]] bool QuerySceneAsync(AzPhysics::SceneQuery::AsyncRequestId requestId,
@@ -94,6 +99,10 @@ namespace PhysX
AZStd::vector<AzPhysics::SimulatedBody*> m_deferredDeletions;
AZStd::queue<AzPhysics::SimulatedBodyIndex> m_freeSceneSlots;
AZStd::vector<AZStd::pair<AZ::Crc32, AzPhysics::Joint*>> m_joints;
AZStd::vector<AzPhysics::Joint*> m_deferredDeletionsJoints;
AZStd::queue<AzPhysics::JointIndex> m_freeJointSlots;
AzPhysics::SystemEvents::OnConfigurationChangedEvent::Handler m_physicsSystemConfigChanged;
static thread_local AZStd::vector<physx::PxRaycastHit> s_rayCastBuffer; //!< thread local structure to hold hits for a single raycast or shapecast.
@@ -11,6 +11,7 @@
*/
#include <Scene/PhysXSceneInterface.h>
#include <AzFramework/Physics/Common/PhysicsJoint.h>
#include <AzFramework/Physics/Common/PhysicsSimulatedBody.h>
#include <AzFramework/Physics/Configuration/SceneConfiguration.h>
#include <System/PhysXSystem.h>
@@ -144,6 +145,36 @@ namespace PhysX
}
}
AzPhysics::JointHandle PhysXSceneInterface::AddJoint(
AzPhysics::SceneHandle sceneHandle, const AzPhysics::JointConfiguration* jointConfig,
AzPhysics::SimulatedBodyHandle parentBody, AzPhysics::SimulatedBodyHandle childBody)
{
if (AzPhysics::Scene* scene = m_physxSystem->GetScene(sceneHandle))
{
return scene->AddJoint(jointConfig, parentBody, childBody);
}
return AzPhysics::InvalidJointHandle;
}
AzPhysics::Joint* PhysXSceneInterface::GetJointFromHandle(AzPhysics::SceneHandle sceneHandle, AzPhysics::JointHandle jointHandle)
{
if (AzPhysics::Scene* scene = m_physxSystem->GetScene(sceneHandle))
{
return scene->GetJointFromHandle(jointHandle);
}
return nullptr;
}
void PhysXSceneInterface::RemoveJoint(AzPhysics::SceneHandle sceneHandle, AzPhysics::JointHandle jointHandle)
{
if (AzPhysics::Scene* scene = m_physxSystem->GetScene(sceneHandle))
{
scene->RemoveJoint(jointHandle);
}
}
AzPhysics::SceneQueryHits PhysXSceneInterface::QueryScene(
AzPhysics::SceneHandle sceneHandle, const AzPhysics::SceneQueryRequest* request)
{
@@ -44,6 +44,10 @@ namespace PhysX
void RemoveSimulatedBodies(AzPhysics::SceneHandle sceneHandle, AzPhysics::SimulatedBodyHandleList& bodyHandles) override;
void EnableSimulationOfBody(AzPhysics::SceneHandle sceneHandle, AzPhysics::SimulatedBodyHandle bodyHandle) override;
void DisableSimulationOfBody(AzPhysics::SceneHandle sceneHandle, AzPhysics::SimulatedBodyHandle bodyHandle) override;
AzPhysics::JointHandle AddJoint(AzPhysics::SceneHandle sceneHandle, const AzPhysics::JointConfiguration* jointConfig,
AzPhysics::SimulatedBodyHandle parentBody, AzPhysics::SimulatedBodyHandle childBody) override;
AzPhysics::Joint* GetJointFromHandle(AzPhysics::SceneHandle sceneHandle, AzPhysics::JointHandle jointHandle) override;
void RemoveJoint(AzPhysics::SceneHandle sceneHandle, AzPhysics::JointHandle jointHandle) override;
AzPhysics::SceneQueryHits QueryScene(AzPhysics::SceneHandle sceneHandle, const AzPhysics::SceneQueryRequest* request) override;
AzPhysics::SceneQueryHitsList QuerySceneBatch(AzPhysics::SceneHandle sceneHandle, const AzPhysics::SceneQueryRequests& requests) override;
[[nodiscard]] bool QuerySceneAsync(AzPhysics::SceneHandle sceneHandle, AzPhysics::SceneQuery::AsyncRequestId requestId,
@@ -0,0 +1,299 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or
* a third party where indicated.
*
* 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.
*
*/
#include <System/PhysXJointInterface.h>
#include <AzFramework/Physics/Configuration/JointConfiguration.h>
#include <PhysX/Joint/Configuration/PhysXJointConfiguration.h>
namespace PhysX
{
namespace
{
struct D6JointState
{
float m_swingAngleY;
float m_swingAngleZ;
float m_twistAngle;
};
D6JointState CalculateD6JointState(
const AZ::Quaternion& parentWorldRotation,
const AZ::Quaternion& parentLocalRotation,
const AZ::Quaternion& childWorldRotation,
const AZ::Quaternion& childLocalRotation)
{
D6JointState result;
const AZ::Quaternion parentRotation = parentWorldRotation * parentLocalRotation;
const AZ::Quaternion childRotation = childWorldRotation * childLocalRotation;
const AZ::Quaternion relativeRotation = parentRotation.GetConjugate() * childRotation;
AZ::Quaternion twistQuat = AZ::IsClose(relativeRotation.GetX(), 0.0f, AZ::Constants::FloatEpsilon)
? AZ::Quaternion::CreateIdentity()
: AZ::Quaternion(relativeRotation.GetX(), 0.0f, 0.0f, relativeRotation.GetW()).GetNormalized();
AZ::Quaternion swingQuat = relativeRotation * twistQuat.GetConjugate();
// make sure the twist angle has the correct sign for the rotation
twistQuat *= AZ::GetSign(twistQuat.GetX());
// make sure we get the shortest arcs for the swing degrees of freedom
swingQuat *= AZ::GetSign(swingQuat.GetW());
// the PhysX swing limits work in terms of tan quarter angles
result.m_swingAngleY = 4.0f * atan2f(swingQuat.GetY(), 1.0f + swingQuat.GetW());
result.m_swingAngleZ = 4.0f * atan2f(swingQuat.GetZ(), 1.0f + swingQuat.GetW());
const float twistAngle = twistQuat.GetAngle();
// GetAngle returns an angle in the range 0..2 pi, but the twist limits work in the range -pi..pi
const float wrappedTwistAngle = twistAngle > AZ::Constants::Pi ? twistAngle - AZ::Constants::TwoPi : twistAngle;
result.m_twistAngle = wrappedTwistAngle;
return result;
}
bool IsD6SwingValid(float swingAngleY, float swingAngleZ, float swingLimitY, float swingLimitZ)
{
const float epsilon = AZ::Constants::FloatEpsilon;
const float yFactor = tanf(0.25f * swingAngleY) / AZStd::GetMax(epsilon, tanf(0.25f * swingLimitY));
const float zFactor = tanf(0.25f * swingAngleZ) / AZStd::GetMax(epsilon, tanf(0.25f * swingLimitZ));
return (yFactor * yFactor + zFactor * zFactor <= 1.0f + epsilon);
}
void AppendD6SwingConeToLineBuffer(
const AZ::Quaternion& parentLocalRotation,
float swingAngleY,
float swingAngleZ,
float swingLimitY,
float swingLimitZ,
float scale,
AZ::u32 angularSubdivisions,
AZ::u32 radialSubdivisions,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut)
{
const AZ::u32 numLinesSwingCone = angularSubdivisions * (1u + radialSubdivisions);
lineBufferOut.reserve(lineBufferOut.size() + 2u * numLinesSwingCone);
lineValidityBufferOut.reserve(lineValidityBufferOut.size() + numLinesSwingCone);
// the orientation quat for a radial line in the cone can be represented in terms of sin and cos half angles
// these expressions can be efficiently calculated using tan quarter angles as follows:
// writing t = tan(x / 4)
// sin(x / 2) = 2 * t / (1 + t * t)
// cos(x / 2) = (1 - t * t) / (1 + t * t)
const float tanQuarterSwingZ = tanf(0.25f * swingLimitZ);
const float tanQuarterSwingY = tanf(0.25f * swingLimitY);
AZ::Vector3 previousRadialVector = AZ::Vector3::CreateZero();
for (AZ::u32 angularIndex = 0; angularIndex <= angularSubdivisions; angularIndex++)
{
const float angle = AZ::Constants::TwoPi / angularSubdivisions * angularIndex;
// the axis about which to rotate the x-axis to get the radial vector for this segment of the cone
const AZ::Vector3 rotationAxis(0, -tanQuarterSwingY * sinf(angle), tanQuarterSwingZ * cosf(angle));
const float normalizationFactor = rotationAxis.GetLengthSq();
const AZ::Quaternion radialVectorRotation = 1.0f / (1.0f + normalizationFactor) *
AZ::Quaternion::CreateFromVector3AndValue(2.0f * rotationAxis, 1.0f - normalizationFactor);
const AZ::Vector3 radialVector =
(parentLocalRotation * radialVectorRotation).TransformVector(AZ::Vector3::CreateAxisX(scale));
if (angularIndex > 0)
{
for (AZ::u32 radialIndex = 1; radialIndex <= radialSubdivisions; radialIndex++)
{
float radiusFraction = 1.0f / radialSubdivisions * radialIndex;
lineBufferOut.push_back(radiusFraction * radialVector);
lineBufferOut.push_back(radiusFraction * previousRadialVector);
}
}
if (angularIndex < angularSubdivisions)
{
lineBufferOut.push_back(AZ::Vector3::CreateZero());
lineBufferOut.push_back(radialVector);
}
previousRadialVector = radialVector;
}
const bool swingValid = IsD6SwingValid(swingAngleY, swingAngleZ, swingLimitY, swingLimitZ);
lineValidityBufferOut.insert(lineValidityBufferOut.end(), numLinesSwingCone, swingValid);
}
void AppendD6TwistArcToLineBuffer(
const AZ::Quaternion& parentLocalRotation,
float twistAngle,
float twistLimitLower,
float twistLimitUpper,
float scale,
AZ::u32 angularSubdivisions,
AZ::u32 radialSubdivisions,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut)
{
const AZ::u32 numLinesTwistArc = angularSubdivisions * (1u + radialSubdivisions) + 1u;
lineBufferOut.reserve(lineBufferOut.size() + 2u * numLinesTwistArc);
AZ::Vector3 previousRadialVector = AZ::Vector3::CreateZero();
const float twistRange = twistLimitUpper - twistLimitLower;
for (AZ::u32 angularIndex = 0; angularIndex <= angularSubdivisions; angularIndex++)
{
const float angle = twistLimitLower + twistRange / angularSubdivisions * angularIndex;
const AZ::Vector3 radialVector = parentLocalRotation.TransformVector(scale * AZ::Vector3(0.0f, cosf(angle), sinf(angle)));
if (angularIndex > 0)
{
for (AZ::u32 radialIndex = 1; radialIndex <= radialSubdivisions; radialIndex++)
{
const float radiusFraction = 1.0f / radialSubdivisions * radialIndex;
lineBufferOut.push_back(radiusFraction * radialVector);
lineBufferOut.push_back(radiusFraction * previousRadialVector);
}
}
lineBufferOut.push_back(AZ::Vector3::CreateZero());
lineBufferOut.push_back(radialVector);
previousRadialVector = radialVector;
}
const bool twistValid = (twistAngle >= twistLimitLower && twistAngle <= twistLimitUpper);
lineValidityBufferOut.insert(lineValidityBufferOut.end(), numLinesTwistArc, twistValid);
}
void AppendD6CurrentTwistToLineBuffer(
const AZ::Quaternion& parentLocalRotation,
float twistAngle,
[[maybe_unused]] float twistLimitLower,
[[maybe_unused]] float twistLimitUpper,
float scale,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut)
{
const AZ::Vector3 twistVector =
parentLocalRotation.TransformVector(1.25f * scale * AZ::Vector3(0.0f, cosf(twistAngle), sinf(twistAngle)));
lineBufferOut.push_back(AZ::Vector3::CreateZero());
lineBufferOut.push_back(twistVector);
lineValidityBufferOut.push_back(true);
}
template<typename Configuration>
AZStd::unique_ptr<AzPhysics::JointConfiguration> ConfigurationFactory(
const AZ::Quaternion& parentLocalRotation, const AZ::Quaternion& childLocalRotation)
{
auto jointConfig = AZStd::make_unique<Configuration>();
jointConfig->m_childLocalRotation = childLocalRotation;
jointConfig->m_parentLocalRotation = parentLocalRotation;
return jointConfig;
}
} // namespace
const AZStd::vector<AZ::TypeId> PhysXJointHelpersInterface::GetSupportedJointTypeIds() const
{
static AZStd::vector<AZ::TypeId> jointTypes = {
D6JointLimitConfiguration::RTTI_Type(),
FixedJointConfiguration::RTTI_Type(),
BallJointConfiguration::RTTI_Type(),
HingeJointConfiguration::RTTI_Type()
};
return jointTypes;
}
AZStd::optional<const AZ::TypeId> PhysXJointHelpersInterface::GetSupportedJointTypeId(AzPhysics::JointType typeEnum) const
{
switch (typeEnum)
{
case AzPhysics::JointType::D6Joint:
return azrtti_typeid<D6JointLimitConfiguration>();
case AzPhysics::JointType::FixedJoint:
return azrtti_typeid<FixedJointConfiguration>();
case AzPhysics::JointType::BallJoint:
return azrtti_typeid<BallJointConfiguration>();
case AzPhysics::JointType::HingeJoint:
return azrtti_typeid<HingeJointConfiguration>();
default:
AZ_Warning("PhysX Joint Utils", false, "Unsupported joint type in GetSupportedJointTypeId");
}
return AZStd::nullopt;
}
AZStd::unique_ptr<AzPhysics::JointConfiguration> PhysXJointHelpersInterface::ComputeInitialJointLimitConfiguration(
const AZ::TypeId& jointLimitTypeId,
const AZ::Quaternion& parentWorldRotation,
const AZ::Quaternion& childWorldRotation,
const AZ::Vector3& axis,
[[maybe_unused]] const AZStd::vector<AZ::Quaternion>& exampleLocalRotations)
{
const AZ::Vector3& normalizedAxis = axis.IsZero() ? AZ::Vector3::CreateAxisX() : axis.GetNormalized();
const AZ::Quaternion childLocalRotation = AZ::Quaternion::CreateShortestArc(
AZ::Vector3::CreateAxisX(), childWorldRotation.GetConjugate().TransformVector(normalizedAxis));
const AZ::Quaternion parentLocalRotation = parentWorldRotation.GetConjugate() * childWorldRotation * childLocalRotation;
if (jointLimitTypeId == azrtti_typeid<D6JointLimitConfiguration>())
{
return ConfigurationFactory<D6JointLimitConfiguration>(parentLocalRotation, childLocalRotation);
}
else if (jointLimitTypeId == azrtti_typeid<FixedJointConfiguration>())
{
return ConfigurationFactory<FixedJointConfiguration>(parentLocalRotation, childLocalRotation);
}
else if (jointLimitTypeId == azrtti_typeid<BallJointConfiguration>())
{
return ConfigurationFactory<BallJointConfiguration>(parentLocalRotation, childLocalRotation);
}
else if (jointLimitTypeId == azrtti_typeid<HingeJointConfiguration>())
{
return ConfigurationFactory<HingeJointConfiguration>(parentLocalRotation, childLocalRotation);
}
AZ_Warning("PhysX Joint Utils", false, "Unsupported joint type in ComputeInitialJointLimitConfiguration");
return nullptr;
}
void PhysXJointHelpersInterface::GenerateJointLimitVisualizationData(
const AzPhysics::JointConfiguration& configuration,
const AZ::Quaternion& parentRotation,
const AZ::Quaternion& childRotation,
float scale,
AZ::u32 angularSubdivisions,
AZ::u32 radialSubdivisions,
[[maybe_unused]] AZStd::vector<AZ::Vector3>& vertexBufferOut,
[[maybe_unused]] AZStd::vector<AZ::u32>& indexBufferOut,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut)
{
if (const auto d6JointConfiguration = azrtti_cast<const D6JointLimitConfiguration*>(&configuration))
{
const AZ::u32 angularSubdivisionsClamped = AZ::GetClamp(angularSubdivisions, 4u, 32u);
const AZ::u32 radialSubdivisionsClamped = AZ::GetClamp(radialSubdivisions, 1u, 4u);
const D6JointState jointState = CalculateD6JointState(
parentRotation, d6JointConfiguration->m_parentLocalRotation, childRotation, d6JointConfiguration->m_childLocalRotation);
const float swingAngleY = jointState.m_swingAngleY;
const float swingAngleZ = jointState.m_swingAngleZ;
const float twistAngle = jointState.m_twistAngle;
const float swingLimitY = AZ::DegToRad(d6JointConfiguration->m_swingLimitY);
const float swingLimitZ = AZ::DegToRad(d6JointConfiguration->m_swingLimitZ);
const float twistLimitLower = AZ::DegToRad(d6JointConfiguration->m_twistLimitLower);
const float twistLimitUpper = AZ::DegToRad(d6JointConfiguration->m_twistLimitUpper);
AppendD6SwingConeToLineBuffer(
d6JointConfiguration->m_parentLocalRotation, swingAngleY, swingAngleZ, swingLimitY, swingLimitZ, scale,
angularSubdivisionsClamped, radialSubdivisionsClamped, lineBufferOut, lineValidityBufferOut);
AppendD6TwistArcToLineBuffer(
d6JointConfiguration->m_parentLocalRotation, twistAngle, twistLimitLower, twistLimitUpper, scale,
angularSubdivisionsClamped, radialSubdivisionsClamped, lineBufferOut, lineValidityBufferOut);
AppendD6CurrentTwistToLineBuffer(
d6JointConfiguration->m_parentLocalRotation, twistAngle, twistLimitLower, twistLimitUpper, scale, lineBufferOut,
lineValidityBufferOut);
}
}
}
@@ -0,0 +1,52 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or
* a third party where indicated.
*
* 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 <AzCore/Interface/Interface.h>
#include <AzFramework/Physics/Common/PhysicsJoint.h>
namespace AzPhysics
{
struct JointConfiguration;
}
namespace PhysX
{
class PhysXJointHelpersInterface
: public AZ::Interface<AzPhysics::JointHelpersInterface>::Registrar
{
public:
AZ_RTTI(PhysX::PhysXJointHelpersInterface, "{48AC5137-2226-4C57-8E4C-FCF3C1965252}", AzPhysics::JointHelpersInterface);
const AZStd::vector<AZ::TypeId> GetSupportedJointTypeIds() const override;
AZStd::optional<const AZ::TypeId> GetSupportedJointTypeId(AzPhysics::JointType typeEnum) const override;
AZStd::unique_ptr<AzPhysics::JointConfiguration> ComputeInitialJointLimitConfiguration(
const AZ::TypeId& jointLimitTypeId,
const AZ::Quaternion& parentWorldRotation,
const AZ::Quaternion& childWorldRotation,
const AZ::Vector3& axis,
const AZStd::vector<AZ::Quaternion>& exampleLocalRotations) override;
void GenerateJointLimitVisualizationData(
const AzPhysics::JointConfiguration& configuration,
const AZ::Quaternion& parentRotation,
const AZ::Quaternion& childRotation,
float scale,
AZ::u32 angularSubdivisions,
AZ::u32 radialSubdivisions,
AZStd::vector<AZ::Vector3>& vertexBufferOut,
AZStd::vector<AZ::u32>& indexBufferOut,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut) override;
};
}
@@ -25,6 +25,7 @@
#include <System/PhysXSdkCallbacks.h>
#include <PhysX/Configuration/PhysXConfiguration.h>
#include <System/PhysXJointInterface.h>
namespace physx
{
@@ -128,6 +129,7 @@ namespace PhysX
Debug::PhysXDebug m_physXDebug; //! Handler for the PhysXDebug Interface.
PhysXSettingsRegistryManager& m_registryManager; //! Handles all settings registry interactions.
PhysXSceneInterface m_sceneInterface; //! Implemented the Scene Az::Interface.
PhysXJointHelpersInterface m_jointHelperInterface; //! Implementation of the JointHelpersInterface.
class MaterialLibraryAssetHelper
: private AZ::Data::AssetBus::Handler
@@ -20,7 +20,6 @@
#include <Source/Utils.h>
#include <Source/Collision.h>
#include <Source/Shape.h>
#include <Source/Joint.h>
#include <Source/Pipeline/MeshAssetHandler.h>
#include <Source/Pipeline/HeightFieldAssetHandler.h>
#include <Source/PhysXCharacters/API/CharacterUtils.h>
@@ -93,7 +92,6 @@ namespace PhysX
void SystemComponent::Reflect(AZ::ReflectContext* context)
{
D6JointLimitConfiguration::Reflect(context);
Pipeline::MeshAsset::Reflect(context);
PhysX::ReflectionUtils::ReflectPhysXOnlyApi(context);
@@ -347,49 +345,6 @@ namespace PhysX
return AZStd::make_shared<PhysX::Material>(materialConfiguration);
}
AZStd::vector<AZ::TypeId> SystemComponent::GetSupportedJointTypes()
{
return JointUtils::GetSupportedJointTypes();
}
AZStd::shared_ptr<Physics::JointLimitConfiguration> SystemComponent::CreateJointLimitConfiguration(AZ::TypeId jointType)
{
return JointUtils::CreateJointLimitConfiguration(jointType);
}
AZStd::shared_ptr<Physics::Joint> SystemComponent::CreateJoint(const AZStd::shared_ptr<Physics::JointLimitConfiguration>& configuration,
AzPhysics::SimulatedBody* parentBody, AzPhysics::SimulatedBody* childBody)
{
return JointUtils::CreateJoint(configuration, parentBody, childBody);
}
void SystemComponent::GenerateJointLimitVisualizationData(
const Physics::JointLimitConfiguration& configuration,
const AZ::Quaternion& parentRotation,
const AZ::Quaternion& childRotation,
float scale,
AZ::u32 angularSubdivisions,
AZ::u32 radialSubdivisions,
AZStd::vector<AZ::Vector3>& vertexBufferOut,
AZStd::vector<AZ::u32>& indexBufferOut,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut)
{
JointUtils::GenerateJointLimitVisualizationData(configuration, parentRotation, childRotation, scale,
angularSubdivisions, radialSubdivisions, vertexBufferOut, indexBufferOut, lineBufferOut, lineValidityBufferOut);
}
AZStd::unique_ptr<Physics::JointLimitConfiguration> SystemComponent::ComputeInitialJointLimitConfiguration(
const AZ::TypeId& jointLimitTypeId,
const AZ::Quaternion& parentWorldRotation,
const AZ::Quaternion& childWorldRotation,
const AZ::Vector3& axis,
const AZStd::vector<AZ::Quaternion>& exampleLocalRotations)
{
return JointUtils::ComputeInitialJointLimitConfiguration(jointLimitTypeId, parentWorldRotation,
childWorldRotation, axis, exampleLocalRotations);
}
void SystemComponent::ReleaseNativeMeshObject(void* nativeMeshObject)
{
if (nativeMeshObject)
-22
View File
@@ -115,28 +115,6 @@ namespace PhysX
AZStd::shared_ptr<Physics::Shape> CreateShape(const Physics::ColliderConfiguration& colliderConfiguration, const Physics::ShapeConfiguration& configuration) override;
AZStd::shared_ptr<Physics::Material> CreateMaterial(const Physics::MaterialConfiguration& materialConfiguration) override;
AZStd::vector<AZ::TypeId> GetSupportedJointTypes() override;
AZStd::shared_ptr<Physics::JointLimitConfiguration> CreateJointLimitConfiguration(AZ::TypeId jointType) override;
AZStd::shared_ptr<Physics::Joint> CreateJoint(const AZStd::shared_ptr<Physics::JointLimitConfiguration>& configuration,
AzPhysics::SimulatedBody* parentBody, AzPhysics::SimulatedBody* childBody) override;
void GenerateJointLimitVisualizationData(
const Physics::JointLimitConfiguration& configuration,
const AZ::Quaternion& parentRotation,
const AZ::Quaternion& childRotation,
float scale,
AZ::u32 angularSubdivisions,
AZ::u32 radialSubdivisions,
AZStd::vector<AZ::Vector3>& vertexBufferOut,
AZStd::vector<AZ::u32>& indexBufferOut,
AZStd::vector<AZ::Vector3>& lineBufferOut,
AZStd::vector<bool>& lineValidityBufferOut) override;
AZStd::unique_ptr<Physics::JointLimitConfiguration> ComputeInitialJointLimitConfiguration(
const AZ::TypeId& jointLimitTypeId,
const AZ::Quaternion& parentWorldRotation,
const AZ::Quaternion& childWorldRotation,
const AZ::Vector3& axis,
const AZStd::vector<AZ::Quaternion>& exampleLocalRotations) override;
void ReleaseNativeMeshObject(void* nativeMeshObject) override;
// Assets related data
+7 -3
View File
@@ -40,9 +40,9 @@
#include <Source/Shape.h>
#include <Source/StaticRigidBodyComponent.h>
#include <Source/RigidBodyStatic.h>
#include <Source/Joint.h>
#include <Source/Utils.h>
#include <PhysX/PhysXLocks.h>
#include <PhysX/Joint/Configuration/PhysXJointConfiguration.h>
namespace PhysX
{
@@ -1394,8 +1394,12 @@ namespace PhysX
ForceRegionBusBehaviorHandler::Reflect(context);
GenericJointConfiguration::Reflect(context);
GenericJointLimitsConfiguration::Reflect(context);
D6JointLimitConfiguration::Reflect(context);
JointGenericProperties::Reflect(context);
JointLimitProperties::Reflect(context);
FixedJointConfiguration::Reflect(context);
BallJointConfiguration::Reflect(context);
HingeJointConfiguration::Reflect(context);
}
void ForceRegionBusBehaviorHandler::Reflect(AZ::ReflectContext* context)
@@ -24,6 +24,7 @@
namespace AzPhysics
{
class Scene;
struct RigidBody;
}
namespace PhysX::Benchmarks
@@ -26,7 +26,7 @@
#include <Benchmarks/PhysXBenchmarksCommon.h>
#include <PhysXTestCommon.h>
#include <Joint.h>
#include <PhysX/Joint/Configuration/PhysXJointConfiguration.h>
namespace PhysX::Benchmarks
{
@@ -102,7 +102,7 @@ namespace PhysX::Benchmarks
{
AzPhysics::RigidBody* m_parent;
AzPhysics::SimulatedBody* m_child;
AZStd::shared_ptr<Physics::Joint> m_joint;
AzPhysics::JointHandle m_jointHandle;
};
//! Structure to hold the upper and lower twist limits
//! used with Utils::CreateJoints GenerateTwistLimitsFuncPtr
@@ -122,13 +122,11 @@ namespace PhysX::Benchmarks
//! Helper function to add the required number of joints to the provided world
//! @param numJoints, the requested number of joints to spawn
//! @param system, current active physics system
//! @param scene, the physics scene to spawn the joints and their world bodies into
//! @param parentPositionGenerator, [optional] function pointer to allow caller to pick the spawn position of the parent body
//! @param childPositionGenerator, [optional] function pointer to allow caller to pick the spawn position of the child body
//! @param GenerateTwistLimitsFuncPtr, [optional] function pointer to allow caller to pick the twist limits of the joint
AZStd::vector<JointGroup> CreateJoints(int numJoints,
Physics::System* system,
AzPhysics::Scene* scene,
GenerateSpawnPositionFuncPtr* parentPositionGenerator = nullptr,
GenerateSpawnPositionFuncPtr* childPositionGenerator = nullptr,
@@ -173,18 +171,18 @@ namespace PhysX::Benchmarks
AzPhysics::SimulatedBodyHandle staticRigidBodyHandle = scene->AddSimulatedBody(&staticRigidBodyConfig);
newJoint.m_child = scene->GetSimulatedBodyFromHandle(staticRigidBodyHandle);
AZStd::shared_ptr <PhysX::D6JointLimitConfiguration> config = AZStd::make_shared<D6JointLimitConfiguration>();
PhysX::D6JointLimitConfiguration config;
TwistLimits limits(JointConstants::CreateJointDefaults::UpperLimit, JointConstants::CreateJointDefaults::LowerLimit);
if (twistLimitsGenerator)
{
limits = (*twistLimitsGenerator)(i);
}
config->m_twistLimitUpper = limits.m_upperLimit;
config->m_twistLimitLower = limits.m_lowerLimit;
config->m_swingLimitY = 1.0f;
config->m_swingLimitZ = 1.0f;
newJoint.m_joint = system->CreateJoint(config, newJoint.m_parent, newJoint.m_child);
config.m_twistLimitUpper = limits.m_upperLimit;
config.m_twistLimitLower = limits.m_lowerLimit;
config.m_swingLimitY = 1.0f;
config.m_swingLimitZ = 1.0f;
newJoint.m_jointHandle = scene->AddJoint(&config, newJoint.m_parent->m_bodyHandle, newJoint.m_child->m_bodyHandle);
joints.emplace_back(AZStd::move(newJoint));
}
@@ -201,8 +199,6 @@ namespace PhysX::Benchmarks
virtual void SetUp([[maybe_unused]] const ::benchmark::State &state) override
{
PhysXBaseBenchmarkFixture::SetUpInternal();
//need to get the Physics::System to be able to spawn the rigid bodies
m_system = AZ::Interface<Physics::System>::Get();
}
virtual void TearDown([[maybe_unused]] const ::benchmark::State &state) override
@@ -218,8 +214,6 @@ namespace PhysX::Benchmarks
return sceneConfig;
}
// PhysXBaseBenchmarkFixture Interface ---------
Physics::System *m_system;
};
//! BM_Joints_AtRest - This test will spawn the requested number of joints
@@ -237,7 +231,7 @@ namespace PhysX::Benchmarks
return position;
};
AZStd::vector<Utils::JointGroup> joinGroups = Utils::CreateJoints(aznumeric_cast<int>(state.range(0)), m_system, m_defaultScene,
AZStd::vector<Utils::JointGroup> joinGroups = Utils::CreateJoints(aznumeric_cast<int>(state.range(0)), m_defaultScene,
&parentPosGenerator, &childPosGenerator);
//setup the sub tick tracker
@@ -260,6 +254,11 @@ namespace PhysX::Benchmarks
}
subTickTracker.Stop();
for (const auto& jointGroup : joinGroups)
{
m_defaultScene->RemoveJoint(jointGroup.m_jointHandle);
}
//sort the frame times and get the P50, P90, P99 percentiles
Utils::ReportFramePercentileCounters(state, tickTimes, subTickTracker.GetSubTickTimes());
Utils::ReportFrameStandardDeviationAndMeanCounters(state, tickTimes, subTickTracker.GetSubTickTimes());
@@ -287,7 +286,7 @@ namespace PhysX::Benchmarks
return Utils::TwistLimits(JointConstants::JointSettings::SwingingJointUpperLimit, JointConstants::JointSettings::SwingingJointLowerLimit);
};
AZStd::vector<Utils::JointGroup> joinGroups = Utils::CreateJoints(aznumeric_cast<int>(state.range(0)), m_system, m_defaultScene,
AZStd::vector<Utils::JointGroup> joinGroups = Utils::CreateJoints(aznumeric_cast<int>(state.range(0)), m_defaultScene,
&parentPosGenerator, &childPosGenerator, &twistGenerator);
//setup the sub tick tracker
@@ -326,6 +325,11 @@ namespace PhysX::Benchmarks
}
subTickTracker.Stop();
for (const auto& jointGroup : joinGroups)
{
m_defaultScene->RemoveJoint(jointGroup.m_jointHandle);
}
//sort the frame times and get the P50, P90, P99 percentiles
Utils::ReportFramePercentileCounters(state, tickTimes, subTickTracker.GetSubTickTimes());
Utils::ReportFrameStandardDeviationAndMeanCounters(state, tickTimes, subTickTracker.GetSubTickTimes());
@@ -370,17 +374,18 @@ namespace PhysX::Benchmarks
snakeRigidBodies = Utils::GetRigidBodiesFromHandles(m_defaultScene, snakeRigidBodyHandles);
//build the snake
AZStd::vector<AZStd::shared_ptr<Physics::Joint>> joints;
AZStd::shared_ptr <PhysX::D6JointLimitConfiguration> config = AZStd::make_shared<D6JointLimitConfiguration>();
config->m_twistLimitUpper = JointConstants::CreateJointDefaults::UpperLimit;
config->m_twistLimitLower = JointConstants::CreateJointDefaults::LowerLimit;
config->m_swingLimitY = 1.0f;
config->m_swingLimitZ = 1.0f;
AZStd::vector<AzPhysics::JointHandle> jointHandles;
PhysX::D6JointLimitConfiguration config;
config.m_twistLimitUpper = JointConstants::CreateJointDefaults::UpperLimit;
config.m_twistLimitLower = JointConstants::CreateJointDefaults::LowerLimit;
config.m_swingLimitY = 1.0f;
config.m_swingLimitZ = 1.0f;
//build the head
joints.emplace_back(m_system->CreateJoint(config, snakeRigidBodies[0], snakeHead));
jointHandles.emplace_back(m_defaultScene->AddJoint(&config, snakeRigidBodies[0]->m_bodyHandle, snakeHead->m_bodyHandle));
for (size_t i = 0; (i+1) < snakeRigidBodies.size(); i++)
{
joints.emplace_back(m_system->CreateJoint(config, snakeRigidBodies[i + 1], snakeRigidBodies[i]));
jointHandles.emplace_back(
m_defaultScene->AddJoint(&config, snakeRigidBodies[i + 1]->m_bodyHandle, snakeRigidBodies[i]->m_bodyHandle));
}
//setup the sub tick tracker
@@ -404,6 +409,10 @@ namespace PhysX::Benchmarks
subTickTracker.Stop();
m_defaultScene->RemoveSimulatedBodies(snakeRigidBodyHandles);
for (const auto& jointHandle : jointHandles)
{
m_defaultScene->RemoveJoint(jointHandle);
}
snakeRigidBodyHandles.clear();
//sort the frame times and get the P50, P90, P99 percentiles
@@ -111,7 +111,7 @@ namespace PhysX
};
class GenericPhysicsInterfaceTest
: protected GenericPhysicsFixture
: public GenericPhysicsFixture
, public testing::Test
{
public:
+98 -10
View File
@@ -18,17 +18,18 @@
#include <BoxColliderComponent.h>
#include <RigidBodyComponent.h>
#include <Joint.h>
#include <JointComponent.h>
#include <BallJointComponent.h>
#include <FixedJointComponent.h>
#include <HingeJointComponent.h>
#include <PhysX/Joint/Configuration/PhysXJointConfiguration.h>
#include <AzCore/Component/TransformBus.h>
#include <AzFramework/Components/TransformComponent.h>
#include <AzFramework/Physics/ShapeConfiguration.h>
#include <AzFramework/Physics/SystemBus.h>
#include <AzFramework/Physics/Configuration/RigidBodyConfiguration.h>
#include <AzFramework/Physics/PhysicsSystem.h>
namespace PhysX
{
@@ -38,8 +39,9 @@ namespace PhysX
AZStd::unique_ptr<AZ::Entity> AddBodyColliderEntity( AzPhysics::SceneHandle sceneHandle,
const AZ::Vector3& position,
const AZ::Vector3& initialLinearVelocity,
AZStd::shared_ptr<GenericJointConfiguration> jointConfig = nullptr,
AZStd::shared_ptr<GenericJointLimitsConfiguration> jointLimitsConfig = nullptr)
AZStd::shared_ptr<JointComponentConfiguration> jointConfig = nullptr,
AZStd::shared_ptr<JointGenericProperties> jointGenericProperties = nullptr,
AZStd::shared_ptr<JointLimitProperties> jointLimitProperties = nullptr)
{
const char* entityName = "testEntity";
auto entity = AZStd::make_unique<AZ::Entity>(entityName);
@@ -68,10 +70,12 @@ namespace PhysX
{
jointConfig->m_followerEntity = entity->GetId();
GenericJointLimitsConfiguration defaultJointLimitsConfig;
JointGenericProperties defaultJointGenericProperties;
JointLimitProperties defaultJointLimitProperties;
entity->CreateComponent<JointComponentType>(
*jointConfig,
(jointLimitsConfig)? *jointLimitsConfig : defaultJointLimitsConfig);
(jointGenericProperties)? *jointGenericProperties : defaultJointGenericProperties,
(jointLimitProperties)? *jointLimitProperties : defaultJointLimitProperties);
}
entity->Init();
@@ -114,7 +118,7 @@ namespace PhysX
leadPosition,
leadInitialLinearVelocity);
auto jointConfig = AZStd::make_shared<GenericJointConfiguration>();
auto jointConfig = AZStd::make_shared<JointComponentConfiguration>();
jointConfig->m_leadEntity = leadEntity->GetId();
jointConfig->m_localTransformFromFollower = jointLocalTransform;
@@ -150,17 +154,18 @@ namespace PhysX
leadPosition,
leadInitialLinearVelocity);
auto jointConfig = AZStd::make_shared<GenericJointConfiguration>();
auto jointConfig = AZStd::make_shared<JointComponentConfiguration>();
jointConfig->m_leadEntity = leadEntity->GetId();
jointConfig->m_localTransformFromFollower = jointLocalTransform;
auto jointLimits = AZStd::make_shared <GenericJointLimitsConfiguration>();
auto jointLimits = AZStd::make_shared <JointLimitProperties>();
jointLimits->m_isLimited = false;
auto followerEntity = AddBodyColliderEntity<HingeJointComponent>(m_testSceneHandle,
followerPosition,
followerInitialLinearVelocity,
jointConfig,
nullptr,
jointLimits);
const AZ::Vector3 followerEndPosition = RunJointTest(m_defaultScene, followerEntity->GetId());
@@ -191,21 +196,104 @@ namespace PhysX
leadPosition,
leadInitialLinearVelocity);
auto jointConfig = AZStd::make_shared<GenericJointConfiguration>();
auto jointConfig = AZStd::make_shared<JointComponentConfiguration>();
jointConfig->m_leadEntity = leadEntity->GetId();
jointConfig->m_localTransformFromFollower = jointLocalTransform;
auto jointLimits = AZStd::make_shared <GenericJointLimitsConfiguration>();
auto jointLimits = AZStd::make_shared <JointLimitProperties>();
jointLimits->m_isLimited = false;
auto followerEntity = AddBodyColliderEntity<BallJointComponent>(m_testSceneHandle,
followerPosition,
followerInitialLinearVelocity,
jointConfig,
nullptr,
jointLimits);
const AZ::Vector3 followerEndPosition = RunJointTest(m_defaultScene, followerEntity->GetId());
EXPECT_TRUE(followerEndPosition.GetZ() > followerPosition.GetZ());
}
// for some reason TYPED_TEST_CASE with the fixture is not working on Android + Linux
#ifdef ENABLE_JOINTS_TYPED_TEST_CASE
template<class JointConfigurationType>
class PhysXJointsApiTest : public PhysX::GenericPhysicsInterfaceTest
{
public:
void SetUp() override
{
PhysX::GenericPhysicsInterfaceTest::SetUp();
if (auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get())
{
AzPhysics::RigidBodyConfiguration parentConfiguration;
AzPhysics::RigidBodyConfiguration childConfiguration;
auto colliderConfig = AZStd::make_shared<Physics::ColliderConfiguration>();
auto shapeConfiguration = AZStd::make_shared<Physics::BoxShapeConfiguration>(AZ::Vector3(1.0f, 1.0f, 1.0f));
parentConfiguration.m_colliderAndShapeData = AzPhysics::ShapeColliderPair(colliderConfig, shapeConfiguration);
childConfiguration.m_colliderAndShapeData = AzPhysics::ShapeColliderPair(colliderConfig, shapeConfiguration);
// Put the child body a bit to the lower side of X to avoid it colliding with parent
childConfiguration.m_position.SetX(childConfiguration.m_position.GetX() - 2.0f);
m_childInitialPos = childConfiguration.m_position;
parentConfiguration.m_initialLinearVelocity.SetX(10.0f);
m_parentBodyHandle = sceneInterface->AddSimulatedBody(m_testSceneHandle, &parentConfiguration);
m_childBodyHandle = sceneInterface->AddSimulatedBody(m_testSceneHandle, &childConfiguration);
}
}
void TearDown() override
{
if (auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get())
{
sceneInterface->RemoveSimulatedBody(m_testSceneHandle, m_parentBodyHandle);
sceneInterface->RemoveSimulatedBody(m_testSceneHandle, m_childBodyHandle);
}
PhysX::GenericPhysicsInterfaceTest::TearDown();
}
AzPhysics::SimulatedBodyHandle m_parentBodyHandle = AzPhysics::InvalidJointHandle;
AzPhysics::SimulatedBodyHandle m_childBodyHandle = AzPhysics::InvalidJointHandle;
AZ::Vector3 m_childInitialPos;
};
using JointTypes = testing::Types<
D6JointLimitConfiguration,
FixedJointConfiguration,
BallJointConfiguration,
HingeJointConfiguration>;
TYPED_TEST_CASE(PhysXJointsApiTest, JointTypes);
TYPED_TEST(PhysXJointsApiTest, Joint_ChildFollowsParent)
{
TypeParam jointConfiguration;
AzPhysics::JointHandle jointHandle = AzPhysics::InvalidJointHandle;
if (auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get())
{
jointHandle = sceneInterface->AddJoint(m_testSceneHandle, &jointConfiguration, m_parentBodyHandle, m_childBodyHandle);
}
EXPECT_NE(jointHandle, AzPhysics::InvalidJointHandle);
// run physics to trigger the the move of parent body
TestUtils::UpdateScene(m_testSceneHandle, AzPhysics::SystemConfiguration::DefaultFixedTimestep, 1);
AZ::Vector3 childCurrentPos;
if (auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get())
{
auto* childBody = sceneInterface->GetSimulatedBodyFromHandle(m_testSceneHandle, m_childBodyHandle);
childCurrentPos = childBody->GetPosition();
}
EXPECT_GT(childCurrentPos.GetX(), m_childInitialPos.GetX());
}
#endif // ENABLE_JOINTS_TYPED_TEST_CASE
}
+88 -88
View File
@@ -4,7 +4,7 @@
<Class name="AZStd::string" field="name" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
</Class>
<Class name="AZStd::vector" field="nodes" type="{023260FD-3D32-570B-A75E-4099359BE960}">
<Class name="RagdollNodeConfiguration" field="element" version="4" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RagdollNodeConfiguration" field="element" version="5" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RigidBodyConfiguration" field="BaseClass1" version="2" type="{ACFA8900-8530-4744-AF00-AA533C868A8E}">
<Class name="WorldBodyConfiguration" field="BaseClass1" version="1" type="{6EEB377C-DC60-4E10-AF12-9626C0763B2D}">
<Class name="AZStd::string" field="name" value="C_pelvis_JNT" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
@@ -27,9 +27,9 @@
<Class name="Matrix3x3" field="Inertia tensor" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000" type="{15A4332F-7C3F-4A58-AC35-50E1CE53FB9C}"/>
<Class name="float" field="Maximum Angular Velocity" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
</Class>
<Class name="AZStd::shared_ptr" field="JointLimit" type="{F5C4DCF0-277D-5536-921B-A6A4AEEF7226}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{90C5C23D-16C0-4F23-AD50-A190E402388E}">
<Class name="JointLimitConfiguration" field="BaseClass1" version="1" type="{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}">
<Class name="AZStd::shared_ptr" field="JointConfig" type="{B7A3D04D-1ECC-5D84-8C93-B4C9E4F8F6B8}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{88E067B4-21E8-4FFA-9142-6C52605B704C}">
<Class name="JointConfiguration" field="BaseClass1" version="1" type="{DF91D39A-4901-48C4-9159-93FD2ACA5252}">
<Class name="Quaternion" field="ParentLocalRotation" value="-0.0391054 -0.7143280 0.0391054 0.6976625" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
<Class name="Vector3" field="ParentLocalPosition" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Quaternion" field="ChildLocalRotation" value="0.0000000 -0.0117843 0.0553034 0.9984280" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
@@ -42,7 +42,7 @@
</Class>
</Class>
</Class>
<Class name="RagdollNodeConfiguration" field="element" version="4" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RagdollNodeConfiguration" field="element" version="5" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RigidBodyConfiguration" field="BaseClass1" version="2" type="{ACFA8900-8530-4744-AF00-AA533C868A8E}">
<Class name="WorldBodyConfiguration" field="BaseClass1" version="1" type="{6EEB377C-DC60-4E10-AF12-9626C0763B2D}">
<Class name="AZStd::string" field="name" value="L_arm_JNT" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
@@ -65,9 +65,9 @@
<Class name="Matrix3x3" field="Inertia tensor" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000" type="{15A4332F-7C3F-4A58-AC35-50E1CE53FB9C}"/>
<Class name="float" field="Maximum Angular Velocity" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
</Class>
<Class name="AZStd::shared_ptr" field="JointLimit" type="{F5C4DCF0-277D-5536-921B-A6A4AEEF7226}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{90C5C23D-16C0-4F23-AD50-A190E402388E}">
<Class name="JointLimitConfiguration" field="BaseClass1" version="1" type="{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}">
<Class name="AZStd::shared_ptr" field="JointConfig" type="{B7A3D04D-1ECC-5D84-8C93-B4C9E4F8F6B8}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{88E067B4-21E8-4FFA-9142-6C52605B704C}">
<Class name="JointConfiguration" field="BaseClass1" version="1" type="{DF91D39A-4901-48C4-9159-93FD2ACA5252}">
<Class name="Quaternion" field="ParentLocalRotation" value="0.0288827 -0.3743261 -0.0537340 0.9254376" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
<Class name="Vector3" field="ParentLocalPosition" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Quaternion" field="ChildLocalRotation" value="0.0000000 -0.0054825 -0.0006252 1.0001229" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
@@ -80,7 +80,7 @@
</Class>
</Class>
</Class>
<Class name="RagdollNodeConfiguration" field="element" version="4" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RagdollNodeConfiguration" field="element" version="5" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RigidBodyConfiguration" field="BaseClass1" version="2" type="{ACFA8900-8530-4744-AF00-AA533C868A8E}">
<Class name="WorldBodyConfiguration" field="BaseClass1" version="1" type="{6EEB377C-DC60-4E10-AF12-9626C0763B2D}">
<Class name="AZStd::string" field="name" value="C_spine_01_JNT" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
@@ -103,9 +103,9 @@
<Class name="Matrix3x3" field="Inertia tensor" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000" type="{15A4332F-7C3F-4A58-AC35-50E1CE53FB9C}"/>
<Class name="float" field="Maximum Angular Velocity" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
</Class>
<Class name="AZStd::shared_ptr" field="JointLimit" type="{F5C4DCF0-277D-5536-921B-A6A4AEEF7226}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{90C5C23D-16C0-4F23-AD50-A190E402388E}">
<Class name="JointLimitConfiguration" field="BaseClass1" version="1" type="{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}">
<Class name="AZStd::shared_ptr" field="JointConfig" type="{B7A3D04D-1ECC-5D84-8C93-B4C9E4F8F6B8}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{88E067B4-21E8-4FFA-9142-6C52605B704C}">
<Class name="JointConfiguration" field="BaseClass1" version="1" type="{DF91D39A-4901-48C4-9159-93FD2ACA5252}">
<Class name="Quaternion" field="ParentLocalRotation" value="0.0000000 -0.0045330 0.0049514 1.0000752" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
<Class name="Vector3" field="ParentLocalPosition" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Quaternion" field="ChildLocalRotation" value="0.0000000 -0.0045330 0.0049514 1.0000751" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
@@ -118,7 +118,7 @@
</Class>
</Class>
</Class>
<Class name="RagdollNodeConfiguration" field="element" version="4" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RagdollNodeConfiguration" field="element" version="5" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RigidBodyConfiguration" field="BaseClass1" version="2" type="{ACFA8900-8530-4744-AF00-AA533C868A8E}">
<Class name="WorldBodyConfiguration" field="BaseClass1" version="1" type="{6EEB377C-DC60-4E10-AF12-9626C0763B2D}">
<Class name="AZStd::string" field="name" value="C_spine_02_JNT" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
@@ -141,9 +141,9 @@
<Class name="Matrix3x3" field="Inertia tensor" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000" type="{15A4332F-7C3F-4A58-AC35-50E1CE53FB9C}"/>
<Class name="float" field="Maximum Angular Velocity" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
</Class>
<Class name="AZStd::shared_ptr" field="JointLimit" type="{F5C4DCF0-277D-5536-921B-A6A4AEEF7226}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{90C5C23D-16C0-4F23-AD50-A190E402388E}">
<Class name="JointLimitConfiguration" field="BaseClass1" version="1" type="{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}">
<Class name="AZStd::shared_ptr" field="JointConfig" type="{B7A3D04D-1ECC-5D84-8C93-B4C9E4F8F6B8}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{88E067B4-21E8-4FFA-9142-6C52605B704C}">
<Class name="JointConfiguration" field="BaseClass1" version="1" type="{DF91D39A-4901-48C4-9159-93FD2ACA5252}">
<Class name="Quaternion" field="ParentLocalRotation" value="0.0000000 0.0000000 -0.0000000 1.0001725" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
<Class name="Vector3" field="ParentLocalPosition" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Quaternion" field="ChildLocalRotation" value="0.0000000 0.0000000 -0.0000000 1.0001724" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
@@ -156,7 +156,7 @@
</Class>
</Class>
</Class>
<Class name="RagdollNodeConfiguration" field="element" version="4" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RagdollNodeConfiguration" field="element" version="5" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RigidBodyConfiguration" field="BaseClass1" version="2" type="{ACFA8900-8530-4744-AF00-AA533C868A8E}">
<Class name="WorldBodyConfiguration" field="BaseClass1" version="1" type="{6EEB377C-DC60-4E10-AF12-9626C0763B2D}">
<Class name="AZStd::string" field="name" value="C_spine_03_JNT" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
@@ -179,9 +179,9 @@
<Class name="Matrix3x3" field="Inertia tensor" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000" type="{15A4332F-7C3F-4A58-AC35-50E1CE53FB9C}"/>
<Class name="float" field="Maximum Angular Velocity" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
</Class>
<Class name="AZStd::shared_ptr" field="JointLimit" type="{F5C4DCF0-277D-5536-921B-A6A4AEEF7226}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{90C5C23D-16C0-4F23-AD50-A190E402388E}">
<Class name="JointLimitConfiguration" field="BaseClass1" version="1" type="{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}">
<Class name="AZStd::shared_ptr" field="JointConfig" type="{B7A3D04D-1ECC-5D84-8C93-B4C9E4F8F6B8}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{88E067B4-21E8-4FFA-9142-6C52605B704C}">
<Class name="JointConfiguration" field="BaseClass1" version="1" type="{DF91D39A-4901-48C4-9159-93FD2ACA5252}">
<Class name="Quaternion" field="ParentLocalRotation" value="0.0000000 0.0000000 0.0000000 1.0002152" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
<Class name="Vector3" field="ParentLocalPosition" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Quaternion" field="ChildLocalRotation" value="0.0000000 0.0000000 0.0000000 1.0002151" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
@@ -194,7 +194,7 @@
</Class>
</Class>
</Class>
<Class name="RagdollNodeConfiguration" field="element" version="4" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RagdollNodeConfiguration" field="element" version="5" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RigidBodyConfiguration" field="BaseClass1" version="2" type="{ACFA8900-8530-4744-AF00-AA533C868A8E}">
<Class name="WorldBodyConfiguration" field="BaseClass1" version="1" type="{6EEB377C-DC60-4E10-AF12-9626C0763B2D}">
<Class name="AZStd::string" field="name" value="C_spine_04_JNT" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
@@ -217,9 +217,9 @@
<Class name="Matrix3x3" field="Inertia tensor" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000" type="{15A4332F-7C3F-4A58-AC35-50E1CE53FB9C}"/>
<Class name="float" field="Maximum Angular Velocity" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
</Class>
<Class name="AZStd::shared_ptr" field="JointLimit" type="{F5C4DCF0-277D-5536-921B-A6A4AEEF7226}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{90C5C23D-16C0-4F23-AD50-A190E402388E}">
<Class name="JointLimitConfiguration" field="BaseClass1" version="1" type="{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}">
<Class name="AZStd::shared_ptr" field="JointConfig" type="{B7A3D04D-1ECC-5D84-8C93-B4C9E4F8F6B8}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{88E067B4-21E8-4FFA-9142-6C52605B704C}">
<Class name="JointConfiguration" field="BaseClass1" version="1" type="{DF91D39A-4901-48C4-9159-93FD2ACA5252}">
<Class name="Quaternion" field="ParentLocalRotation" value="0.0000000 -0.0004615 -0.1719919 0.9851767" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
<Class name="Vector3" field="ParentLocalPosition" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Quaternion" field="ChildLocalRotation" value="0.0000000 -0.0004615 -0.1719919 0.9851766" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
@@ -232,7 +232,7 @@
</Class>
</Class>
</Class>
<Class name="RagdollNodeConfiguration" field="element" version="4" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RagdollNodeConfiguration" field="element" version="5" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RigidBodyConfiguration" field="BaseClass1" version="2" type="{ACFA8900-8530-4744-AF00-AA533C868A8E}">
<Class name="WorldBodyConfiguration" field="BaseClass1" version="1" type="{6EEB377C-DC60-4E10-AF12-9626C0763B2D}">
<Class name="AZStd::string" field="name" value="L_clavicle_JNT" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
@@ -255,9 +255,9 @@
<Class name="Matrix3x3" field="Inertia tensor" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000" type="{15A4332F-7C3F-4A58-AC35-50E1CE53FB9C}"/>
<Class name="float" field="Maximum Angular Velocity" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
</Class>
<Class name="AZStd::shared_ptr" field="JointLimit" type="{F5C4DCF0-277D-5536-921B-A6A4AEEF7226}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{90C5C23D-16C0-4F23-AD50-A190E402388E}">
<Class name="JointLimitConfiguration" field="BaseClass1" version="1" type="{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}">
<Class name="AZStd::shared_ptr" field="JointConfig" type="{B7A3D04D-1ECC-5D84-8C93-B4C9E4F8F6B8}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{88E067B4-21E8-4FFA-9142-6C52605B704C}">
<Class name="JointConfiguration" field="BaseClass1" version="1" type="{DF91D39A-4901-48C4-9159-93FD2ACA5252}">
<Class name="Quaternion" field="ParentLocalRotation" value="-0.0195780 -0.7155011 0.0194289 0.6982983" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
<Class name="Vector3" field="ParentLocalPosition" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Quaternion" field="ChildLocalRotation" value="0.0000000 -0.0135283 0.0381485 0.9993421" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
@@ -270,7 +270,7 @@
</Class>
</Class>
</Class>
<Class name="RagdollNodeConfiguration" field="element" version="4" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RagdollNodeConfiguration" field="element" version="5" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RigidBodyConfiguration" field="BaseClass1" version="2" type="{ACFA8900-8530-4744-AF00-AA533C868A8E}">
<Class name="WorldBodyConfiguration" field="BaseClass1" version="1" type="{6EEB377C-DC60-4E10-AF12-9626C0763B2D}">
<Class name="AZStd::string" field="name" value="L_wrist_JNT" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
@@ -293,9 +293,9 @@
<Class name="Matrix3x3" field="Inertia tensor" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000" type="{15A4332F-7C3F-4A58-AC35-50E1CE53FB9C}"/>
<Class name="float" field="Maximum Angular Velocity" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
</Class>
<Class name="AZStd::shared_ptr" field="JointLimit" type="{F5C4DCF0-277D-5536-921B-A6A4AEEF7226}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{90C5C23D-16C0-4F23-AD50-A190E402388E}">
<Class name="JointLimitConfiguration" field="BaseClass1" version="1" type="{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}">
<Class name="AZStd::shared_ptr" field="JointConfig" type="{B7A3D04D-1ECC-5D84-8C93-B4C9E4F8F6B8}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{88E067B4-21E8-4FFA-9142-6C52605B704C}">
<Class name="JointConfiguration" field="BaseClass1" version="1" type="{DF91D39A-4901-48C4-9159-93FD2ACA5252}">
<Class name="Quaternion" field="ParentLocalRotation" value="0.0000000 -0.0883498 0.0613066 0.9941655" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
<Class name="Vector3" field="ParentLocalPosition" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Quaternion" field="ChildLocalRotation" value="0.0000000 -0.0883498 0.0613066 0.9941654" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
@@ -308,7 +308,7 @@
</Class>
</Class>
</Class>
<Class name="RagdollNodeConfiguration" field="element" version="4" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RagdollNodeConfiguration" field="element" version="5" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RigidBodyConfiguration" field="BaseClass1" version="2" type="{ACFA8900-8530-4744-AF00-AA533C868A8E}">
<Class name="WorldBodyConfiguration" field="BaseClass1" version="1" type="{6EEB377C-DC60-4E10-AF12-9626C0763B2D}">
<Class name="AZStd::string" field="name" value="L_elbow_JNT" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
@@ -331,9 +331,9 @@
<Class name="Matrix3x3" field="Inertia tensor" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000" type="{15A4332F-7C3F-4A58-AC35-50E1CE53FB9C}"/>
<Class name="float" field="Maximum Angular Velocity" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
</Class>
<Class name="AZStd::shared_ptr" field="JointLimit" type="{F5C4DCF0-277D-5536-921B-A6A4AEEF7226}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{90C5C23D-16C0-4F23-AD50-A190E402388E}">
<Class name="JointLimitConfiguration" field="BaseClass1" version="1" type="{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}">
<Class name="AZStd::shared_ptr" field="JointConfig" type="{B7A3D04D-1ECC-5D84-8C93-B4C9E4F8F6B8}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{88E067B4-21E8-4FFA-9142-6C52605B704C}">
<Class name="JointConfiguration" field="BaseClass1" version="1" type="{DF91D39A-4901-48C4-9159-93FD2ACA5252}">
<Class name="Quaternion" field="ParentLocalRotation" value="0.0000000 0.0000000 0.6087880 0.7948525" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
<Class name="Vector3" field="ParentLocalPosition" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Quaternion" field="ChildLocalRotation" value="0.0000000 -0.0000001 0.0000000 1.0002161" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
@@ -346,7 +346,7 @@
</Class>
</Class>
</Class>
<Class name="RagdollNodeConfiguration" field="element" version="4" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RagdollNodeConfiguration" field="element" version="5" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RigidBodyConfiguration" field="BaseClass1" version="2" type="{ACFA8900-8530-4744-AF00-AA533C868A8E}">
<Class name="WorldBodyConfiguration" field="BaseClass1" version="1" type="{6EEB377C-DC60-4E10-AF12-9626C0763B2D}">
<Class name="AZStd::string" field="name" value="C_neck_01_JNT" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
@@ -369,9 +369,9 @@
<Class name="Matrix3x3" field="Inertia tensor" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000" type="{15A4332F-7C3F-4A58-AC35-50E1CE53FB9C}"/>
<Class name="float" field="Maximum Angular Velocity" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
</Class>
<Class name="AZStd::shared_ptr" field="JointLimit" type="{F5C4DCF0-277D-5536-921B-A6A4AEEF7226}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{90C5C23D-16C0-4F23-AD50-A190E402388E}">
<Class name="JointLimitConfiguration" field="BaseClass1" version="1" type="{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}">
<Class name="AZStd::shared_ptr" field="JointConfig" type="{B7A3D04D-1ECC-5D84-8C93-B4C9E4F8F6B8}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{88E067B4-21E8-4FFA-9142-6C52605B704C}">
<Class name="JointConfiguration" field="BaseClass1" version="1" type="{DF91D39A-4901-48C4-9159-93FD2ACA5252}">
<Class name="Quaternion" field="ParentLocalRotation" value="0.0000000 -0.0000000 0.0967176 0.9951238" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
<Class name="Vector3" field="ParentLocalPosition" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Quaternion" field="ChildLocalRotation" value="0.0000000 -0.0000000 0.0000000 0.9998127" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
@@ -384,7 +384,7 @@
</Class>
</Class>
</Class>
<Class name="RagdollNodeConfiguration" field="element" version="4" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RagdollNodeConfiguration" field="element" version="5" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RigidBodyConfiguration" field="BaseClass1" version="2" type="{ACFA8900-8530-4744-AF00-AA533C868A8E}">
<Class name="WorldBodyConfiguration" field="BaseClass1" version="1" type="{6EEB377C-DC60-4E10-AF12-9626C0763B2D}">
<Class name="AZStd::string" field="name" value="C_head_JNT" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
@@ -407,9 +407,9 @@
<Class name="Matrix3x3" field="Inertia tensor" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000" type="{15A4332F-7C3F-4A58-AC35-50E1CE53FB9C}"/>
<Class name="float" field="Maximum Angular Velocity" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
</Class>
<Class name="AZStd::shared_ptr" field="JointLimit" type="{F5C4DCF0-277D-5536-921B-A6A4AEEF7226}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{90C5C23D-16C0-4F23-AD50-A190E402388E}">
<Class name="JointLimitConfiguration" field="BaseClass1" version="1" type="{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}">
<Class name="AZStd::shared_ptr" field="JointConfig" type="{B7A3D04D-1ECC-5D84-8C93-B4C9E4F8F6B8}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{88E067B4-21E8-4FFA-9142-6C52605B704C}">
<Class name="JointConfiguration" field="BaseClass1" version="1" type="{DF91D39A-4901-48C4-9159-93FD2ACA5252}">
<Class name="Quaternion" field="ParentLocalRotation" value="0.0000000 -0.0029691 0.5012505 0.8653531" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
<Class name="Vector3" field="ParentLocalPosition" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Quaternion" field="ChildLocalRotation" value="0.0000000 -0.0029691 0.5012505 0.8653531" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
@@ -422,7 +422,7 @@
</Class>
</Class>
</Class>
<Class name="RagdollNodeConfiguration" field="element" version="4" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RagdollNodeConfiguration" field="element" version="5" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RigidBodyConfiguration" field="BaseClass1" version="2" type="{ACFA8900-8530-4744-AF00-AA533C868A8E}">
<Class name="WorldBodyConfiguration" field="BaseClass1" version="1" type="{6EEB377C-DC60-4E10-AF12-9626C0763B2D}">
<Class name="AZStd::string" field="name" value="C_neck_02_JNT" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
@@ -445,9 +445,9 @@
<Class name="Matrix3x3" field="Inertia tensor" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000" type="{15A4332F-7C3F-4A58-AC35-50E1CE53FB9C}"/>
<Class name="float" field="Maximum Angular Velocity" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
</Class>
<Class name="AZStd::shared_ptr" field="JointLimit" type="{F5C4DCF0-277D-5536-921B-A6A4AEEF7226}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{90C5C23D-16C0-4F23-AD50-A190E402388E}">
<Class name="JointLimitConfiguration" field="BaseClass1" version="1" type="{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}">
<Class name="AZStd::shared_ptr" field="JointConfig" type="{B7A3D04D-1ECC-5D84-8C93-B4C9E4F8F6B8}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{88E067B4-21E8-4FFA-9142-6C52605B704C}">
<Class name="JointConfiguration" field="BaseClass1" version="1" type="{DF91D39A-4901-48C4-9159-93FD2ACA5252}">
<Class name="Quaternion" field="ParentLocalRotation" value="0.0000000 0.0000000 0.0028993 1.0001502" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
<Class name="Vector3" field="ParentLocalPosition" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Quaternion" field="ChildLocalRotation" value="-0.0000000 0.0000000 0.0028993 1.0001502" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
@@ -460,7 +460,7 @@
</Class>
</Class>
</Class>
<Class name="RagdollNodeConfiguration" field="element" version="4" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RagdollNodeConfiguration" field="element" version="5" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RigidBodyConfiguration" field="BaseClass1" version="2" type="{ACFA8900-8530-4744-AF00-AA533C868A8E}">
<Class name="WorldBodyConfiguration" field="BaseClass1" version="1" type="{6EEB377C-DC60-4E10-AF12-9626C0763B2D}">
<Class name="AZStd::string" field="name" value="R_clavicle_JNT" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
@@ -483,9 +483,9 @@
<Class name="Matrix3x3" field="Inertia tensor" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000" type="{15A4332F-7C3F-4A58-AC35-50E1CE53FB9C}"/>
<Class name="float" field="Maximum Angular Velocity" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
</Class>
<Class name="AZStd::shared_ptr" field="JointLimit" type="{F5C4DCF0-277D-5536-921B-A6A4AEEF7226}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{90C5C23D-16C0-4F23-AD50-A190E402388E}">
<Class name="JointLimitConfiguration" field="BaseClass1" version="1" type="{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}">
<Class name="AZStd::shared_ptr" field="JointConfig" type="{B7A3D04D-1ECC-5D84-8C93-B4C9E4F8F6B8}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{88E067B4-21E8-4FFA-9142-6C52605B704C}">
<Class name="JointConfiguration" field="BaseClass1" version="1" type="{DF91D39A-4901-48C4-9159-93FD2ACA5252}">
<Class name="Quaternion" field="ParentLocalRotation" value="0.0195778 0.7154908 0.0194290 0.6983082" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
<Class name="Vector3" field="ParentLocalPosition" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Quaternion" field="ChildLocalRotation" value="0.0135140 -0.0000000 -0.9993417 0.0381484" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
@@ -498,7 +498,7 @@
</Class>
</Class>
</Class>
<Class name="RagdollNodeConfiguration" field="element" version="4" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RagdollNodeConfiguration" field="element" version="5" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RigidBodyConfiguration" field="BaseClass1" version="2" type="{ACFA8900-8530-4744-AF00-AA533C868A8E}">
<Class name="WorldBodyConfiguration" field="BaseClass1" version="1" type="{6EEB377C-DC60-4E10-AF12-9626C0763B2D}">
<Class name="AZStd::string" field="name" value="R_wrist_JNT" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
@@ -521,9 +521,9 @@
<Class name="Matrix3x3" field="Inertia tensor" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000" type="{15A4332F-7C3F-4A58-AC35-50E1CE53FB9C}"/>
<Class name="float" field="Maximum Angular Velocity" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
</Class>
<Class name="AZStd::shared_ptr" field="JointLimit" type="{F5C4DCF0-277D-5536-921B-A6A4AEEF7226}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{90C5C23D-16C0-4F23-AD50-A190E402388E}">
<Class name="JointLimitConfiguration" field="BaseClass1" version="1" type="{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}">
<Class name="AZStd::shared_ptr" field="JointConfig" type="{B7A3D04D-1ECC-5D84-8C93-B4C9E4F8F6B8}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{88E067B4-21E8-4FFA-9142-6C52605B704C}">
<Class name="JointConfiguration" field="BaseClass1" version="1" type="{DF91D39A-4901-48C4-9159-93FD2ACA5252}">
<Class name="Quaternion" field="ParentLocalRotation" value="0.0883390 0.0000000 -0.9943419 0.0613376" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
<Class name="Vector3" field="ParentLocalPosition" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Quaternion" field="ChildLocalRotation" value="0.0883390 -0.0000000 -0.9943417 0.0613376" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
@@ -536,7 +536,7 @@
</Class>
</Class>
</Class>
<Class name="RagdollNodeConfiguration" field="element" version="4" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RagdollNodeConfiguration" field="element" version="5" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RigidBodyConfiguration" field="BaseClass1" version="2" type="{ACFA8900-8530-4744-AF00-AA533C868A8E}">
<Class name="WorldBodyConfiguration" field="BaseClass1" version="1" type="{6EEB377C-DC60-4E10-AF12-9626C0763B2D}">
<Class name="AZStd::string" field="name" value="R_arm_JNT" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
@@ -559,9 +559,9 @@
<Class name="Matrix3x3" field="Inertia tensor" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000" type="{15A4332F-7C3F-4A58-AC35-50E1CE53FB9C}"/>
<Class name="float" field="Maximum Angular Velocity" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
</Class>
<Class name="AZStd::shared_ptr" field="JointLimit" type="{F5C4DCF0-277D-5536-921B-A6A4AEEF7226}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{90C5C23D-16C0-4F23-AD50-A190E402388E}">
<Class name="JointLimitConfiguration" field="BaseClass1" version="1" type="{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}">
<Class name="AZStd::shared_ptr" field="JointConfig" type="{B7A3D04D-1ECC-5D84-8C93-B4C9E4F8F6B8}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{88E067B4-21E8-4FFA-9142-6C52605B704C}">
<Class name="JointConfiguration" field="BaseClass1" version="1" type="{DF91D39A-4901-48C4-9159-93FD2ACA5252}">
<Class name="Quaternion" field="ParentLocalRotation" value="0.3743524 0.0288702 -0.9254135 -0.0538333" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
<Class name="Vector3" field="ParentLocalPosition" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Quaternion" field="ChildLocalRotation" value="0.0024797 -0.0000000 -1.0001022 0.0071253" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
@@ -574,7 +574,7 @@
</Class>
</Class>
</Class>
<Class name="RagdollNodeConfiguration" field="element" version="4" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RagdollNodeConfiguration" field="element" version="5" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RigidBodyConfiguration" field="BaseClass1" version="2" type="{ACFA8900-8530-4744-AF00-AA533C868A8E}">
<Class name="WorldBodyConfiguration" field="BaseClass1" version="1" type="{6EEB377C-DC60-4E10-AF12-9626C0763B2D}">
<Class name="AZStd::string" field="name" value="R_elbow_JNT" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
@@ -597,9 +597,9 @@
<Class name="Matrix3x3" field="Inertia tensor" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000" type="{15A4332F-7C3F-4A58-AC35-50E1CE53FB9C}"/>
<Class name="float" field="Maximum Angular Velocity" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
</Class>
<Class name="AZStd::shared_ptr" field="JointLimit" type="{F5C4DCF0-277D-5536-921B-A6A4AEEF7226}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{90C5C23D-16C0-4F23-AD50-A190E402388E}">
<Class name="JointLimitConfiguration" field="BaseClass1" version="1" type="{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}">
<Class name="AZStd::shared_ptr" field="JointConfig" type="{B7A3D04D-1ECC-5D84-8C93-B4C9E4F8F6B8}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{88E067B4-21E8-4FFA-9142-6C52605B704C}">
<Class name="JointConfiguration" field="BaseClass1" version="1" type="{DF91D39A-4901-48C4-9159-93FD2ACA5252}">
<Class name="Quaternion" field="ParentLocalRotation" value="0.0000000 -0.0000000 0.8197944 -0.5787863" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
<Class name="Vector3" field="ParentLocalPosition" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Quaternion" field="ChildLocalRotation" value="-0.0000031 0.0000000 1.0002232 0.0000017" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
@@ -612,7 +612,7 @@
</Class>
</Class>
</Class>
<Class name="RagdollNodeConfiguration" field="element" version="4" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RagdollNodeConfiguration" field="element" version="5" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RigidBodyConfiguration" field="BaseClass1" version="2" type="{ACFA8900-8530-4744-AF00-AA533C868A8E}">
<Class name="WorldBodyConfiguration" field="BaseClass1" version="1" type="{6EEB377C-DC60-4E10-AF12-9626C0763B2D}">
<Class name="AZStd::string" field="name" value="L_leg_JNT" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
@@ -635,9 +635,9 @@
<Class name="Matrix3x3" field="Inertia tensor" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000" type="{15A4332F-7C3F-4A58-AC35-50E1CE53FB9C}"/>
<Class name="float" field="Maximum Angular Velocity" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
</Class>
<Class name="AZStd::shared_ptr" field="JointLimit" type="{F5C4DCF0-277D-5536-921B-A6A4AEEF7226}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{90C5C23D-16C0-4F23-AD50-A190E402388E}">
<Class name="JointLimitConfiguration" field="BaseClass1" version="1" type="{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}">
<Class name="AZStd::shared_ptr" field="JointConfig" type="{B7A3D04D-1ECC-5D84-8C93-B4C9E4F8F6B8}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{88E067B4-21E8-4FFA-9142-6C52605B704C}">
<Class name="JointConfiguration" field="BaseClass1" version="1" type="{DF91D39A-4901-48C4-9159-93FD2ACA5252}">
<Class name="Quaternion" field="ParentLocalRotation" value="0.2611587 0.9659281 -0.0034238 -0.0126628" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
<Class name="Vector3" field="ParentLocalPosition" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Quaternion" field="ChildLocalRotation" value="0.0000000 0.0000000 -0.0000000 0.9998225" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
@@ -650,7 +650,7 @@
</Class>
</Class>
</Class>
<Class name="RagdollNodeConfiguration" field="element" version="4" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RagdollNodeConfiguration" field="element" version="5" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RigidBodyConfiguration" field="BaseClass1" version="2" type="{ACFA8900-8530-4744-AF00-AA533C868A8E}">
<Class name="WorldBodyConfiguration" field="BaseClass1" version="1" type="{6EEB377C-DC60-4E10-AF12-9626C0763B2D}">
<Class name="AZStd::string" field="name" value="L_foot_JNT" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
@@ -673,9 +673,9 @@
<Class name="Matrix3x3" field="Inertia tensor" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000" type="{15A4332F-7C3F-4A58-AC35-50E1CE53FB9C}"/>
<Class name="float" field="Maximum Angular Velocity" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
</Class>
<Class name="AZStd::shared_ptr" field="JointLimit" type="{F5C4DCF0-277D-5536-921B-A6A4AEEF7226}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{90C5C23D-16C0-4F23-AD50-A190E402388E}">
<Class name="JointLimitConfiguration" field="BaseClass1" version="1" type="{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}">
<Class name="AZStd::shared_ptr" field="JointConfig" type="{B7A3D04D-1ECC-5D84-8C93-B4C9E4F8F6B8}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{88E067B4-21E8-4FFA-9142-6C52605B704C}">
<Class name="JointConfiguration" field="BaseClass1" version="1" type="{DF91D39A-4901-48C4-9159-93FD2ACA5252}">
<Class name="Quaternion" field="ParentLocalRotation" value="-0.0073839 -0.0140681 0.5175676 0.8556790" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
<Class name="Vector3" field="ParentLocalPosition" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Quaternion" field="ChildLocalRotation" value="0.0000000 0.0000000 -0.0000000 1.0001576" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
@@ -688,7 +688,7 @@
</Class>
</Class>
</Class>
<Class name="RagdollNodeConfiguration" field="element" version="4" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RagdollNodeConfiguration" field="element" version="5" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RigidBodyConfiguration" field="BaseClass1" version="2" type="{ACFA8900-8530-4744-AF00-AA533C868A8E}">
<Class name="WorldBodyConfiguration" field="BaseClass1" version="1" type="{6EEB377C-DC60-4E10-AF12-9626C0763B2D}">
<Class name="AZStd::string" field="name" value="L_knee_JNT" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
@@ -711,9 +711,9 @@
<Class name="Matrix3x3" field="Inertia tensor" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000" type="{15A4332F-7C3F-4A58-AC35-50E1CE53FB9C}"/>
<Class name="float" field="Maximum Angular Velocity" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
</Class>
<Class name="AZStd::shared_ptr" field="JointLimit" type="{F5C4DCF0-277D-5536-921B-A6A4AEEF7226}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{90C5C23D-16C0-4F23-AD50-A190E402388E}">
<Class name="JointLimitConfiguration" field="BaseClass1" version="1" type="{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}">
<Class name="AZStd::shared_ptr" field="JointConfig" type="{B7A3D04D-1ECC-5D84-8C93-B4C9E4F8F6B8}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{88E067B4-21E8-4FFA-9142-6C52605B704C}">
<Class name="JointConfiguration" field="BaseClass1" version="1" type="{DF91D39A-4901-48C4-9159-93FD2ACA5252}">
<Class name="Quaternion" field="ParentLocalRotation" value="0.0000000 -0.0000000 0.3640593 -0.9358648" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
<Class name="Vector3" field="ParentLocalPosition" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Quaternion" field="ChildLocalRotation" value="0.0000000 -0.0000000 -0.0000000 0.9999046" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
@@ -726,7 +726,7 @@
</Class>
</Class>
</Class>
<Class name="RagdollNodeConfiguration" field="element" version="4" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RagdollNodeConfiguration" field="element" version="5" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RigidBodyConfiguration" field="BaseClass1" version="2" type="{ACFA8900-8530-4744-AF00-AA533C868A8E}">
<Class name="WorldBodyConfiguration" field="BaseClass1" version="1" type="{6EEB377C-DC60-4E10-AF12-9626C0763B2D}">
<Class name="AZStd::string" field="name" value="R_leg_JNT" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
@@ -749,9 +749,9 @@
<Class name="Matrix3x3" field="Inertia tensor" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000" type="{15A4332F-7C3F-4A58-AC35-50E1CE53FB9C}"/>
<Class name="float" field="Maximum Angular Velocity" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
</Class>
<Class name="AZStd::shared_ptr" field="JointLimit" type="{F5C4DCF0-277D-5536-921B-A6A4AEEF7226}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{90C5C23D-16C0-4F23-AD50-A190E402388E}">
<Class name="JointLimitConfiguration" field="BaseClass1" version="1" type="{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}">
<Class name="AZStd::shared_ptr" field="JointConfig" type="{B7A3D04D-1ECC-5D84-8C93-B4C9E4F8F6B8}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{88E067B4-21E8-4FFA-9142-6C52605B704C}">
<Class name="JointConfiguration" field="BaseClass1" version="1" type="{DF91D39A-4901-48C4-9159-93FD2ACA5252}">
<Class name="Quaternion" field="ParentLocalRotation" value="-0.2770883 -0.9615672 -0.0035520 -0.0123266" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
<Class name="Vector3" field="ParentLocalPosition" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Quaternion" field="ChildLocalRotation" value="0.0000005 0.0000000 0.9998229 0.0000000" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
@@ -764,7 +764,7 @@
</Class>
</Class>
</Class>
<Class name="RagdollNodeConfiguration" field="element" version="4" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RagdollNodeConfiguration" field="element" version="5" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RigidBodyConfiguration" field="BaseClass1" version="2" type="{ACFA8900-8530-4744-AF00-AA533C868A8E}">
<Class name="WorldBodyConfiguration" field="BaseClass1" version="1" type="{6EEB377C-DC60-4E10-AF12-9626C0763B2D}">
<Class name="AZStd::string" field="name" value="R_foot_JNT" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
@@ -787,9 +787,9 @@
<Class name="Matrix3x3" field="Inertia tensor" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000" type="{15A4332F-7C3F-4A58-AC35-50E1CE53FB9C}"/>
<Class name="float" field="Maximum Angular Velocity" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
</Class>
<Class name="AZStd::shared_ptr" field="JointLimit" type="{F5C4DCF0-277D-5536-921B-A6A4AEEF7226}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{90C5C23D-16C0-4F23-AD50-A190E402388E}">
<Class name="JointLimitConfiguration" field="BaseClass1" version="1" type="{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}">
<Class name="AZStd::shared_ptr" field="JointConfig" type="{B7A3D04D-1ECC-5D84-8C93-B4C9E4F8F6B8}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{88E067B4-21E8-4FFA-9142-6C52605B704C}">
<Class name="JointConfiguration" field="BaseClass1" version="1" type="{DF91D39A-4901-48C4-9159-93FD2ACA5252}">
<Class name="Quaternion" field="ParentLocalRotation" value="0.0140685 -0.0073837 -0.8556802 0.5175687" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
<Class name="Vector3" field="ParentLocalPosition" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Quaternion" field="ChildLocalRotation" value="0.0000004 -0.0000000 -1.0001591 0.0000003" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
@@ -802,7 +802,7 @@
</Class>
</Class>
</Class>
<Class name="RagdollNodeConfiguration" field="element" version="4" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RagdollNodeConfiguration" field="element" version="5" type="{A1796586-85AB-496E-93C9-C5841F03B1AD}">
<Class name="RigidBodyConfiguration" field="BaseClass1" version="2" type="{ACFA8900-8530-4744-AF00-AA533C868A8E}">
<Class name="WorldBodyConfiguration" field="BaseClass1" version="1" type="{6EEB377C-DC60-4E10-AF12-9626C0763B2D}">
<Class name="AZStd::string" field="name" value="R_knee_JNT" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
@@ -825,9 +825,9 @@
<Class name="Matrix3x3" field="Inertia tensor" value="1.0000000 0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000000 0.0000000 1.0000000" type="{15A4332F-7C3F-4A58-AC35-50E1CE53FB9C}"/>
<Class name="float" field="Maximum Angular Velocity" value="100.0000000" type="{EA2C3E90-AFBE-44D4-A90D-FAAF79BAF93D}"/>
</Class>
<Class name="AZStd::shared_ptr" field="JointLimit" type="{F5C4DCF0-277D-5536-921B-A6A4AEEF7226}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{90C5C23D-16C0-4F23-AD50-A190E402388E}">
<Class name="JointLimitConfiguration" field="BaseClass1" version="1" type="{C9B70C4D-22D7-45AB-9B0A-30A4ED5E42DB}">
<Class name="AZStd::shared_ptr" field="JointConfig" type="{B7A3D04D-1ECC-5D84-8C93-B4C9E4F8F6B8}">
<Class name="D6JointLimitConfiguration" field="element" version="1" type="{88E067B4-21E8-4FFA-9142-6C52605B704C}">
<Class name="JointConfiguration" field="BaseClass1" version="1" type="{DF91D39A-4901-48C4-9159-93FD2ACA5252}">
<Class name="Quaternion" field="ParentLocalRotation" value="-0.0000033 0.0000092 -0.9416476 -0.3386196" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
<Class name="Vector3" field="ParentLocalPosition" value="0.0000000 0.0000000 0.0000000" type="{8379EB7D-01FA-4538-B64B-A6543B4BE73D}"/>
<Class name="Quaternion" field="ChildLocalRotation" value="0.0000000 -0.0000000 -0.9999050 0.0000000" type="{73103120-3DD3-4873-BAB3-9713FA2804FB}"/>
+2 -2
View File
@@ -208,8 +208,8 @@ namespace PhysX
}
else
{
EXPECT_EQ(joint->GetChildBody(), &node->GetRigidBody());
EXPECT_EQ(joint->GetParentBody(), &ragdoll->GetNode(parentIndex)->GetRigidBody());
EXPECT_EQ(joint->GetChildBodyHandle(), node->GetRigidBody().m_bodyHandle);
EXPECT_EQ(joint->GetParentBodyHandle(), ragdoll->GetNode(parentIndex)->GetRigidBody().m_bodyHandle);
}
}
}
+8 -2
View File
@@ -75,8 +75,6 @@ set(FILES
Source/Shape.cpp
Source/Material.cpp
Source/Material.h
Source/Joint.cpp
Source/Joint.h
Source/ForceRegionForces.cpp
Source/ForceRegionForces.h
Source/ForceRegion.cpp
@@ -104,6 +102,7 @@ set(FILES
Include/PhysX/Debug/PhysXDebugConfiguration.h
Include/PhysX/Debug/PhysXDebugInterface.h
Include/PhysX/Configuration/PhysXConfiguration.h
Include/PhysX/Joint/Configuration/PhysXJointConfiguration.h
Source/Common/PhysXSceneQueryHelpers.h
Source/Common/PhysXSceneQueryHelpers.cpp
Source/Configuration/PhysXConfiguration.cpp
@@ -112,6 +111,11 @@ set(FILES
Source/Debug/PhysXDebug.h
Source/Debug/PhysXDebug.cpp
Source/Debug/Configuration/PhysXDebugConfiguration.cpp
Source/Joint/PhysXJoint.h
Source/Joint/PhysXJoint.cpp
Source/Joint/PhysXJointUtils.h
Source/Joint/PhysXJointUtils.cpp
Source/Joint/Configuration/PhysXJointConfiguration.cpp
Source/Scene/PhysXScene.h
Source/Scene/PhysXScene.cpp
Source/Scene/PhysXSceneInterface.h
@@ -128,6 +132,8 @@ set(FILES
Source/System/PhysXCpuDispatcher.h
Source/System/PhysXJob.cpp
Source/System/PhysXJob.h
Source/System/PhysXJointInterface.h
Source/System/PhysXJointInterface.cpp
Source/System/PhysXSdkCallbacks.h
Source/System/PhysXSdkCallbacks.cpp
Source/System/PhysXSystem.h
@@ -783,7 +783,7 @@ namespace PhysXDebug
Physics::RagdollNode* ragdollNode = actorData->GetRagdollNode();
if (ragdollNode)
{
const AZStd::shared_ptr<Physics::Joint>& joint = ragdollNode->GetJoint();
AzPhysics::Joint* joint = ragdollNode->GetJoint();
physx::PxJoint* pxJoint = static_cast<physx::PxJoint*>(joint->GetNativePointer());
physx::PxTransform jointPose = actor1->getGlobalPose() * pxJoint->getLocalPose(physx::PxJointActorIndex::eACTOR1);
if (!m_culling.m_enabled || m_cullingBox.contains(jointPose.p))

Some files were not shown because too many files have changed in this diff Show More