EditorArticulationLinkComponent.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/Serialization/EditContext.h>
  9. #include <AzToolsFramework/ToolsComponents/TransformComponent.h>
  10. #include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
  11. #include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
  12. #include <Editor/EditorJointCommon.h>
  13. #include <Source/ArticulationLinkComponent.h>
  14. #include <Source/EditorArticulationLinkComponent.h>
  15. #include <Source/EditorColliderComponent.h>
  16. #include <AzFramework/Physics/NameConstants.h>
  17. namespace PhysX
  18. {
  19. namespace
  20. {
  21. const float LocalRotationMax = 360.0f;
  22. const float LocalRotationMin = -360.0f;
  23. }
  24. void EditorArticulationLinkConfiguration::Reflect(AZ::ReflectContext* context)
  25. {
  26. if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  27. {
  28. serializeContext->Class<EditorArticulationLinkConfiguration, ArticulationLinkConfiguration>()->Version(2);
  29. if (auto* editContext = serializeContext->GetEditContext())
  30. {
  31. editContext->Class<ArticulationLinkConfiguration>("PhysX Articulation Configuration", "")
  32. ->ClassElement(AZ::Edit::ClassElements::EditorData, "Articulation configuration")
  33. ->Attribute(AZ::Edit::Attributes::Category, "PhysX")
  34. ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
  35. ->UIElement(AZ::Edit::UIHandlers::Label, "<b>Root Link</b>")
  36. ->Attribute(AZ::Edit::Attributes::Visibility, &ArticulationLinkConfiguration::m_isRootArticulation)
  37. ->UIElement(AZ::Edit::UIHandlers::Label, "<b>Child Link</b>")
  38. ->Attribute(AZ::Edit::Attributes::Visibility, &ArticulationLinkConfiguration::IsNotRootArticulation)
  39. ->DataElement(
  40. AZ::Edit::UIHandlers::Default,
  41. &ArticulationLinkConfiguration::m_isFixedBase,
  42. "Fixed Base",
  43. "When active, the root articulation is fixed.")
  44. ->Attribute(AZ::Edit::Attributes::Visibility, &ArticulationLinkConfiguration::m_isRootArticulation)
  45. ->DataElement(
  46. 0,
  47. &ArticulationLinkConfiguration::m_selfCollide,
  48. "Self Collide",
  49. "Enable collisions between the articulation's links (note that parent/child collisions are disabled internally in either case).")
  50. ->Attribute(AZ::Edit::Attributes::Visibility, &ArticulationLinkConfiguration::m_isRootArticulation)
  51. ->ClassElement(AZ::Edit::ClassElements::Group, "Rigid Body configuration")
  52. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  53. ->DataElement(
  54. AZ::Edit::UIHandlers::Default,
  55. &ArticulationLinkConfiguration::m_gravityEnabled,
  56. "Gravity enabled",
  57. "When active, global gravity affects this rigid body.")
  58. ->DataElement(
  59. AZ::Edit::UIHandlers::Default,
  60. &ArticulationLinkConfiguration::m_mass,
  61. "Mass",
  62. "The mass of the rigid body in kilograms. A value of 0 is treated as infinite. "
  63. "The trajectory of infinite mass bodies cannot be affected by any collisions or forces other than gravity.")
  64. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  65. ->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetMassUnit())
  66. ->DataElement(
  67. AZ::Edit::UIHandlers::Default,
  68. &ArticulationLinkConfiguration::m_centerOfMassOffset,
  69. "COM offset",
  70. "Local space offset for the center of mass (COM).")
  71. ->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetLengthUnit())
  72. ->DataElement(
  73. AZ::Edit::UIHandlers::Default,
  74. &ArticulationLinkConfiguration::m_linearDamping,
  75. "Linear damping",
  76. "The rate of decay over time for linear velocity even if no forces are acting on the rigid body.")
  77. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  78. ->DataElement(
  79. AZ::Edit::UIHandlers::Default,
  80. &ArticulationLinkConfiguration::m_angularDamping,
  81. "Angular damping",
  82. "The rate of decay over time for angular velocity even if no forces are acting on the rigid body.")
  83. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  84. ->DataElement(
  85. AZ::Edit::UIHandlers::Default,
  86. &ArticulationLinkConfiguration::m_sleepMinEnergy,
  87. "Sleep threshold",
  88. "The rigid body can go to sleep (settle) when kinetic energy per unit mass is persistently below this value.")
  89. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  90. ->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetSleepThresholdUnit())
  91. ->Attribute(AZ::Edit::Attributes::Visibility, &ArticulationLinkConfiguration::m_isRootArticulation)
  92. ->DataElement(
  93. AZ::Edit::UIHandlers::Default,
  94. &ArticulationLinkConfiguration::m_startAsleep,
  95. "Start asleep",
  96. "When active, the rigid body will be asleep when spawned, and wake when the body is disturbed.")
  97. ->Attribute(AZ::Edit::Attributes::Visibility, &ArticulationLinkConfiguration::m_isRootArticulation)
  98. ->DataElement(
  99. AZ::Edit::UIHandlers::Default,
  100. &ArticulationLinkConfiguration::m_maxAngularVelocity,
  101. "Maximum angular velocity",
  102. "Clamp angular velocities to this maximum value. "
  103. "This prevents rigid bodies from rotating at unrealistic velocities after collisions.")
  104. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  105. ->Attribute(AZ::Edit::Attributes::Suffix, " " + Physics::NameConstants::GetAngularVelocityUnit())
  106. ->DataElement(
  107. AZ::Edit::UIHandlers::Default,
  108. &ArticulationLinkConfiguration::m_solverPositionIterations,
  109. "Solver Position Iterations",
  110. "Higher values can improve stability at the cost of performance.")
  111. ->Attribute(AZ::Edit::Attributes::Min, 1)
  112. ->Attribute(AZ::Edit::Attributes::Max, 255)
  113. ->Attribute(AZ::Edit::Attributes::Visibility, &ArticulationLinkConfiguration::m_isRootArticulation)
  114. ->DataElement(
  115. AZ::Edit::UIHandlers::Default,
  116. &ArticulationLinkConfiguration::m_solverVelocityIterations,
  117. "Solver Velocity Iterations",
  118. "Higher values can improve stability at the cost of performance.")
  119. ->Attribute(AZ::Edit::Attributes::Min, 1)
  120. ->Attribute(AZ::Edit::Attributes::Max, 255)
  121. ->Attribute(AZ::Edit::Attributes::Visibility, &ArticulationLinkConfiguration::m_isRootArticulation)
  122. ->EndGroup()
  123. ->ClassElement(AZ::Edit::ClassElements::Group, "Joint configuration")
  124. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  125. ->DataElement(
  126. AZ::Edit::UIHandlers::ComboBox,
  127. &ArticulationLinkConfiguration::m_articulationJointType,
  128. "Joint Type",
  129. "Set the type of joint for this link")
  130. ->EnumAttribute(ArticulationJointType::Fix, "Fix")
  131. ->EnumAttribute(ArticulationJointType::Hinge, "Hinge")
  132. ->EnumAttribute(ArticulationJointType::Prismatic, "Prismatic")
  133. ->Attribute(AZ::Edit::Attributes::Visibility, &ArticulationLinkConfiguration::IsNotRootArticulation)
  134. ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
  135. ->DataElement(
  136. 0,
  137. &PhysX::ArticulationLinkConfiguration::m_localPosition,
  138. "Local Position",
  139. "Local Position of joint, relative to its entity.")
  140. ->Attribute(AZ::Edit::Attributes::Visibility, &ArticulationLinkConfiguration::IsNotRootArticulation)
  141. ->DataElement(
  142. 0,
  143. &PhysX::ArticulationLinkConfiguration::m_localRotation,
  144. "Local Rotation",
  145. "Local Rotation of joint, relative to its entity.")
  146. ->Attribute(AZ::Edit::Attributes::Min, LocalRotationMin)
  147. ->Attribute(AZ::Edit::Attributes::Max, LocalRotationMax)
  148. ->Attribute(AZ::Edit::Attributes::Visibility, &ArticulationLinkConfiguration::IsNotRootArticulation)
  149. ->DataElement(
  150. 0,
  151. &ArticulationLinkConfiguration::m_fixJointLocation,
  152. "Fix Joint Location",
  153. "When enabled the joint will remain in the same location when moving the entity.")
  154. ->Attribute(AZ::Edit::Attributes::Visibility, &ArticulationLinkConfiguration::IsNotRootArticulation)
  155. ->DataElement(
  156. AZ::Edit::UIHandlers::ComboBox,
  157. &ArticulationLinkConfiguration::m_displayJointSetup,
  158. "Display Setup in Viewport",
  159. "Never = Not shown."
  160. "Select = Show setup display when entity is selected."
  161. "Always = Always show setup display.")
  162. ->Attribute(AZ::Edit::Attributes::Visibility, &ArticulationLinkConfiguration::IsNotRootArticulation)
  163. ->EnumAttribute(ArticulationLinkConfiguration::DisplaySetupState::Never, "Never")
  164. ->EnumAttribute(ArticulationLinkConfiguration::DisplaySetupState::Selected, "Selected")
  165. ->EnumAttribute(ArticulationLinkConfiguration::DisplaySetupState::Always, "Always")
  166. ->ClassElement(AZ::Edit::ClassElements::Group, "Joint limits")
  167. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  168. ->DataElement(
  169. 0, &ArticulationLinkConfiguration::m_isLimited, "Limit", "When active, the joint's degrees of freedom are limited.")
  170. ->Attribute(AZ::Edit::Attributes::Visibility, &ArticulationLinkConfiguration::IsSingleDofJointType)
  171. ->DataElement(
  172. 0, &ArticulationLinkConfiguration::m_linearLimitLower, "Lower Linear Limit", "Lower limit of linear motion.")
  173. ->Attribute(AZ::Edit::Attributes::Visibility, &ArticulationLinkConfiguration::PrismaticPropertiesVisible)
  174. ->DataElement(
  175. 0, &ArticulationLinkConfiguration::m_linearLimitUpper, "Upper Linear Limit", "Upper limit for linear motion.")
  176. ->Attribute(AZ::Edit::Attributes::Visibility, &ArticulationLinkConfiguration::PrismaticPropertiesVisible)
  177. ->DataElement(
  178. 0, &ArticulationLinkConfiguration::m_angularLimitNegative, "Lower Angular Limit", "Lower limit of angular motion.")
  179. ->Attribute(AZ::Edit::Attributes::Visibility, &ArticulationLinkConfiguration::HingePropertiesVisible)
  180. ->DataElement(
  181. 0, &ArticulationLinkConfiguration::m_angularLimitPositive, "Upper Angular Limit", "Lower limit of angular motion.")
  182. ->Attribute(AZ::Edit::Attributes::Visibility, &ArticulationLinkConfiguration::HingePropertiesVisible)
  183. ->EndGroup()
  184. ->DataElement(
  185. 0, &ArticulationLinkConfiguration::m_motorConfiguration, "Motor Configuration", "Joint's motor configuration.")
  186. ->Attribute(AZ::Edit::Attributes::Visibility, &ArticulationLinkConfiguration::IsSingleDofJointType)
  187. ->DataElement(0, &ArticulationLinkConfiguration::m_jointFriction, "Joint Friction", "Joint's friction coefficient.")
  188. ->Attribute(AZ::Edit::Attributes::Min, 0.f)
  189. ->Attribute(AZ::Edit::Attributes::Visibility, &ArticulationLinkConfiguration::IsSingleDofJointType)
  190. ->DataElement(0, &ArticulationLinkConfiguration::m_armature, "Armature", "Mass for prismatic joints, inertia for hinge")
  191. ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
  192. ->Attribute(AZ::Edit::Attributes::Visibility, &ArticulationLinkConfiguration::IsSingleDofJointType)
  193. ->ClassElement(AZ::Edit::ClassElements::Group, "Sensors")
  194. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  195. ->DataElement(0, &ArticulationLinkConfiguration::m_sensorConfigs, "Sensor Configurations", "Sensor configurations")
  196. ->EndGroup();
  197. }
  198. }
  199. }
  200. EditorArticulationLinkComponent::EditorArticulationLinkComponent(const EditorArticulationLinkConfiguration& configuration)
  201. : m_config(configuration)
  202. {
  203. }
  204. void EditorArticulationLinkComponent::Reflect(AZ::ReflectContext* context)
  205. {
  206. EditorArticulationLinkConfiguration::Reflect(context);
  207. if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  208. {
  209. serializeContext->Class<EditorArticulationLinkComponent, AzToolsFramework::Components::EditorComponentBase>()
  210. ->Version(1)
  211. ->Field("ArticulationConfiguration", &EditorArticulationLinkComponent::m_config);
  212. if (auto* editContext = serializeContext->GetEditContext())
  213. {
  214. constexpr const char* ToolTip = "Articulated rigid body.";
  215. AZStd::vector<AZ::Crc32> componentMenus;
  216. if (ReducedCoordinateArticulationsEnabled())
  217. {
  218. componentMenus.push_back(AZ::Crc32("Game"));
  219. }
  220. editContext->Class<EditorArticulationLinkComponent>("PhysX Articulation Link", ToolTip)
  221. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  222. ->Attribute(AZ::Edit::Attributes::Category, "PhysX")
  223. ->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/PhysXRigidBody.svg")
  224. ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/PhysXRigidBody.svg")
  225. ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, componentMenus)
  226. ->Attribute(AZ::Edit::Attributes::HelpPageURL, "")
  227. ->DataElement(
  228. AZ::Edit::UIHandlers::Default,
  229. &EditorArticulationLinkComponent::m_config,
  230. "Articulation Configuration",
  231. "Configuration for the Articulation Link Component.")
  232. ->Attribute(AZ::Edit::Attributes::AutoExpand, false)
  233. ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly);
  234. }
  235. }
  236. }
  237. void EditorArticulationLinkComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  238. {
  239. provided.push_back(AZ_CRC_CE("PhysicsWorldBodyService"));
  240. provided.push_back(AZ_CRC_CE("PhysicsDynamicRigidBodyService"));
  241. provided.push_back(AZ_CRC_CE("PhysicsRigidBodyService"));
  242. provided.push_back(AZ_CRC_CE("ArticulationLinkService"));
  243. }
  244. void EditorArticulationLinkComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
  245. {
  246. incompatible.push_back(AZ_CRC_CE("PhysicsRigidBodyService"));
  247. }
  248. void EditorArticulationLinkComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
  249. {
  250. required.push_back(AZ_CRC_CE("TransformService"));
  251. }
  252. void EditorArticulationLinkComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
  253. {
  254. dependent.push_back(AZ_CRC_CE("NonUniformScaleService"));
  255. }
  256. bool EditorArticulationLinkComponent::IsRootArticulation() const
  257. {
  258. return IsRootArticulationEntity<EditorArticulationLinkComponent>(GetEntity());
  259. }
  260. void EditorArticulationLinkComponent::Activate()
  261. {
  262. AzToolsFramework::Components::EditorComponentBase::Activate();
  263. m_config.m_isRootArticulation = IsRootArticulation();
  264. AZ::TransformNotificationBus::Handler::BusConnect(GetEntityId());
  265. AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(GetEntityId());
  266. }
  267. void EditorArticulationLinkComponent::Deactivate()
  268. {
  269. AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect();
  270. AZ::TransformNotificationBus::Handler::BusDisconnect();
  271. AzToolsFramework::Components::EditorComponentBase::Deactivate();
  272. }
  273. void EditorArticulationLinkComponent::BuildGameEntity(AZ::Entity* gameEntity)
  274. {
  275. gameEntity->CreateComponent<ArticulationLinkComponent>(m_config);
  276. }
  277. void EditorArticulationLinkComponent::OnTransformChanged([[maybe_unused]] const AZ::Transform& localTM, const AZ::Transform& worldTM)
  278. {
  279. if (m_config.m_fixJointLocation)
  280. {
  281. const AZ::Transform localJoint = AZ::Transform::CreateFromQuaternionAndTranslation(
  282. AZ::Quaternion::CreateFromEulerAnglesDegrees(m_config.m_localRotation), m_config.m_localPosition);
  283. const AZ::Transform worldJoint = m_cachedWorldTM * localJoint;
  284. const AZ::Transform localFromWorld = worldTM.GetInverse();
  285. const AZ::Transform newLocalJoint = localFromWorld * worldJoint;
  286. m_config.m_localPosition = newLocalJoint.GetTranslation();
  287. m_config.m_localRotation = newLocalJoint.GetEulerDegrees();
  288. InvalidatePropertyDisplay(AzToolsFramework::Refresh_Values);
  289. }
  290. m_cachedWorldTM = worldTM;
  291. }
  292. void EditorArticulationLinkComponent::DisplayEntityViewport(
  293. const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay)
  294. {
  295. // The root articulation doesn't have a joint.
  296. if (IsRootArticulation())
  297. {
  298. return;
  299. }
  300. ShowJointHierarchy(viewportInfo, debugDisplay);
  301. if (!ShowSetupDisplay())
  302. {
  303. return;
  304. }
  305. switch (m_config.m_articulationJointType)
  306. {
  307. case ArticulationJointType::Hinge:
  308. ShowHingeJoint(viewportInfo, debugDisplay);
  309. break;
  310. case ArticulationJointType::Prismatic:
  311. ShowPrismaticJoint(viewportInfo, debugDisplay);
  312. break;
  313. default:
  314. // Nothing to show
  315. break;
  316. }
  317. }
  318. bool EditorArticulationLinkComponent::ShowSetupDisplay() const
  319. {
  320. switch (m_config.m_displayJointSetup)
  321. {
  322. case ArticulationLinkConfiguration::DisplaySetupState::Always:
  323. return true;
  324. case ArticulationLinkConfiguration::DisplaySetupState::Selected:
  325. {
  326. bool showSetup = false;
  327. AzToolsFramework::EditorEntityInfoRequestBus::EventResult(
  328. showSetup, GetEntityId(), &AzToolsFramework::EditorEntityInfoRequests::IsSelected);
  329. return showSetup;
  330. }
  331. }
  332. return false;
  333. }
  334. void EditorArticulationLinkComponent::ShowJointHierarchy(
  335. [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) const
  336. {
  337. auto* physXDebug = AZ::Interface<Debug::PhysXDebugInterface>::Get();
  338. if (physXDebug == nullptr)
  339. {
  340. return;
  341. }
  342. const PhysX::Debug::DebugDisplayData& displayData = physXDebug->GetDebugDisplayData();
  343. if (displayData.m_showJointHierarchy)
  344. {
  345. const AZ::Color leadLineColor = displayData.GetJointLeadColor();
  346. const AZ::Color followerLineColor = displayData.GetJointFollowerColor();
  347. const AZ::Transform followerWorldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(GetEntityId());
  348. const AZ::Vector3 followerWorldPosition = followerWorldTransform.GetTranslation();
  349. const AZ::Transform jointLocalTransform = AZ::Transform::CreateFromQuaternionAndTranslation(AZ::Quaternion::CreateFromEulerAnglesDegrees(m_config.m_localRotation),
  350. m_config.m_localPosition);
  351. const AZ::Vector3 jointWorldPosition = PhysX::Utils::ComputeJointWorldTransform(jointLocalTransform, followerWorldTransform).GetTranslation();
  352. const float distance = followerWorldPosition.GetDistance(jointWorldPosition);
  353. const float lineWidth = 4.0f;
  354. AZ::u32 stateBefore = debugDisplay.GetState();
  355. debugDisplay.DepthTestOff();
  356. debugDisplay.SetColor(leadLineColor);
  357. debugDisplay.SetLineWidth(lineWidth);
  358. if (distance < displayData.m_jointHierarchyDistanceThreshold)
  359. {
  360. const AZ::Transform leadWorldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(GetEntity()->GetTransform()->GetParentId());
  361. const AZ::Vector3 leadWorldPosition = leadWorldTransform.GetTranslation();
  362. const AZ::Vector3 midPoint = (jointWorldPosition + leadWorldPosition) * 0.5f;
  363. debugDisplay.DrawLine(jointWorldPosition, midPoint);
  364. debugDisplay.SetColor(followerLineColor);
  365. debugDisplay.DrawLine(midPoint, leadWorldPosition);
  366. }
  367. else
  368. {
  369. const AZ::Vector3 midPoint = (jointWorldPosition + followerWorldPosition) * 0.5f;
  370. debugDisplay.DrawLine(jointWorldPosition, midPoint);
  371. debugDisplay.SetColor(followerLineColor);
  372. debugDisplay.DrawLine(midPoint, followerWorldPosition);
  373. }
  374. debugDisplay.SetState(stateBefore);
  375. }
  376. }
  377. void EditorArticulationLinkComponent::ShowHingeJoint(
  378. const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) const
  379. {
  380. const float s_alpha = 0.6f;
  381. const AZ::Color s_colorDefault = AZ::Color(1.0f, 1.0f, 1.0f, s_alpha);
  382. const AZ::Color s_colorFirst = AZ::Color(1.0f, 0.0f, 0.0f, s_alpha);
  383. const AZ::Color s_colorSecond = AZ::Color(0.0f, 1.0f, 0.0f, s_alpha);
  384. const AZ::Color s_colorSweepArc = AZ::Color(1.0f, 1.0f, 1.0f, s_alpha);
  385. AngleLimitsFloatPair currentValue(m_config.m_angularLimitPositive, m_config.m_angularLimitNegative);
  386. AZ::Vector3 axis = AZ::Vector3::CreateAxisX();
  387. const AZ::EntityId& entityId = GetEntityId();
  388. const AZ::Transform jointLocalTransform = AZ::Transform::CreateFromQuaternionAndTranslation(
  389. AZ::Quaternion::CreateFromEulerAnglesDegrees(m_config.m_localRotation), m_config.m_localPosition);
  390. const AZ::Transform jointWorldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(entityId) * jointLocalTransform;
  391. const AzFramework::CameraState cameraState = AzToolsFramework::GetCameraState(viewportInfo.m_viewportId);
  392. // scaleMultiply will represent a scale for the debug draw that makes it remain the same size on screen
  393. float scaleMultiply = AzToolsFramework::CalculateScreenToWorldMultiplier(jointWorldTransform.GetTranslation(), cameraState);
  394. const float size = 2.0f * scaleMultiply;
  395. AZ::u32 stateBefore = debugDisplay.GetState();
  396. debugDisplay.CullOff();
  397. debugDisplay.SetAlpha(s_alpha);
  398. debugDisplay.PushMatrix(jointWorldTransform);
  399. // draw a cylinder to indicate the axis of revolution.
  400. const float cylinderThickness = 0.05f * scaleMultiply;
  401. debugDisplay.SetColor(s_colorFirst);
  402. debugDisplay.DrawSolidCylinder(AZ::Vector3::CreateZero(), AZ::Vector3::CreateAxisX(), cylinderThickness, size, true);
  403. if (m_config.m_isLimited)
  404. {
  405. // if we are angularly limited, then show the limits, with an arc between them:
  406. AZ::Vector3 axisPoint = axis * size * 0.5f;
  407. AZ::Vector3 points[4] = { -axisPoint, axisPoint, axisPoint, -axisPoint };
  408. if (axis == AZ::Vector3::CreateAxisX())
  409. {
  410. points[2].SetZ(size);
  411. points[3].SetZ(size);
  412. }
  413. else if (axis == AZ::Vector3::CreateAxisY())
  414. {
  415. points[2].SetX(size);
  416. points[3].SetX(size);
  417. }
  418. else if (axis == AZ::Vector3::CreateAxisZ())
  419. {
  420. points[2].SetX(size);
  421. points[3].SetX(size);
  422. }
  423. debugDisplay.SetColor(s_colorSweepArc);
  424. const float sweepLineDisplaceFactor = 0.5f;
  425. const float sweepLineThickness = 1.0f * scaleMultiply;
  426. const float sweepLineGranularity = 1.0f;
  427. const AZ::Vector3 zeroVector = AZ::Vector3::CreateZero();
  428. const AZ::Vector3 posPosition = axis * sweepLineDisplaceFactor * scaleMultiply;
  429. const AZ::Vector3 negPosition = -posPosition;
  430. debugDisplay.DrawArc(posPosition, sweepLineThickness, -currentValue.first, currentValue.first, sweepLineGranularity, -axis);
  431. debugDisplay.DrawArc(zeroVector, sweepLineThickness, -currentValue.first, currentValue.first, sweepLineGranularity, -axis);
  432. debugDisplay.DrawArc(negPosition, sweepLineThickness, -currentValue.first, currentValue.first, sweepLineGranularity, -axis);
  433. debugDisplay.DrawArc(posPosition, sweepLineThickness, 0.0f, abs(currentValue.second), sweepLineGranularity, -axis);
  434. debugDisplay.DrawArc(zeroVector, sweepLineThickness, 0.0f, abs(currentValue.second), sweepLineGranularity, -axis);
  435. debugDisplay.DrawArc(negPosition, sweepLineThickness, 0.0f, abs(currentValue.second), sweepLineGranularity, -axis);
  436. AZ::Quaternion firstRotate = AZ::Quaternion::CreateFromAxisAngle(axis, AZ::DegToRad(currentValue.first));
  437. AZ::Transform firstTM = AZ::Transform::CreateFromQuaternion(firstRotate);
  438. debugDisplay.PushMatrix(firstTM);
  439. debugDisplay.SetColor(s_colorFirst);
  440. debugDisplay.DrawQuad(points[0], points[1], points[2], points[3]);
  441. debugDisplay.PopMatrix();
  442. AZ::Quaternion secondRotate = AZ::Quaternion::CreateFromAxisAngle(axis, AZ::DegToRad(currentValue.second));
  443. AZ::Transform secondTM = AZ::Transform::CreateFromQuaternion(secondRotate);
  444. debugDisplay.PushMatrix(secondTM);
  445. debugDisplay.SetColor(s_colorSecond);
  446. debugDisplay.DrawQuad(points[0], points[1], points[2], points[3]);
  447. debugDisplay.PopMatrix();
  448. debugDisplay.SetColor(s_colorDefault);
  449. debugDisplay.DrawQuad(points[0], points[1], points[2], points[3]);
  450. }
  451. else // if we are not limited, show direction of revolve instead
  452. {
  453. debugDisplay.SetColor(s_colorSweepArc);
  454. const float circleRadius = 0.6f * scaleMultiply;
  455. const float coneRadius = 0.05 * scaleMultiply;
  456. const float coneHeight = 0.2f * scaleMultiply;
  457. debugDisplay.DrawCircle(AZ::Vector3::CreateZero(), 1.0f * circleRadius, 0);
  458. // show tick-marks on the revolve axis that indicate the positive direction of revolution
  459. AZ::Vector3 pointOnCircle = circleRadius * AZ::Vector3::CreateAxisY();
  460. debugDisplay.DrawWireCone(pointOnCircle, -AZ::Vector3::CreateAxisZ(), coneRadius, coneHeight);
  461. pointOnCircle = -circleRadius * AZ::Vector3::CreateAxisY();
  462. debugDisplay.DrawWireCone(pointOnCircle, AZ::Vector3::CreateAxisZ(), coneRadius, coneHeight);
  463. pointOnCircle = circleRadius * AZ::Vector3::CreateAxisZ();
  464. debugDisplay.DrawWireCone(pointOnCircle, AZ::Vector3::CreateAxisY(), coneRadius, coneHeight);
  465. pointOnCircle = -circleRadius * AZ::Vector3::CreateAxisZ();
  466. debugDisplay.DrawWireCone(pointOnCircle, -AZ::Vector3::CreateAxisY(), coneRadius, coneHeight);
  467. }
  468. debugDisplay.PopMatrix(); // pop joint world transform
  469. debugDisplay.SetState(stateBefore);
  470. }
  471. void EditorArticulationLinkComponent::ShowPrismaticJoint(
  472. const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) const
  473. {
  474. const float alpha = 0.6f;
  475. const AZ::Color colorDefault = AZ::Color(1.0f, 1.0f, 1.0f, alpha);
  476. const AZ::Color colorLimitLower = AZ::Color(1.0f, 0.0f, 0.0f, alpha);
  477. const AZ::Color colorLimitUpper = AZ::Color(0.0f, 1.0f, 0.0f, alpha);
  478. AZ::u32 stateBefore = debugDisplay.GetState();
  479. debugDisplay.CullOff();
  480. debugDisplay.SetAlpha(alpha);
  481. const AZ::EntityId& entityId = GetEntityId();
  482. const AZ::Transform jointLocalTransform = AZ::Transform::CreateFromQuaternionAndTranslation(
  483. AZ::Quaternion::CreateFromEulerAnglesDegrees(m_config.m_localRotation), m_config.m_localPosition);
  484. const AZ::Transform jointWorldTransform = PhysX::Utils::GetEntityWorldTransformWithoutScale(entityId) * jointLocalTransform;
  485. const AzFramework::CameraState cameraState = AzToolsFramework::GetCameraState(viewportInfo.m_viewportId);
  486. // scaleMultiply will represent a scale for the debug draw that makes it remain the same size on screen
  487. float scaleMultiply = AzToolsFramework::CalculateScreenToWorldMultiplier(jointWorldTransform.GetTranslation(), cameraState);
  488. const float size = 1.0f * scaleMultiply;
  489. debugDisplay.PushMatrix(jointWorldTransform);
  490. debugDisplay.SetColor(colorDefault);
  491. debugDisplay.DrawLine(AZ::Vector3::CreateAxisX(m_config.m_linearLimitLower), AZ::Vector3::CreateAxisX(m_config.m_linearLimitUpper));
  492. debugDisplay.SetColor(colorLimitLower);
  493. debugDisplay.DrawQuad(
  494. AZ::Vector3(m_config.m_linearLimitLower, -size, -size),
  495. AZ::Vector3(m_config.m_linearLimitLower, -size, size),
  496. AZ::Vector3(m_config.m_linearLimitLower, size, size),
  497. AZ::Vector3(m_config.m_linearLimitLower, size, -size));
  498. debugDisplay.SetColor(colorLimitUpper);
  499. debugDisplay.DrawQuad(
  500. AZ::Vector3(m_config.m_linearLimitUpper, -size, -size),
  501. AZ::Vector3(m_config.m_linearLimitUpper, -size, size),
  502. AZ::Vector3(m_config.m_linearLimitUpper, size, size),
  503. AZ::Vector3(m_config.m_linearLimitUpper, size, -size));
  504. debugDisplay.PopMatrix(); // pop joint world transform
  505. debugDisplay.SetState(stateBefore);
  506. }
  507. } // namespace PhysX