fixed joint crash when no lead entity is selected (#2867)

Signed-off-by: amzn-sean <75276488+amzn-sean@users.noreply.github.com>
This commit is contained in:
amzn-sean
2021-08-16 15:46:46 +01:00
committed by GitHub
parent 5925bd22f6
commit e630e3324d
5 changed files with 121 additions and 15 deletions
+17 -2
View File
@@ -46,11 +46,26 @@ namespace PhysX
JointComponent::LeadFollowerInfo leadFollowerInfo;
ObtainLeadFollowerInfo(leadFollowerInfo);
if (!leadFollowerInfo.m_followerActor)
if (leadFollowerInfo.m_followerActor == nullptr ||
leadFollowerInfo.m_followerBody == nullptr)
{
return;
}
// if there is no lead body, this will be a constraint of the follower's global position, so use invalid body handle.
AzPhysics::SimulatedBodyHandle parentHandle = AzPhysics::InvalidSimulatedBodyHandle;
if (leadFollowerInfo.m_leadBody != nullptr)
{
parentHandle = leadFollowerInfo.m_leadBody->m_bodyHandle;
}
else
{
AZ_TracePrintf(
"PhysX", "Entity [%s] Ball Joint component missing lead entity. This joint will be a global constraint on the follower's global position.",
GetEntity()->GetName().c_str());
}
BallJointConfiguration configuration;
configuration.m_parentLocalPosition = leadFollowerInfo.m_leadLocal.GetTranslation();
configuration.m_parentLocalRotation = leadFollowerInfo.m_leadLocal.GetRotation();
@@ -65,7 +80,7 @@ namespace PhysX
m_jointHandle = sceneInterface->AddJoint(
leadFollowerInfo.m_followerBody->m_sceneOwner,
&configuration,
leadFollowerInfo.m_leadBody->m_bodyHandle,
parentHandle,
leadFollowerInfo.m_followerBody->m_bodyHandle);
m_jointSceneOwner = leadFollowerInfo.m_followerBody->m_sceneOwner;
}
+16 -2
View File
@@ -54,11 +54,25 @@ namespace PhysX
JointComponent::LeadFollowerInfo leadFollowerInfo;
ObtainLeadFollowerInfo(leadFollowerInfo);
if (!leadFollowerInfo.m_followerActor)
if (leadFollowerInfo.m_followerActor == nullptr ||
leadFollowerInfo.m_followerBody == nullptr)
{
return;
}
// if there is no lead body, this will be a constraint of the follower's global position, so use invalid body handle.
AzPhysics::SimulatedBodyHandle parentHandle = AzPhysics::InvalidSimulatedBodyHandle;
if (leadFollowerInfo.m_leadBody != nullptr)
{
parentHandle = leadFollowerInfo.m_leadBody->m_bodyHandle;
}
else
{
AZ_TracePrintf("PhysX",
"Entity [%s] Fixed Joint component missing lead entity. This joint will be a global constraint on the follower's global position.",
GetEntity()->GetName().c_str());
}
FixedJointConfiguration configuration;
configuration.m_parentLocalPosition = leadFollowerInfo.m_leadLocal.GetTranslation();
configuration.m_parentLocalRotation = leadFollowerInfo.m_leadLocal.GetRotation();
@@ -72,7 +86,7 @@ namespace PhysX
m_jointHandle = sceneInterface->AddJoint(
leadFollowerInfo.m_followerBody->m_sceneOwner,
&configuration,
leadFollowerInfo.m_leadBody->m_bodyHandle,
parentHandle,
leadFollowerInfo.m_followerBody->m_bodyHandle);
m_jointSceneOwner = leadFollowerInfo.m_followerBody->m_sceneOwner;
}
+16 -2
View File
@@ -48,12 +48,24 @@ namespace PhysX
JointComponent::LeadFollowerInfo leadFollowerInfo;
ObtainLeadFollowerInfo(leadFollowerInfo);
if (leadFollowerInfo.m_followerActor == nullptr ||
leadFollowerInfo.m_leadBody == nullptr ||
leadFollowerInfo.m_followerBody == nullptr)
{
return;
}
// if there is no lead body, this will be a constraint of the follower's global position, so use invalid body handle.
AzPhysics::SimulatedBodyHandle parentHandle = AzPhysics::InvalidSimulatedBodyHandle;
if (leadFollowerInfo.m_leadBody != nullptr)
{
parentHandle = leadFollowerInfo.m_leadBody->m_bodyHandle;
}
else
{
AZ_TracePrintf(
"PhysX", "Entity [%s] Hinge Joint component missing lead entity. This joint will be a global constraint on the follower's global position.",
GetEntity()->GetName().c_str());
}
HingeJointConfiguration configuration;
configuration.m_parentLocalPosition = leadFollowerInfo.m_leadLocal.GetTranslation();
configuration.m_parentLocalRotation = leadFollowerInfo.m_leadLocal.GetRotation();
@@ -66,7 +78,9 @@ namespace PhysX
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_sceneOwner,
&configuration,
parentHandle,
leadFollowerInfo.m_followerBody->m_bodyHandle);
m_jointSceneOwner = leadFollowerInfo.m_followerBody->m_sceneOwner;
}
@@ -190,8 +190,9 @@ namespace PhysX {
{
PxJointActorData actorData = GetJointPxActors(sceneHandle, parentBodyHandle, childBodyHandle);
if (!actorData.parentActor || !actorData.childActor)
if (actorData.parentActor == nullptr && actorData.childActor == nullptr)
{
AZ_Warning("PhysX Joint", false, "CreateJoint failed - at least one body must be a PxRigidActor.");
return nullptr;
}
@@ -239,7 +240,8 @@ namespace PhysX {
{
PxJointActorData actorData = GetJointPxActors(sceneHandle, parentBodyHandle, childBodyHandle);
if (!actorData.parentActor || !actorData.childActor)
//only check the child actor, as a null parent actor means this joint is a global constraint.
if (!actorData.childActor)
{
return nullptr;
}
@@ -252,7 +254,8 @@ namespace PhysX {
{
PHYSX_SCENE_READ_LOCK(actorData.childActor->getScene());
joint = physx::PxFixedJointCreate(PxGetPhysics(),
joint = physx::PxFixedJointCreate(
PxGetPhysics(),
actorData.parentActor, PxMathConvert(parentLocalTM),
actorData.childActor, PxMathConvert(childLocalTM));
}
@@ -272,7 +275,8 @@ namespace PhysX {
{
PxJointActorData actorData = GetJointPxActors(sceneHandle, parentBodyHandle, childBodyHandle);
if (!actorData.parentActor || !actorData.childActor)
// only check the child actor, as a null parent actor means this joint is a global constraint.
if (!actorData.childActor)
{
return nullptr;
}
@@ -306,7 +310,8 @@ namespace PhysX {
{
PxJointActorData actorData = GetJointPxActors(sceneHandle, parentBodyHandle, childBodyHandle);
if (!actorData.parentActor || !actorData.childActor)
// only check the child actor, as a null parent actor means this joint is a global constraint.
if (!actorData.childActor)
{
return nullptr;
}
+62 -4
View File
@@ -123,7 +123,7 @@ namespace PhysX
const AZ::Vector3 followerEndPosition = RunJointTest(m_defaultScene, followerEntity->GetId());
EXPECT_TRUE(followerEndPosition.GetX() > followerPosition.GetX());
EXPECT_GT(followerEndPosition.GetX(), followerPosition.GetX());
}
TEST_F(PhysXJointsTest, Joint_HingeJoint_FollowerSwingsAroundLead)
@@ -164,8 +164,8 @@ namespace PhysX
const AZ::Vector3 followerEndPosition = RunJointTest(m_defaultScene, followerEntity->GetId());
EXPECT_TRUE(followerEndPosition.GetX() > followerPosition.GetX());
EXPECT_TRUE(abs(followerEndPosition.GetZ()) > FLT_EPSILON);
EXPECT_GT(followerEndPosition.GetX(), followerPosition.GetX());
EXPECT_GT(abs(followerEndPosition.GetZ()), FLT_EPSILON);
}
TEST_F(PhysXJointsTest, Joint_BallJoint_FollowerSwingsUpAboutLead)
@@ -206,7 +206,65 @@ namespace PhysX
const AZ::Vector3 followerEndPosition = RunJointTest(m_defaultScene, followerEntity->GetId());
EXPECT_TRUE(followerEndPosition.GetZ() > followerPosition.GetZ());
EXPECT_GT(followerEndPosition.GetZ(), followerPosition.GetZ());
}
TEST_F(PhysXJointsTest, Joint_BallJoint_GlobalConstraint)
{
// Place an entity in the world with a rigid body, physx collider, and a ball joint components.
// Do not set a lead entity on the ball joint component.
// Set entity's initial velocity to 10 in the X and Y directions on the rigid body component.
// The entity should swing up on the global constraint.
const AZ::Vector3 followerPosition(0.0f, 0.0f, -1.0f);
const AZ::Vector3 followerInitialLinearVelocity(10.0f, 10.0f, 0.0f);
const AZ::Vector3 jointLocalPosition(0.0f, 0.0f, 2.0f);
const AZ::Quaternion jointLocalRotation = AZ::Quaternion::CreateRotationY(90.0f);
const AZ::Transform jointLocalTransform = AZ::Transform::CreateFromQuaternionAndTranslation(jointLocalRotation, jointLocalPosition);
//we want a global constraint, so leave the lead entity unset.
auto jointConfig = AZStd::make_shared<JointComponentConfiguration>();
jointConfig->m_localTransformFromFollower = jointLocalTransform;
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_GT(followerEndPosition.GetZ(), followerPosition.GetZ());
}
TEST_F(PhysXJointsTest, Joint_HingeJoint_GlobalConstraint)
{
// Place an entity in the world with a rigid body, physx collider, and a hinge joint components.
// Do not set a lead entity on the hinge joint component.
// Set entity's initial velocity to 10 in the X and Y directions on the rigid body component.
// The entity should swing up on the global constraint.
const AZ::Vector3 followerPosition(0.0f, 0.0f, -1.0f);
const AZ::Vector3 followerInitialLinearVelocity(10.0f, 10.0f, 0.0f);
const AZ::Vector3 jointLocalPosition(0.0f, 0.0f, 2.0f);
const AZ::Quaternion jointLocalRotation = AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(0.0f, 180.0f, 90.0f));
const AZ::Transform jointLocalTransform = AZ::Transform::CreateFromQuaternionAndTranslation(jointLocalRotation, jointLocalPosition);
// do not set the lead entity as that makes this a global constraint
auto jointConfig = AZStd::make_shared<JointComponentConfiguration>();
jointConfig->m_localTransformFromFollower = jointLocalTransform;
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());
EXPECT_GT(followerEndPosition.GetZ(), followerPosition.GetZ());
}
// for some reason TYPED_TEST_CASE with the fixture is not working on Android + Linux