CreateRagdoll.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // Copyright (c) 2008-2022 the Urho3D project
  2. // License: MIT
  3. #include <Urho3D/Graphics/AnimatedModel.h>
  4. #include <Urho3D/IO/Log.h>
  5. #include <Urho3D/Physics/PhysicsEvents.h>
  6. #include <Urho3D/Physics/RigidBody.h>
  7. #include "CreateRagdoll.h"
  8. #include <Urho3D/DebugNew.h>
  9. CreateRagdoll::CreateRagdoll(Context* context) :
  10. Component(context)
  11. {
  12. }
  13. void CreateRagdoll::OnNodeSet(Node* node)
  14. {
  15. // If the node pointer is non-null, this component has been created into a scene node. Subscribe to physics collisions that
  16. // concern this scene node
  17. if (node)
  18. SubscribeToEvent(node, E_NODECOLLISION, URHO3D_HANDLER(CreateRagdoll, HandleNodeCollision));
  19. }
  20. void CreateRagdoll::HandleNodeCollision(StringHash eventType, VariantMap& eventData)
  21. {
  22. using namespace NodeCollision;
  23. // Get the other colliding body, make sure it is moving (has nonzero mass)
  24. auto* otherBody = static_cast<RigidBody*>(eventData[P_OTHERBODY].GetPtr());
  25. if (otherBody->GetMass() > 0.0f)
  26. {
  27. // We do not need the physics components in the AnimatedModel's root scene node anymore
  28. node_->RemoveComponent<RigidBody>();
  29. node_->RemoveComponent<CollisionShape>();
  30. // Create RigidBody & CollisionShape components to bones
  31. CreateRagdollBone("Bip01_Pelvis", SHAPE_BOX, Vector3(0.3f, 0.2f, 0.25f), Vector3(0.0f, 0.0f, 0.0f),
  32. Quaternion(0.0f, 0.0f, 0.0f));
  33. CreateRagdollBone("Bip01_Spine1", SHAPE_BOX, Vector3(0.35f, 0.2f, 0.3f), Vector3(0.15f, 0.0f, 0.0f),
  34. Quaternion(0.0f, 0.0f, 0.0f));
  35. CreateRagdollBone("Bip01_L_Thigh", SHAPE_CAPSULE, Vector3(0.175f, 0.45f, 0.175f), Vector3(0.25f, 0.0f, 0.0f),
  36. Quaternion(0.0f, 0.0f, 90.0f));
  37. CreateRagdollBone("Bip01_R_Thigh", SHAPE_CAPSULE, Vector3(0.175f, 0.45f, 0.175f), Vector3(0.25f, 0.0f, 0.0f),
  38. Quaternion(0.0f, 0.0f, 90.0f));
  39. CreateRagdollBone("Bip01_L_Calf", SHAPE_CAPSULE, Vector3(0.15f, 0.55f, 0.15f), Vector3(0.25f, 0.0f, 0.0f),
  40. Quaternion(0.0f, 0.0f, 90.0f));
  41. CreateRagdollBone("Bip01_R_Calf", SHAPE_CAPSULE, Vector3(0.15f, 0.55f, 0.15f), Vector3(0.25f, 0.0f, 0.0f),
  42. Quaternion(0.0f, 0.0f, 90.0f));
  43. CreateRagdollBone("Bip01_Head", SHAPE_BOX, Vector3(0.2f, 0.2f, 0.2f), Vector3(0.1f, 0.0f, 0.0f),
  44. Quaternion(0.0f, 0.0f, 0.0f));
  45. CreateRagdollBone("Bip01_L_UpperArm", SHAPE_CAPSULE, Vector3(0.15f, 0.35f, 0.15f), Vector3(0.1f, 0.0f, 0.0f),
  46. Quaternion(0.0f, 0.0f, 90.0f));
  47. CreateRagdollBone("Bip01_R_UpperArm", SHAPE_CAPSULE, Vector3(0.15f, 0.35f, 0.15f), Vector3(0.1f, 0.0f, 0.0f),
  48. Quaternion(0.0f, 0.0f, 90.0f));
  49. CreateRagdollBone("Bip01_L_Forearm", SHAPE_CAPSULE, Vector3(0.125f, 0.4f, 0.125f), Vector3(0.2f, 0.0f, 0.0f),
  50. Quaternion(0.0f, 0.0f, 90.0f));
  51. CreateRagdollBone("Bip01_R_Forearm", SHAPE_CAPSULE, Vector3(0.125f, 0.4f, 0.125f), Vector3(0.2f, 0.0f, 0.0f),
  52. Quaternion(0.0f, 0.0f, 90.0f));
  53. // Create Constraints between bones
  54. CreateRagdollConstraint("Bip01_L_Thigh", "Bip01_Pelvis", CONSTRAINT_CONETWIST, Vector3::BACK, Vector3::FORWARD,
  55. Vector2(45.0f, 45.0f), Vector2::ZERO);
  56. CreateRagdollConstraint("Bip01_R_Thigh", "Bip01_Pelvis", CONSTRAINT_CONETWIST, Vector3::BACK, Vector3::FORWARD,
  57. Vector2(45.0f, 45.0f), Vector2::ZERO);
  58. CreateRagdollConstraint("Bip01_L_Calf", "Bip01_L_Thigh", CONSTRAINT_HINGE, Vector3::BACK, Vector3::BACK,
  59. Vector2(90.0f, 0.0f), Vector2::ZERO);
  60. CreateRagdollConstraint("Bip01_R_Calf", "Bip01_R_Thigh", CONSTRAINT_HINGE, Vector3::BACK, Vector3::BACK,
  61. Vector2(90.0f, 0.0f), Vector2::ZERO);
  62. CreateRagdollConstraint("Bip01_Spine1", "Bip01_Pelvis", CONSTRAINT_HINGE, Vector3::FORWARD, Vector3::FORWARD,
  63. Vector2(45.0f, 0.0f), Vector2(-10.0f, 0.0f));
  64. CreateRagdollConstraint("Bip01_Head", "Bip01_Spine1", CONSTRAINT_CONETWIST, Vector3::LEFT, Vector3::LEFT,
  65. Vector2(0.0f, 30.0f), Vector2::ZERO);
  66. CreateRagdollConstraint("Bip01_L_UpperArm", "Bip01_Spine1", CONSTRAINT_CONETWIST, Vector3::DOWN, Vector3::UP,
  67. Vector2(45.0f, 45.0f), Vector2::ZERO, false);
  68. CreateRagdollConstraint("Bip01_R_UpperArm", "Bip01_Spine1", CONSTRAINT_CONETWIST, Vector3::DOWN, Vector3::UP,
  69. Vector2(45.0f, 45.0f), Vector2::ZERO, false);
  70. CreateRagdollConstraint("Bip01_L_Forearm", "Bip01_L_UpperArm", CONSTRAINT_HINGE, Vector3::BACK, Vector3::BACK,
  71. Vector2(90.0f, 0.0f), Vector2::ZERO);
  72. CreateRagdollConstraint("Bip01_R_Forearm", "Bip01_R_UpperArm", CONSTRAINT_HINGE, Vector3::BACK, Vector3::BACK,
  73. Vector2(90.0f, 0.0f), Vector2::ZERO);
  74. // Disable keyframe animation from all bones so that they will not interfere with the ragdoll
  75. auto* model = GetComponent<AnimatedModel>();
  76. Skeleton& skeleton = model->GetSkeleton();
  77. for (unsigned i = 0; i < skeleton.GetNumBones(); ++i)
  78. skeleton.GetBone(i)->animated_ = false;
  79. // Finally remove self from the scene node. Note that this must be the last operation performed in the function
  80. Remove();
  81. }
  82. }
  83. void CreateRagdoll::CreateRagdollBone(const String& boneName, ShapeType type, const Vector3& size, const Vector3& position,
  84. const Quaternion& rotation)
  85. {
  86. // Find the correct child scene node recursively
  87. Node* boneNode = node_->GetChild(boneName, true);
  88. if (!boneNode)
  89. {
  90. URHO3D_LOGWARNING("Could not find bone " + boneName + " for creating ragdoll physics components");
  91. return;
  92. }
  93. auto* body = boneNode->CreateComponent<RigidBody>();
  94. // Set mass to make movable
  95. body->SetMass(1.0f);
  96. // Set damping parameters to smooth out the motion
  97. body->SetLinearDamping(0.05f);
  98. body->SetAngularDamping(0.85f);
  99. // Set rest thresholds to ensure the ragdoll rigid bodies come to rest to not consume CPU endlessly
  100. body->SetLinearRestThreshold(1.5f);
  101. body->SetAngularRestThreshold(2.5f);
  102. auto* shape = boneNode->CreateComponent<CollisionShape>();
  103. // We use either a box or a capsule shape for all of the bones
  104. if (type == SHAPE_BOX)
  105. shape->SetBox(size, position, rotation);
  106. else
  107. shape->SetCapsule(size.x_, size.y_, position, rotation);
  108. }
  109. void CreateRagdoll::CreateRagdollConstraint(const String& boneName, const String& parentName, ConstraintType type,
  110. const Vector3& axis, const Vector3& parentAxis, const Vector2& highLimit, const Vector2& lowLimit,
  111. bool disableCollision)
  112. {
  113. Node* boneNode = node_->GetChild(boneName, true);
  114. Node* parentNode = node_->GetChild(parentName, true);
  115. if (!boneNode)
  116. {
  117. URHO3D_LOGWARNING("Could not find bone " + boneName + " for creating ragdoll constraint");
  118. return;
  119. }
  120. if (!parentNode)
  121. {
  122. URHO3D_LOGWARNING("Could not find bone " + parentName + " for creating ragdoll constraint");
  123. return;
  124. }
  125. auto* constraint = boneNode->CreateComponent<Constraint>();
  126. constraint->SetConstraintType(type);
  127. // Most of the constraints in the ragdoll will work better when the connected bodies don't collide against each other
  128. constraint->SetDisableCollision(disableCollision);
  129. // The connected body must be specified before setting the world position
  130. constraint->SetOtherBody(parentNode->GetComponent<RigidBody>());
  131. // Position the constraint at the child bone we are connecting
  132. constraint->SetWorldPosition(boneNode->GetWorldPosition());
  133. // Configure axes and limits
  134. constraint->SetAxis(axis);
  135. constraint->SetOtherAxis(parentAxis);
  136. constraint->SetHighLimit(highLimit);
  137. constraint->SetLowLimit(lowLimit);
  138. }