DebugDrawSystemComponent.cpp 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240
  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/SerializeContext.h>
  9. #include <AzCore/Serialization/EditContext.h>
  10. #include <AzCore/Component/TickBus.h>
  11. #include <AzCore/Component/TransformBus.h>
  12. #include <AzCore/RTTI/BehaviorContext.h>
  13. #include <AzCore/std/parallel/lock.h>
  14. #include "DebugDrawSystemComponent.h"
  15. // Editor specific
  16. #ifdef DEBUGDRAW_GEM_EDITOR
  17. #include "EditorDebugDrawComponentCommon.h" // for Reflection
  18. #include "EditorDebugDrawLineComponent.h"
  19. #include "EditorDebugDrawRayComponent.h"
  20. #include "EditorDebugDrawSphereComponent.h"
  21. #include "EditorDebugDrawObbComponent.h"
  22. #include "EditorDebugDrawTextComponent.h"
  23. #include <AzToolsFramework/Entity/EditorEntityContextComponent.h>
  24. #endif // DEBUGDRAW_GEM_EDITOR
  25. #include <Atom/RPI.Public/RPISystemInterface.h>
  26. #include <Atom/RPI.Public/RPIUtils.h>
  27. #include <Atom/RPI.Public/Scene.h>
  28. namespace
  29. {
  30. AZ::Uuid UuidFromEntityId(const AZ::EntityId& entityId)
  31. {
  32. AZ::u64 entityIdNumber = static_cast<AZ::u64>(entityId);
  33. return AZ::Uuid::CreateData(reinterpret_cast<const AZStd::byte*>(&entityIdNumber), sizeof(AZ::u64));
  34. }
  35. }
  36. namespace DebugDraw
  37. {
  38. void DebugDrawSystemComponent::Reflect(AZ::ReflectContext* context)
  39. {
  40. #ifdef DEBUGDRAW_GEM_EDITOR
  41. EditorDebugDrawComponentSettings::Reflect(context);
  42. #endif // DEBUGDRAW_GEM_EDITOR
  43. if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
  44. {
  45. serialize->Class<DebugDrawSystemComponent, AZ::Component>()
  46. ->Version(0);
  47. if (AZ::EditContext* ec = serialize->GetEditContext())
  48. {
  49. ec->Class<DebugDrawSystemComponent>("DebugDraw", "Provides game runtime debug visualization.")
  50. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  51. ->Attribute(AZ::Edit::Attributes::Category, "Debugging")
  52. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  53. ;
  54. }
  55. }
  56. if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
  57. {
  58. behaviorContext->EBus<DebugDrawRequestBus>("DebugDrawRequestBus")
  59. ->Attribute(AZ::Script::Attributes::Category, "Debug")
  60. ->Event("DrawAabb", &DebugDrawRequestBus::Events::DrawAabb)
  61. ->Event("DrawAabbOnEntity", &DebugDrawRequestBus::Events::DrawAabbOnEntity)
  62. ->Event("DrawLineLocationToLocation", &DebugDrawRequestBus::Events::DrawLineLocationToLocation)
  63. ->Event("DrawLineEntityToLocation", &DebugDrawRequestBus::Events::DrawLineEntityToLocation)
  64. ->Event("DrawLineEntityToEntity", &DebugDrawRequestBus::Events::DrawLineEntityToEntity)
  65. ->Event("DrawObb", &DebugDrawRequestBus::Events::DrawObb)
  66. ->Event("DrawObbOnEntity", &DebugDrawRequestBus::Events::DrawObbOnEntity)
  67. ->Event("DrawRayLocationToDirection", &DebugDrawRequestBus::Events::DrawRayLocationToDirection)
  68. ->Event("DrawRayEntityToDirection", &DebugDrawRequestBus::Events::DrawRayEntityToDirection)
  69. ->Event("DrawRayEntityToEntity", &DebugDrawRequestBus::Events::DrawRayEntityToEntity)
  70. ->Event("DrawSphereAtLocation", &DebugDrawRequestBus::Events::DrawSphereAtLocation)
  71. ->Event("DrawSphereOnEntity", &DebugDrawRequestBus::Events::DrawSphereOnEntity)
  72. ->Event("DrawTextAtLocation", &DebugDrawRequestBus::Events::DrawTextAtLocation)
  73. ->Event("DrawTextOnEntity", &DebugDrawRequestBus::Events::DrawTextOnEntity)
  74. ->Event("DrawTextOnScreen", &DebugDrawRequestBus::Events::DrawTextOnScreen)
  75. ;
  76. }
  77. }
  78. void DebugDrawSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  79. {
  80. provided.push_back(AZ_CRC("DebugDrawService", 0x651d8874));
  81. }
  82. void DebugDrawSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
  83. {
  84. incompatible.push_back(AZ_CRC("DebugDrawService", 0x651d8874));
  85. }
  86. void DebugDrawSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
  87. {
  88. required.push_back(AZ_CRC("RPISystem", 0xf2add773));
  89. }
  90. void DebugDrawSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
  91. {
  92. (void)dependent;
  93. }
  94. void DebugDrawSystemComponent::Init()
  95. {
  96. }
  97. void DebugDrawSystemComponent::Activate()
  98. {
  99. DebugDrawInternalRequestBus::Handler::BusConnect();
  100. DebugDrawRequestBus::Handler::BusConnect();
  101. AZ::Render::Bootstrap::NotificationBus::Handler::BusConnect();
  102. #ifdef DEBUGDRAW_GEM_EDITOR
  103. AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusConnect();
  104. #endif // DEBUGDRAW_GEM_EDITOR
  105. }
  106. void DebugDrawSystemComponent::Deactivate()
  107. {
  108. #ifdef DEBUGDRAW_GEM_EDITOR
  109. AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusDisconnect();
  110. #endif // DEBUGDRAW_GEM_EDITOR
  111. AZ::RPI::SceneNotificationBus::Handler::BusDisconnect();
  112. DebugDrawRequestBus::Handler::BusDisconnect();
  113. DebugDrawInternalRequestBus::Handler::BusDisconnect();
  114. {
  115. AZStd::lock_guard<AZStd::mutex> locker(m_activeAabbsMutex);
  116. m_activeAabbs.clear();
  117. }
  118. {
  119. AZStd::lock_guard<AZStd::mutex> locker(m_activeLinesMutex);
  120. m_activeLines.clear();
  121. }
  122. {
  123. AZStd::lock_guard<AZStd::mutex> locker(m_activeObbsMutex);
  124. for (const auto& obb : m_activeObbs)
  125. {
  126. RemoveRaytracingData(obb);
  127. }
  128. m_activeObbs.clear();
  129. }
  130. {
  131. AZStd::lock_guard<AZStd::mutex> locker(m_activeRaysMutex);
  132. m_activeRays.clear();
  133. }
  134. {
  135. AZStd::lock_guard<AZStd::mutex> locker(m_activeSpheresMutex);
  136. for (const auto& sphere : m_activeSpheres)
  137. {
  138. RemoveRaytracingData(sphere);
  139. }
  140. m_activeSpheres.clear();
  141. }
  142. {
  143. AZStd::lock_guard<AZStd::mutex> locker(m_activeTextsMutex);
  144. m_activeTexts.clear();
  145. }
  146. m_sphereRayTracingTypeHandle.Free();
  147. m_obbRayTracingTypeHandle.Free();
  148. m_spheresRayTracingIndicesBuffer.reset();
  149. m_spheresRayTracingIndices.Reset();
  150. }
  151. void DebugDrawSystemComponent::OnBootstrapSceneReady(AZ::RPI::Scene* scene)
  152. {
  153. AZ_Assert(scene, "Invalid scene received in OnBootstrapSceneReady");
  154. AZ::RPI::SceneNotificationBus::Handler::BusDisconnect();
  155. AZ::RPI::SceneNotificationBus::Handler::BusConnect(scene->GetId());
  156. }
  157. #ifdef DEBUGDRAW_GEM_EDITOR
  158. void DebugDrawSystemComponent::OnStopPlayInEditor()
  159. {
  160. // Remove all debug elements that weren't triggered by editor components
  161. // We need this check because OnStopPlayInEditor() is called AFTER editor entities
  162. // have been re-activated, so at this time we have both our game AND editor
  163. // debug drawings active
  164. // Aabbs
  165. {
  166. AZStd::lock_guard<AZStd::mutex> locker(m_activeAabbsMutex);
  167. AZStd::vector<DebugDrawAabbElement> elementsToSave;
  168. for (const DebugDrawAabbElement& element : m_activeAabbs)
  169. {
  170. if (element.m_owningEditorComponent != AZ::InvalidComponentId)
  171. {
  172. elementsToSave.push_back(element);
  173. }
  174. }
  175. m_activeAabbs.clear();
  176. m_activeAabbs.assign_rv(AZStd::forward<AZStd::vector<DebugDrawAabbElement>>(elementsToSave));
  177. }
  178. // Lines
  179. {
  180. AZStd::lock_guard<AZStd::mutex> locker(m_activeLinesMutex);
  181. AZStd::vector<DebugDrawLineElement> elementsToSave;
  182. for (const DebugDrawLineElement& element : m_activeLines)
  183. {
  184. if (element.m_owningEditorComponent != AZ::InvalidComponentId)
  185. {
  186. elementsToSave.push_back(element);
  187. }
  188. }
  189. m_activeLines.clear();
  190. m_activeLines.assign_rv(AZStd::forward<AZStd::vector<DebugDrawLineElement>>(elementsToSave));
  191. }
  192. // Obbs
  193. {
  194. AZStd::lock_guard<AZStd::mutex> locker(m_activeObbsMutex);
  195. AZStd::vector<DebugDrawObbElementWrapper> elementsToSave;
  196. for (const DebugDrawObbElementWrapper& element : m_activeObbs)
  197. {
  198. if (element.m_owningEditorComponent != AZ::InvalidComponentId)
  199. {
  200. elementsToSave.push_back(element);
  201. }
  202. }
  203. m_activeObbs.clear();
  204. m_activeObbs.assign_rv(AZStd::forward<AZStd::vector<DebugDrawObbElementWrapper>>(elementsToSave));
  205. }
  206. // Rays
  207. {
  208. AZStd::lock_guard<AZStd::mutex> locker(m_activeRaysMutex);
  209. AZStd::vector<DebugDrawRayElement> elementsToSave;
  210. for (const DebugDrawRayElement& element : m_activeRays)
  211. {
  212. if (element.m_owningEditorComponent != AZ::InvalidComponentId)
  213. {
  214. elementsToSave.push_back(element);
  215. }
  216. }
  217. m_activeRays.clear();
  218. m_activeRays.assign_rv(AZStd::forward<AZStd::vector<DebugDrawRayElement>>(elementsToSave));
  219. }
  220. // Spheres
  221. {
  222. AZStd::lock_guard<AZStd::mutex> locker(m_activeSpheresMutex);
  223. AZStd::vector<DebugDrawSphereElementWrapper> elementsToSave;
  224. for (const DebugDrawSphereElementWrapper& element : m_activeSpheres)
  225. {
  226. if (element.m_owningEditorComponent != AZ::InvalidComponentId)
  227. {
  228. elementsToSave.push_back(element);
  229. }
  230. }
  231. m_activeSpheres.clear();
  232. m_activeSpheres.assign_rv(AZStd::forward<AZStd::vector<DebugDrawSphereElementWrapper>>(elementsToSave));
  233. }
  234. // Text
  235. {
  236. AZStd::lock_guard<AZStd::mutex> locker(m_activeTextsMutex);
  237. AZStd::vector<DebugDrawTextElement> elementsToSave;
  238. for (const DebugDrawTextElement& element : m_activeTexts)
  239. {
  240. if (element.m_owningEditorComponent != AZ::InvalidComponentId)
  241. {
  242. elementsToSave.push_back(element);
  243. }
  244. }
  245. m_activeTexts.clear();
  246. m_activeTexts.assign_rv(AZStd::forward<AZStd::vector<DebugDrawTextElement>>(elementsToSave));
  247. }
  248. }
  249. #endif // DEBUGDRAW_GEM_EDITOR
  250. void DebugDrawSystemComponent::OnBeginPrepareRender()
  251. {
  252. AZ::ScriptTimePoint time;
  253. AZ::TickRequestBus::BroadcastResult(time, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  254. m_currentTime = time.GetSeconds();
  255. AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus;
  256. AzFramework::DebugDisplayRequestBus::Bind(
  257. debugDisplayBus, AzFramework::g_defaultSceneEntityDebugDisplayId);
  258. AZ_Assert(debugDisplayBus, "Invalid DebugDisplayRequestBus.");
  259. AzFramework::DebugDisplayRequests* debugDisplay =
  260. AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus);
  261. if (debugDisplay)
  262. {
  263. OnTickAabbs(*debugDisplay);
  264. OnTickLines(*debugDisplay);
  265. OnTickObbs(*debugDisplay);
  266. OnTickRays(*debugDisplay);
  267. OnTickSpheres(*debugDisplay);
  268. OnTickText(*debugDisplay);
  269. }
  270. }
  271. template <typename F>
  272. void DebugDrawSystemComponent::removeExpiredDebugElementsFromVector(AZStd::vector<F>& vectorToExpire)
  273. {
  274. auto removalCondition = std::remove_if(std::begin(vectorToExpire), std::end(vectorToExpire), [this](F& element)
  275. {
  276. return element.m_duration == 0.0f || (element.m_duration > 0.0f && (element.m_activateTime.GetSeconds() + element.m_duration <= m_currentTime));
  277. });
  278. vectorToExpire.erase(removalCondition, std::end(vectorToExpire));
  279. }
  280. void DebugDrawSystemComponent::OnTickAabbs(AzFramework::DebugDisplayRequests& debugDisplay)
  281. {
  282. AZStd::lock_guard<AZStd::mutex> locker(m_activeAabbsMutex);
  283. // Draw Aabb elements and remove any that are expired
  284. for (auto& aabbElement : m_activeAabbs)
  285. {
  286. AZ::Aabb transformedAabb(aabbElement.m_aabb);
  287. // Query for entity location if this Aabb is attached to an entity
  288. if (aabbElement.m_targetEntityId.IsValid())
  289. {
  290. AZ::TransformBus::EventResult(aabbElement.m_worldLocation, aabbElement.m_targetEntityId, &AZ::TransformBus::Events::GetWorldTranslation);
  291. // Re-center
  292. AZ::Vector3 currentCenter = transformedAabb.GetCenter();
  293. transformedAabb.Set(transformedAabb.GetMin() - currentCenter + aabbElement.m_worldLocation, transformedAabb.GetMax() - currentCenter + aabbElement.m_worldLocation);
  294. }
  295. debugDisplay.SetColor(aabbElement.m_color);
  296. debugDisplay.DrawSolidBox(transformedAabb.GetMin(), transformedAabb.GetMax());
  297. }
  298. removeExpiredDebugElementsFromVector(m_activeAabbs);
  299. }
  300. void DebugDrawSystemComponent::OnTickLines(AzFramework::DebugDisplayRequests& debugDisplay)
  301. {
  302. AZStd::lock_guard<AZStd::mutex> locker(m_activeLinesMutex);
  303. size_t numActiveLines = m_activeLines.size();
  304. m_batchPoints.clear();
  305. m_batchColors.clear();
  306. m_batchPoints.reserve(numActiveLines * 2);
  307. m_batchColors.reserve(numActiveLines * 2);
  308. // Draw line elements and remove any that are expired
  309. for (auto& lineElement : m_activeLines)
  310. {
  311. // Query for entity locations if this line starts or ends at valid entities.
  312. // Nice thing with this setup where we're using the lineElement's locations to query is that
  313. // when one of the entities gets destroyed, we'll keep drawing to its last known location (if
  314. // that entity deactivation didn't result in the line no longer being drawn)
  315. if (lineElement.m_startEntityId.IsValid())
  316. {
  317. AZ::TransformBus::EventResult(
  318. lineElement.m_startWorldLocation,
  319. lineElement.m_startEntityId,
  320. &AZ::TransformBus::Events::GetWorldTranslation);
  321. }
  322. if (lineElement.m_endEntityId.IsValid())
  323. {
  324. AZ::TransformBus::EventResult(
  325. lineElement.m_endWorldLocation,
  326. lineElement.m_endEntityId,
  327. &AZ::TransformBus::Events::GetWorldTranslation);
  328. }
  329. debugDisplay.SetColor(lineElement.m_color);
  330. debugDisplay.DrawLine(lineElement.m_startWorldLocation, lineElement.m_endWorldLocation);
  331. }
  332. removeExpiredDebugElementsFromVector(m_activeLines);
  333. }
  334. void DebugDrawSystemComponent::OnTickObbs(AzFramework::DebugDisplayRequests& debugDisplay)
  335. {
  336. AZStd::lock_guard<AZStd::mutex> locker(m_activeObbsMutex);
  337. // Draw Obb elements and remove any that are expired
  338. for (auto& obbElement : m_activeObbs)
  339. {
  340. AZ::Obb transformedObb = obbElement.m_obb;
  341. // Entity-attached Obbs get positioned and rotated according to entity transform
  342. if (obbElement.m_targetEntityId.IsValid())
  343. {
  344. AZ::Transform entityTM;
  345. AZ::TransformBus::EventResult(entityTM, obbElement.m_targetEntityId, &AZ::TransformBus::Events::GetWorldTM);
  346. obbElement.m_worldLocation = entityTM.GetTranslation();
  347. transformedObb.SetPosition(AZ::Vector3::CreateZero());
  348. transformedObb = entityTM * transformedObb;
  349. //set half lengths based on editor values
  350. for (unsigned i = 0; i <= 2; ++i)
  351. {
  352. transformedObb.SetHalfLength(i, obbElement.m_scale.GetElement(i));
  353. }
  354. }
  355. else
  356. {
  357. obbElement.m_worldLocation = transformedObb.GetPosition();
  358. }
  359. debugDisplay.SetColor(obbElement.m_color);
  360. debugDisplay.DrawSolidOBB(obbElement.m_worldLocation, transformedObb.GetAxisX(), transformedObb.GetAxisY(), transformedObb.GetAxisZ(), transformedObb.GetHalfLengths());
  361. if (m_rayTracingFeatureProcessor && obbElement.m_isRayTracingEnabled &&
  362. (obbElement.m_worldLocation != obbElement.m_previousWorldLocation ||
  363. obbElement.m_scale != obbElement.m_previousScale ||
  364. transformedObb.GetRotation() != obbElement.m_previousRotation))
  365. {
  366. AZ::Transform obbTransform(obbElement.m_worldLocation, transformedObb.GetRotation(), 1.f);
  367. m_rayTracingFeatureProcessor->SetProceduralGeometryTransform(UuidFromEntityId(obbElement.m_targetEntityId), obbTransform, obbElement.m_scale);
  368. obbElement.m_previousWorldLocation = obbElement.m_worldLocation;
  369. obbElement.m_previousScale = obbElement.m_scale;
  370. obbElement.m_previousRotation = transformedObb.GetRotation();
  371. }
  372. }
  373. removeExpiredDebugElementsFromVector(m_activeObbs);
  374. }
  375. void DebugDrawSystemComponent::OnTickRays(AzFramework::DebugDisplayRequests& debugDisplay)
  376. {
  377. AZStd::lock_guard<AZStd::mutex> locker(m_activeRaysMutex);
  378. // Draw ray elements and remove any that are expired
  379. for (auto& rayElement : m_activeRays)
  380. {
  381. // Query for entity locations if this ray starts or ends at valid entities.
  382. if (rayElement.m_startEntityId.IsValid())
  383. {
  384. AZ::TransformBus::EventResult(rayElement.m_worldLocation, rayElement.m_startEntityId, &AZ::TransformBus::Events::GetWorldTranslation);
  385. }
  386. AZ::Vector3 endWorldLocation(rayElement.m_worldLocation + rayElement.m_worldDirection);
  387. if (rayElement.m_endEntityId.IsValid())
  388. {
  389. AZ::TransformBus::EventResult(endWorldLocation, rayElement.m_endEntityId, &AZ::TransformBus::Events::GetWorldTranslation);
  390. rayElement.m_worldDirection = (endWorldLocation - rayElement.m_worldLocation);
  391. }
  392. float conePercentHeight = 0.5f;
  393. float coneHeight = rayElement.m_worldDirection.GetLength() * conePercentHeight;
  394. AZ::Vector3 coneBaseLocation = endWorldLocation - rayElement.m_worldDirection * conePercentHeight;
  395. float coneRadius = AZ::GetClamp(coneHeight * 0.07f, 0.05f, 0.2f);
  396. debugDisplay.SetColor(rayElement.m_color);
  397. debugDisplay.SetLineWidth(5.0f);
  398. debugDisplay.DrawLine(rayElement.m_worldLocation, coneBaseLocation);
  399. debugDisplay.DrawSolidCone(coneBaseLocation, rayElement.m_worldDirection, coneRadius, coneHeight, false);
  400. }
  401. removeExpiredDebugElementsFromVector(m_activeRays);
  402. }
  403. void DebugDrawSystemComponent::OnTickSpheres(AzFramework::DebugDisplayRequests& debugDisplay)
  404. {
  405. AZStd::lock_guard<AZStd::mutex> locker(m_activeSpheresMutex);
  406. // Draw sphere elements and remove any that are expired
  407. for (auto& sphereElement : m_activeSpheres)
  408. {
  409. // Query for entity location if this sphere is attached to an entity
  410. if (sphereElement.m_targetEntityId.IsValid())
  411. {
  412. AZ::TransformBus::EventResult(sphereElement.m_worldLocation, sphereElement.m_targetEntityId, &AZ::TransformBus::Events::GetWorldTranslation);
  413. }
  414. debugDisplay.SetColor(sphereElement.m_color);
  415. debugDisplay.DrawBall(sphereElement.m_worldLocation, sphereElement.m_radius, true);
  416. if (m_rayTracingFeatureProcessor && sphereElement.m_isRayTracingEnabled &&
  417. (sphereElement.m_worldLocation != sphereElement.m_previousWorldLocation ||
  418. sphereElement.m_radius != sphereElement.m_previousRadius))
  419. {
  420. AZ::Transform sphereTransform(sphereElement.m_worldLocation, AZ::Quaternion::CreateIdentity(), sphereElement.m_radius);
  421. m_rayTracingFeatureProcessor->SetProceduralGeometryTransform(
  422. UuidFromEntityId(sphereElement.m_targetEntityId), sphereTransform);
  423. sphereElement.m_previousWorldLocation = sphereElement.m_worldLocation;
  424. sphereElement.m_previousRadius = sphereElement.m_radius;
  425. }
  426. }
  427. removeExpiredDebugElementsFromVector(m_activeSpheres);
  428. }
  429. void DebugDrawSystemComponent::OnTickText(AzFramework::DebugDisplayRequests& debugDisplay)
  430. {
  431. AZStd::lock_guard<AZStd::mutex> locker(m_activeTextsMutex);
  432. // Determine if we need gamma conversion
  433. bool needsGammaConversion = false;
  434. #ifdef DEBUGDRAW_GEM_EDITOR
  435. bool isInGameMode = true;
  436. AzToolsFramework::EditorEntityContextRequestBus::BroadcastResult(isInGameMode, &AzToolsFramework::EditorEntityContextRequestBus::Events::IsEditorRunningGame);
  437. if (isInGameMode)
  438. {
  439. needsGammaConversion = true;
  440. }
  441. #endif // DEBUGDRAW_GEM_EDITOR
  442. // Draw text elements and remove any that are expired
  443. float currentOnScreenY = 20.f; // Initial shift down for the 1st line, then recalculate shifts down for next lines accounting for textElement.m_fontScale
  444. AZ::EntityId lastTargetEntityId;
  445. for (auto& textElement : m_activeTexts)
  446. {
  447. const AZ::Color textColor = needsGammaConversion ? textElement.m_color.GammaToLinear() : textElement.m_color;
  448. debugDisplay.SetColor(textColor);
  449. if (textElement.m_drawMode == DebugDrawTextElement::DrawMode::OnScreen)
  450. {
  451. if (textElement.m_useOnScreenCoordinates)
  452. {
  453. // Reuse textElement.m_worldLocation for 2D OnScreen positioning.
  454. debugDisplay.Draw2dTextLabel(textElement.m_worldLocation.GetX(),textElement.m_worldLocation.GetY(),textElement.m_fontScale
  455. , textElement.m_text.c_str(), textElement.m_bCenter);
  456. }
  457. else
  458. {
  459. // Hardcoded 2D OnScreen positioning as in original code. Note original code below with constant shifts.
  460. debugDisplay.Draw2dTextLabel(100.0f, currentOnScreenY, textElement.m_fontScale, textElement.m_text.c_str());
  461. // Prepare the shift down for a next line assuming default m_textSizeFactor = 12.0f + line gap.
  462. // Could be more precise if Draw2dTextLabel() returned drawn text size with current viewport settings.
  463. currentOnScreenY += textElement.m_fontScale * 14.0f + 2.0f;
  464. }
  465. }
  466. else if (textElement.m_drawMode == DebugDrawTextElement::DrawMode::InWorld)
  467. {
  468. AZ::Vector3 worldLocation;
  469. if (textElement.m_targetEntityId.IsValid())
  470. {
  471. // Entity text
  472. AZ::TransformBus::EventResult(worldLocation, textElement.m_targetEntityId, &AZ::TransformBus::Events::GetWorldTranslation);
  473. }
  474. else
  475. {
  476. // World text
  477. worldLocation = textElement.m_worldLocation;
  478. }
  479. debugDisplay.DrawTextLabel(worldLocation, textElement.m_size, textElement.m_text.c_str(), textElement.m_centered);
  480. }
  481. }
  482. removeExpiredDebugElementsFromVector(m_activeTexts);
  483. }
  484. void DebugDrawSystemComponent::RegisterDebugDrawComponent(AZ::Component* component)
  485. {
  486. AZ_Assert(component != nullptr, "Null component being registered!");
  487. AZ::EntityBus::MultiHandler::BusConnect(component->GetEntityId());
  488. if (DebugDrawLineComponent* lineComponent = azrtti_cast<DebugDrawLineComponent*>(component))
  489. {
  490. CreateLineEntryForComponent(lineComponent->GetEntityId(), lineComponent->m_element);
  491. }
  492. #ifdef DEBUGDRAW_GEM_EDITOR
  493. else if (EditorDebugDrawLineComponent* editorLineComponent = azrtti_cast<EditorDebugDrawLineComponent*>(component))
  494. {
  495. CreateLineEntryForComponent(editorLineComponent->GetEntityId(), editorLineComponent->m_element);
  496. }
  497. #endif // DEBUGDRAW_GEM_EDITOR
  498. else if (DebugDrawRayComponent* rayComponent = azrtti_cast<DebugDrawRayComponent*>(component))
  499. {
  500. CreateRayEntryForComponent(rayComponent->GetEntityId(), rayComponent->m_element);
  501. }
  502. #ifdef DEBUGDRAW_GEM_EDITOR
  503. else if (EditorDebugDrawRayComponent* editorRayComponent = azrtti_cast<EditorDebugDrawRayComponent*>(component))
  504. {
  505. CreateRayEntryForComponent(editorRayComponent->GetEntityId(), editorRayComponent->m_element);
  506. }
  507. #endif // DEBUGDRAW_GEM_EDITOR
  508. else if (DebugDrawSphereComponent* sphereComponent = azrtti_cast<DebugDrawSphereComponent*>(component))
  509. {
  510. CreateSphereEntryForComponent(sphereComponent->GetEntityId(), sphereComponent->m_element);
  511. }
  512. #ifdef DEBUGDRAW_GEM_EDITOR
  513. else if (EditorDebugDrawSphereComponent* editorSphereComponent = azrtti_cast<EditorDebugDrawSphereComponent*>(component))
  514. {
  515. CreateSphereEntryForComponent(editorSphereComponent->GetEntityId(), editorSphereComponent->m_element);
  516. }
  517. #endif // DEBUGDRAW_GEM_EDITOR
  518. else if (DebugDrawObbComponent* obbComponent = azrtti_cast<DebugDrawObbComponent*>(component))
  519. {
  520. CreateObbEntryForComponent(obbComponent->GetEntityId(), obbComponent->m_element);
  521. }
  522. #ifdef DEBUGDRAW_GEM_EDITOR
  523. else if (EditorDebugDrawObbComponent* editorObbComponent = azrtti_cast<EditorDebugDrawObbComponent*>(component))
  524. {
  525. CreateObbEntryForComponent(editorObbComponent->GetEntityId(), editorObbComponent->m_element);
  526. }
  527. #endif // DEBUGDRAW_GEM_EDITOR
  528. else if (DebugDrawTextComponent* textComponent = azrtti_cast<DebugDrawTextComponent*>(component))
  529. {
  530. CreateTextEntryForComponent(textComponent->GetEntityId(), textComponent->m_element);
  531. }
  532. #ifdef DEBUGDRAW_GEM_EDITOR
  533. else if (EditorDebugDrawTextComponent* editorTextComponent = azrtti_cast<EditorDebugDrawTextComponent*>(component))
  534. {
  535. CreateTextEntryForComponent(editorTextComponent->GetEntityId(), editorTextComponent->m_element);
  536. }
  537. #endif // DEBUGDRAW_GEM_EDITOR
  538. }
  539. void DebugDrawSystemComponent::OnEntityDeactivated(const AZ::EntityId& entityId)
  540. {
  541. AZ::EntityBus::MultiHandler::BusDisconnect(entityId);
  542. // Remove all associated entity-based debug elements for this entity
  543. // Lines
  544. {
  545. AZStd::lock_guard<AZStd::mutex> locker(m_activeLinesMutex);
  546. for (auto iter = m_activeLines.begin(); iter != m_activeLines.end();)
  547. {
  548. DebugDrawLineElement& element = *iter;
  549. if (element.m_startEntityId == entityId)
  550. {
  551. m_activeLines.erase(iter);
  552. }
  553. else
  554. {
  555. ++iter;
  556. }
  557. }
  558. }
  559. // Rays
  560. {
  561. AZStd::lock_guard<AZStd::mutex> locker(m_activeRaysMutex);
  562. for (auto iter = m_activeRays.begin(); iter != m_activeRays.end();)
  563. {
  564. DebugDrawRayElement& element = *iter;
  565. if (element.m_startEntityId == entityId)
  566. {
  567. m_activeRays.erase(iter);
  568. }
  569. else
  570. {
  571. ++iter;
  572. }
  573. }
  574. }
  575. // Obbs
  576. {
  577. AZStd::lock_guard<AZStd::mutex> locker(m_activeObbsMutex);
  578. for (auto iter = m_activeObbs.begin(); iter != m_activeObbs.end();)
  579. {
  580. DebugDrawObbElementWrapper& element = *iter;
  581. if (element.m_targetEntityId == entityId)
  582. {
  583. RemoveRaytracingData(element);
  584. m_activeObbs.erase(iter);
  585. }
  586. else
  587. {
  588. ++iter;
  589. }
  590. }
  591. }
  592. // Spheres
  593. {
  594. AZStd::lock_guard<AZStd::mutex> locker(m_activeSpheresMutex);
  595. for (auto iter = m_activeSpheres.begin(); iter != m_activeSpheres.end();)
  596. {
  597. DebugDrawSphereElementWrapper& element = *iter;
  598. if (element.m_targetEntityId == entityId)
  599. {
  600. RemoveRaytracingData(element);
  601. m_activeSpheres.erase(iter);
  602. }
  603. else
  604. {
  605. ++iter;
  606. }
  607. }
  608. }
  609. // Text
  610. {
  611. AZStd::lock_guard<AZStd::mutex> locker(m_activeTextsMutex);
  612. for (auto iter = m_activeTexts.begin(); iter != m_activeTexts.end();)
  613. {
  614. DebugDrawTextElement& element = *iter;
  615. if (element.m_targetEntityId == entityId)
  616. {
  617. m_activeTexts.erase(iter);
  618. }
  619. else
  620. {
  621. ++iter;
  622. }
  623. }
  624. }
  625. }
  626. void DebugDrawSystemComponent::UnregisterDebugDrawComponent(AZ::Component* component)
  627. {
  628. const AZ::EntityId componentEntityId = component->GetEntityId();
  629. const AZ::ComponentId componentId = component->GetId();
  630. // Remove specific associated entity-based debug element for this entity/component combo
  631. // Lines
  632. {
  633. AZStd::lock_guard<AZStd::mutex> locker(m_activeLinesMutex);
  634. for (auto iter = m_activeLines.begin(); iter != m_activeLines.end();)
  635. {
  636. DebugDrawLineElement& element = *iter;
  637. if (element.m_startEntityId == componentEntityId && element.m_owningEditorComponent == componentId)
  638. {
  639. m_activeLines.erase(iter);
  640. break; // Only one element per component
  641. }
  642. else
  643. {
  644. ++iter;
  645. }
  646. }
  647. }
  648. // Rays
  649. {
  650. AZStd::lock_guard<AZStd::mutex> locker(m_activeRaysMutex);
  651. for (auto iter = m_activeRays.begin(); iter != m_activeRays.end();)
  652. {
  653. DebugDrawRayElement& element = *iter;
  654. if (element.m_startEntityId == componentEntityId && element.m_owningEditorComponent == componentId)
  655. {
  656. m_activeRays.erase(iter);
  657. break; // Only one element per component
  658. }
  659. else
  660. {
  661. ++iter;
  662. }
  663. }
  664. }
  665. // Obbs
  666. {
  667. AZStd::lock_guard<AZStd::mutex> locker(m_activeObbsMutex);
  668. for (auto iter = m_activeObbs.begin(); iter != m_activeObbs.end();)
  669. {
  670. DebugDrawObbElementWrapper& element = *iter;
  671. if (element.m_targetEntityId == componentEntityId && element.m_owningEditorComponent == componentId)
  672. {
  673. RemoveRaytracingData(element);
  674. m_activeObbs.erase(iter);
  675. break; // Only one element per component
  676. }
  677. else
  678. {
  679. ++iter;
  680. }
  681. }
  682. }
  683. // Spheres
  684. {
  685. AZStd::lock_guard<AZStd::mutex> locker(m_activeSpheresMutex);
  686. for (auto iter = m_activeSpheres.begin(); iter != m_activeSpheres.end();)
  687. {
  688. DebugDrawSphereElementWrapper& element = *iter;
  689. if (element.m_targetEntityId == componentEntityId && element.m_owningEditorComponent == componentId)
  690. {
  691. RemoveRaytracingData(element);
  692. m_activeSpheres.erase(iter);
  693. break; // Only one element per component
  694. }
  695. else
  696. {
  697. ++iter;
  698. }
  699. }
  700. }
  701. // Text
  702. {
  703. AZStd::lock_guard<AZStd::mutex> locker(m_activeTextsMutex);
  704. for (auto iter = m_activeTexts.begin(); iter != m_activeTexts.end();)
  705. {
  706. DebugDrawTextElement& element = *iter;
  707. if (element.m_targetEntityId == componentEntityId && element.m_owningEditorComponent == componentId)
  708. {
  709. m_activeTexts.erase(iter);
  710. break; // Only one element per component
  711. }
  712. else
  713. {
  714. ++iter;
  715. }
  716. }
  717. }
  718. }
  719. ///////////////////////////////////////////////////////////////////////
  720. // Aabbs
  721. ///////////////////////////////////////////////////////////////////////
  722. void DebugDrawSystemComponent::DrawAabb(const AZ::Aabb& aabb, const AZ::Color& color, float duration)
  723. {
  724. AZStd::lock_guard<AZStd::mutex> locker(m_activeAabbsMutex);
  725. DebugDrawAabbElement& newElement = m_activeAabbs.emplace_back();
  726. newElement.m_aabb = aabb;
  727. newElement.m_color = color;
  728. newElement.m_duration = duration;
  729. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  730. }
  731. void DebugDrawSystemComponent::DrawAabbOnEntity(const AZ::EntityId& targetEntity, const AZ::Aabb& aabb, const AZ::Color& color, float duration)
  732. {
  733. AZStd::lock_guard<AZStd::mutex> locker(m_activeAabbsMutex);
  734. DebugDrawAabbElement& newElement = m_activeAabbs.emplace_back();
  735. newElement.m_targetEntityId = targetEntity;
  736. newElement.m_aabb = aabb;
  737. newElement.m_color = color;
  738. newElement.m_duration = duration;
  739. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  740. }
  741. void DebugDrawSystemComponent::CreateAabbEntryForComponent(const AZ::EntityId& componentEntityId, const DebugDrawAabbElement& element)
  742. {
  743. AZStd::lock_guard<AZStd::mutex> locker(m_activeAabbsMutex);
  744. m_activeAabbs.push_back(element);
  745. DebugDrawAabbElement& newElement = m_activeAabbs.back();
  746. newElement.m_duration = -1.0f; // Component-spawned text has infinite duration currently (can change in the future)
  747. newElement.m_targetEntityId = componentEntityId;
  748. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  749. }
  750. ///////////////////////////////////////////////////////////////////////
  751. // Lines
  752. ///////////////////////////////////////////////////////////////////////
  753. void DebugDrawSystemComponent::DrawLineBatchLocationToLocation(const AZStd::vector<DebugDraw::DebugDrawLineElement>& lineBatch)
  754. {
  755. AZStd::lock_guard<AZStd::mutex> locker(m_activeLinesMutex);
  756. m_activeLines.insert(m_activeLines.end(), lineBatch.begin(), lineBatch.end());
  757. }
  758. void DebugDrawSystemComponent::DrawLineLocationToLocation(const AZ::Vector3& startLocation, const AZ::Vector3& endLocation, const AZ::Color& color, float duration)
  759. {
  760. AZStd::lock_guard<AZStd::mutex> locker(m_activeLinesMutex);
  761. DebugDrawLineElement& newElement = m_activeLines.emplace_back();
  762. newElement.m_color = color;
  763. newElement.m_duration = duration;
  764. newElement.m_startWorldLocation = startLocation;
  765. newElement.m_endWorldLocation = endLocation;
  766. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  767. }
  768. void DebugDrawSystemComponent::DrawLineEntityToLocation(const AZ::EntityId& startEntity, const AZ::Vector3& endLocation, const AZ::Color& color, float duration)
  769. {
  770. AZStd::lock_guard<AZStd::mutex> locker(m_activeLinesMutex);
  771. DebugDrawLineElement& newElement = m_activeLines.emplace_back();
  772. newElement.m_color = color;
  773. newElement.m_duration = duration;
  774. newElement.m_startEntityId = startEntity; // Start of line is at this entity's location
  775. newElement.m_endWorldLocation = endLocation;
  776. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  777. }
  778. void DebugDrawSystemComponent::DrawLineEntityToEntity(const AZ::EntityId& startEntity, const AZ::EntityId& endEntity, const AZ::Color& color, float duration)
  779. {
  780. AZStd::lock_guard<AZStd::mutex> locker(m_activeLinesMutex);
  781. DebugDrawLineElement& newElement = m_activeLines.emplace_back();
  782. newElement.m_color = color;
  783. newElement.m_duration = duration;
  784. newElement.m_startEntityId = startEntity; // Start of line is at start entity's location
  785. newElement.m_endEntityId = endEntity; // End of line is at end entity's location
  786. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  787. }
  788. void DebugDrawSystemComponent::CreateLineEntryForComponent(const AZ::EntityId& componentEntityId, const DebugDrawLineElement& element)
  789. {
  790. AZStd::lock_guard<AZStd::mutex> locker(m_activeLinesMutex);
  791. m_activeLines.push_back(element);
  792. DebugDrawLineElement& newElement = m_activeLines.back();
  793. newElement.m_duration = -1.0f; // Component-spawned text has infinite duration currently (can change in the future)
  794. newElement.m_startEntityId = componentEntityId;
  795. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  796. }
  797. ///////////////////////////////////////////////////////////////////////
  798. // Obbs
  799. ///////////////////////////////////////////////////////////////////////
  800. void DebugDrawSystemComponent::DrawObb(const AZ::Obb& obb, const AZ::Color& color, float duration)
  801. {
  802. AZStd::lock_guard<AZStd::mutex> locker(m_activeObbsMutex);
  803. DebugDrawObbElementWrapper& newElement = m_activeObbs.emplace_back();
  804. newElement.m_obb = obb;
  805. newElement.m_color = color;
  806. newElement.m_duration = duration;
  807. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  808. }
  809. void DebugDrawSystemComponent::DrawObbOnEntity(const AZ::EntityId& targetEntity, const AZ::Obb& obb, const AZ::Color& color, bool enableRayTracing, float duration)
  810. {
  811. AZStd::lock_guard<AZStd::mutex> locker(m_activeObbsMutex);
  812. DebugDrawObbElementWrapper& newElement = m_activeObbs.emplace_back();
  813. newElement.m_targetEntityId = targetEntity;
  814. newElement.m_obb = obb;
  815. newElement.m_scale = obb.GetHalfLengths();
  816. newElement.m_color = color;
  817. newElement.m_isRayTracingEnabled = enableRayTracing;
  818. newElement.m_duration = duration;
  819. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  820. AddRaytracingData(newElement);
  821. }
  822. void DebugDrawSystemComponent::CreateObbEntryForComponent(const AZ::EntityId& componentEntityId, const DebugDrawObbElement& element)
  823. {
  824. AZStd::lock_guard<AZStd::mutex> locker(m_activeObbsMutex);
  825. DebugDrawObbElementWrapper& newElement = m_activeObbs.emplace_back();
  826. newElement.m_targetEntityId = componentEntityId;
  827. newElement.m_obb = element.m_obb;
  828. newElement.m_duration = -1.0f; // Component-spawned text has infinite duration currently (can change in the future)
  829. newElement.m_color = element.m_color;
  830. newElement.m_worldLocation = element.m_worldLocation;
  831. newElement.m_owningEditorComponent = element.m_owningEditorComponent;
  832. newElement.m_scale = element.m_scale;
  833. newElement.m_isRayTracingEnabled = element.m_isRayTracingEnabled;
  834. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  835. AddRaytracingData(newElement);
  836. }
  837. ///////////////////////////////////////////////////////////////////////
  838. // Rays
  839. ///////////////////////////////////////////////////////////////////////
  840. void DebugDrawSystemComponent::DrawRayLocationToDirection(const AZ::Vector3& worldLocation, const AZ::Vector3& worldDirection, const AZ::Color& color, float duration)
  841. {
  842. AZStd::lock_guard<AZStd::mutex> locker(m_activeRaysMutex);
  843. DebugDrawRayElement& newElement = m_activeRays.emplace_back();
  844. newElement.m_color = color;
  845. newElement.m_duration = duration;
  846. newElement.m_worldLocation = worldLocation;
  847. newElement.m_worldDirection = worldDirection;
  848. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  849. }
  850. void DebugDrawSystemComponent::DrawRayEntityToDirection(const AZ::EntityId& startEntity, const AZ::Vector3& worldDirection, const AZ::Color& color, float duration)
  851. {
  852. AZStd::lock_guard<AZStd::mutex> locker(m_activeRaysMutex);
  853. DebugDrawRayElement& newElement = m_activeRays.emplace_back();
  854. newElement.m_color = color;
  855. newElement.m_duration = duration;
  856. newElement.m_startEntityId = startEntity;
  857. newElement.m_worldDirection = worldDirection;
  858. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  859. }
  860. void DebugDrawSystemComponent::DrawRayEntityToEntity(const AZ::EntityId& startEntity, const AZ::EntityId& endEntity, const AZ::Color& color, float duration)
  861. {
  862. AZStd::lock_guard<AZStd::mutex> locker(m_activeRaysMutex);
  863. DebugDrawRayElement& newElement = m_activeRays.emplace_back();
  864. newElement.m_color = color;
  865. newElement.m_duration = duration;
  866. newElement.m_startEntityId = startEntity;
  867. newElement.m_endEntityId = endEntity;
  868. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  869. }
  870. void DebugDrawSystemComponent::CreateRayEntryForComponent(const AZ::EntityId& componentEntityId, const DebugDrawRayElement& element)
  871. {
  872. AZStd::lock_guard<AZStd::mutex> locker(m_activeRaysMutex);
  873. m_activeRays.push_back(element);
  874. DebugDrawRayElement& newElement = m_activeRays.back();
  875. newElement.m_duration = -1.0f; // Component-spawned text has infinite duration currently (can change in the future)
  876. newElement.m_startEntityId = componentEntityId;
  877. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  878. }
  879. ///////////////////////////////////////////////////////////////////////
  880. // Spheres
  881. ///////////////////////////////////////////////////////////////////////
  882. void DebugDrawSystemComponent::DrawSphereAtLocation(const AZ::Vector3& worldLocation, float radius, const AZ::Color& color, float duration)
  883. {
  884. AZStd::lock_guard<AZStd::mutex> locker(m_activeSpheresMutex);
  885. DebugDrawSphereElementWrapper& newElement = m_activeSpheres.emplace_back();
  886. newElement.m_worldLocation = worldLocation;
  887. newElement.m_radius = radius;
  888. newElement.m_color = color;
  889. newElement.m_duration = duration;
  890. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  891. }
  892. void DebugDrawSystemComponent::DrawSphereOnEntity(const AZ::EntityId& targetEntity, float radius, const AZ::Color& color, bool enableRayTracing, float duration)
  893. {
  894. AZStd::lock_guard<AZStd::mutex> locker(m_activeSpheresMutex);
  895. DebugDrawSphereElementWrapper& newElement = m_activeSpheres.emplace_back();
  896. newElement.m_targetEntityId = targetEntity;
  897. newElement.m_radius = radius;
  898. newElement.m_color = color;
  899. newElement.m_isRayTracingEnabled = enableRayTracing;
  900. newElement.m_duration = duration;
  901. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  902. AddRaytracingData(newElement);
  903. }
  904. void DebugDrawSystemComponent::CreateSphereEntryForComponent(const AZ::EntityId& componentEntityId, const DebugDrawSphereElement& element)
  905. {
  906. AZStd::lock_guard<AZStd::mutex> locker(m_activeSpheresMutex);
  907. DebugDrawSphereElementWrapper& newElement = m_activeSpheres.emplace_back();
  908. newElement.m_duration = -1.0f; // Component-spawned text has infinite duration currently (can change in the future)
  909. newElement.m_color = element.m_color;
  910. newElement.m_targetEntityId = componentEntityId;
  911. newElement.m_worldLocation = element.m_worldLocation;
  912. newElement.m_radius = element.m_radius;
  913. newElement.m_isRayTracingEnabled = element.m_isRayTracingEnabled;
  914. newElement.m_owningEditorComponent = element.m_owningEditorComponent;
  915. AZ::TickRequestBus::BroadcastResult(newElement.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  916. AddRaytracingData(newElement);
  917. }
  918. ///////////////////////////////////////////////////////////////////////
  919. // Text
  920. ///////////////////////////////////////////////////////////////////////
  921. void DebugDrawSystemComponent::DrawTextAtLocation(const AZ::Vector3& worldLocation, const AZStd::string& text, const AZ::Color& color, float duration)
  922. {
  923. AZStd::lock_guard<AZStd::mutex> locker(m_activeTextsMutex);
  924. DebugDrawTextElement& newText = m_activeTexts.emplace_back();
  925. newText.m_drawMode = DebugDrawTextElement::DrawMode::InWorld;
  926. newText.m_text = text;
  927. newText.m_color = color;
  928. newText.m_duration = duration;
  929. newText.m_worldLocation = worldLocation;
  930. AZ::TickRequestBus::BroadcastResult(newText.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  931. }
  932. void DebugDrawSystemComponent::DrawTextOnEntity(const AZ::EntityId& targetEntity, const AZStd::string& text, const AZ::Color& color, float duration)
  933. {
  934. AZStd::lock_guard<AZStd::mutex> locker(m_activeTextsMutex);
  935. DebugDrawTextElement& newText = m_activeTexts.emplace_back();
  936. newText.m_drawMode = DebugDrawTextElement::DrawMode::InWorld;
  937. newText.m_text = text;
  938. newText.m_color = color;
  939. newText.m_duration = duration;
  940. newText.m_targetEntityId = targetEntity;
  941. AZ::TickRequestBus::BroadcastResult(newText.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  942. }
  943. void DebugDrawSystemComponent::DrawTextOnScreen(const AZStd::string& text, const AZ::Color& color, float duration)
  944. {
  945. AZStd::lock_guard<AZStd::mutex> locker(m_activeTextsMutex);
  946. DebugDrawTextElement& newText = m_activeTexts.emplace_back();
  947. newText.m_drawMode = DebugDrawTextElement::DrawMode::OnScreen;
  948. //newText.m_category = 0;
  949. newText.m_text = text;
  950. newText.m_color = color;
  951. newText.m_duration = duration;
  952. AZ::TickRequestBus::BroadcastResult(newText.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  953. }
  954. void DebugDrawSystemComponent::DrawScaledTextOnScreen(const AZStd::string& text, float fontScale, const AZ::Color& color, float duration)
  955. {
  956. AZStd::lock_guard<AZStd::mutex> locker(m_activeTextsMutex);
  957. DebugDrawTextElement& newText = m_activeTexts.emplace_back();
  958. newText.m_drawMode = DebugDrawTextElement::DrawMode::OnScreen;
  959. newText.m_text = text;
  960. newText.m_fontScale = fontScale;
  961. newText.m_color = color;
  962. newText.m_duration = duration;
  963. AZ::TickRequestBus::BroadcastResult(newText.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  964. }
  965. void DebugDrawSystemComponent::DrawScaledTextOnScreenPos(float x, float y, const AZStd::string& text, float fontScale, const AZ::Color& color, float duration, bool bCenter)
  966. {
  967. AZStd::lock_guard<AZStd::mutex> locker(m_activeTextsMutex);
  968. DebugDrawTextElement& newText = m_activeTexts.emplace_back();
  969. newText.m_drawMode = DebugDrawTextElement::DrawMode::OnScreen;
  970. newText.m_text = text;
  971. newText.m_fontScale = fontScale;
  972. newText.m_color = color;
  973. newText.m_duration = duration;
  974. newText.m_bCenter = bCenter;
  975. newText.m_useOnScreenCoordinates = true;
  976. newText.m_worldLocation.Set(x, y, 1.f);
  977. AZ::TickRequestBus::BroadcastResult(newText.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  978. }
  979. void DebugDrawSystemComponent::DebugDrawSystemComponent::CreateTextEntryForComponent(const AZ::EntityId& componentEntityId, const DebugDrawTextElement& element)
  980. {
  981. AZStd::lock_guard<AZStd::mutex> locker(m_activeTextsMutex);
  982. m_activeTexts.push_back(element);
  983. DebugDrawTextElement& newText = m_activeTexts.back();
  984. newText.m_duration = -1.0f; // Component-spawned text has infinite duration currently (can change in the future)
  985. newText.m_targetEntityId = componentEntityId;
  986. AZ::TickRequestBus::BroadcastResult(newText.m_activateTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
  987. }
  988. void DebugDrawSystemComponent::AddRaytracingData(DebugDrawSphereElementWrapper& element)
  989. {
  990. if (!element.m_isRayTracingEnabled)
  991. {
  992. return;
  993. }
  994. if (!m_sphereRayTracingTypeHandle.IsValid())
  995. {
  996. m_rayTracingFeatureProcessor =
  997. AZ::RPI::Scene::GetFeatureProcessorForEntity<AZ::Render::RayTracingFeatureProcessor>(element.m_targetEntityId);
  998. auto shaderAsset = AZ::RPI::FindShaderAsset("shaders/sphereintersection.azshader");
  999. auto rayTracingShader = AZ::RPI::Shader::FindOrCreate(shaderAsset);
  1000. AZ::RPI::CommonBufferDescriptor desc;
  1001. desc.m_bufferName = "SpheresBuffer";
  1002. desc.m_poolType = AZ::RPI::CommonBufferPoolType::ReadOnly;
  1003. desc.m_byteCount = sizeof(float); // Start with just 1 element
  1004. desc.m_elementSize = sizeof(float);
  1005. desc.m_elementFormat = AZ::RHI::Format::R32_FLOAT;
  1006. desc.m_bufferData = nullptr;
  1007. m_spheresRayTracingIndicesBuffer = AZ::RPI::BufferSystemInterface::Get()->CreateBufferFromCommonPool(desc);
  1008. m_sphereRayTracingTypeHandle = m_rayTracingFeatureProcessor->RegisterProceduralGeometryType(
  1009. "DebugDraw::Sphere",
  1010. rayTracingShader,
  1011. "SphereIntersection",
  1012. m_spheresRayTracingIndicesBuffer->GetBufferView()->GetDeviceBufferView(AZ::RHI::MultiDevice::DefaultDeviceIndex)->GetBindlessReadIndex());
  1013. }
  1014. element.m_localInstanceIndex = m_spheresRayTracingIndices.AddEntry(0);
  1015. size_t requiredSizeInBytes = m_spheresRayTracingIndices.GetIndexList().size() * sizeof(float);
  1016. if (requiredSizeInBytes > m_spheresRayTracingIndicesBuffer->GetBufferSize())
  1017. {
  1018. m_spheresRayTracingIndicesBuffer->Resize(requiredSizeInBytes);
  1019. m_rayTracingFeatureProcessor->SetProceduralGeometryTypeBindlessBufferIndex(
  1020. m_sphereRayTracingTypeHandle.GetWeakHandle(), m_spheresRayTracingIndicesBuffer->GetBufferView()->GetDeviceBufferView(AZ::RHI::MultiDevice::DefaultDeviceIndex)->GetBindlessReadIndex());
  1021. // Need to copy all existing data to resized buffer
  1022. AZStd::vector<float> radii(m_spheresRayTracingIndices.GetIndexList().size());
  1023. for (const DebugDrawSphereElementWrapper& sphere : m_activeSpheres)
  1024. {
  1025. radii[sphere.m_localInstanceIndex] = sphere.m_radius;
  1026. }
  1027. m_spheresRayTracingIndicesBuffer->UpdateData(radii.data(), radii.size() * sizeof(radii[0]));
  1028. }
  1029. m_spheresRayTracingIndicesBuffer->UpdateData(&element.m_radius, sizeof(float), element.m_localInstanceIndex * sizeof(float));
  1030. AZ::Render::RayTracingFeatureProcessor::SubMeshMaterial material;
  1031. material.m_baseColor = element.m_color;
  1032. material.m_roughnessFactor = 0.9f;
  1033. m_rayTracingFeatureProcessor->AddProceduralGeometry(
  1034. m_sphereRayTracingTypeHandle.GetWeakHandle(),
  1035. UuidFromEntityId(element.m_targetEntityId),
  1036. AZ::Aabb::CreateCenterRadius(AZ::Vector3::CreateZero(), 1.f),
  1037. material,
  1038. AZ::RHI::RayTracingAccelerationStructureInstanceInclusionMask::STATIC_MESH,
  1039. element.m_localInstanceIndex);
  1040. }
  1041. void DebugDrawSystemComponent::AddRaytracingData(DebugDrawObbElementWrapper& element)
  1042. {
  1043. if (!element.m_isRayTracingEnabled)
  1044. {
  1045. return;
  1046. }
  1047. if (!m_obbRayTracingTypeHandle.IsValid())
  1048. {
  1049. m_rayTracingFeatureProcessor =
  1050. AZ::RPI::Scene::GetFeatureProcessorForEntity<AZ::Render::RayTracingFeatureProcessor>(element.m_targetEntityId);
  1051. auto shaderAsset = AZ::RPI::FindShaderAsset("shaders/obbintersection.azshader");
  1052. auto rayTracingShader = AZ::RPI::Shader::FindOrCreate(shaderAsset);
  1053. m_obbRayTracingTypeHandle =
  1054. m_rayTracingFeatureProcessor->RegisterProceduralGeometryType("DebugDraw::Obb", rayTracingShader, "ObbIntersection");
  1055. }
  1056. AZ::Render::RayTracingFeatureProcessor::SubMeshMaterial material;
  1057. material.m_baseColor = element.m_color;
  1058. material.m_roughnessFactor = 0.9f;
  1059. m_rayTracingFeatureProcessor->AddProceduralGeometry(
  1060. m_obbRayTracingTypeHandle.GetWeakHandle(),
  1061. UuidFromEntityId(element.m_targetEntityId),
  1062. AZ::Aabb::CreateCenterRadius(AZ::Vector3::CreateZero(), 1.f),
  1063. material,
  1064. AZ::RHI::RayTracingAccelerationStructureInstanceInclusionMask::STATIC_MESH,
  1065. 0);
  1066. }
  1067. void DebugDrawSystemComponent::RemoveRaytracingData(const DebugDrawSphereElementWrapper& element)
  1068. {
  1069. if (m_rayTracingFeatureProcessor && element.m_isRayTracingEnabled)
  1070. {
  1071. m_spheresRayTracingIndices.RemoveEntry(element.m_localInstanceIndex);
  1072. m_rayTracingFeatureProcessor->RemoveProceduralGeometry(UuidFromEntityId(element.m_targetEntityId));
  1073. if (m_rayTracingFeatureProcessor->GetProceduralGeometryCount(m_sphereRayTracingTypeHandle.GetWeakHandle()) == 0)
  1074. {
  1075. m_sphereRayTracingTypeHandle.Free();
  1076. m_spheresRayTracingIndicesBuffer.reset();
  1077. m_spheresRayTracingIndices.Reset();
  1078. }
  1079. }
  1080. }
  1081. void DebugDrawSystemComponent::RemoveRaytracingData(const DebugDrawObbElementWrapper& element)
  1082. {
  1083. if (m_rayTracingFeatureProcessor && element.m_isRayTracingEnabled)
  1084. {
  1085. m_rayTracingFeatureProcessor->RemoveProceduralGeometry(UuidFromEntityId(element.m_targetEntityId));
  1086. if (m_rayTracingFeatureProcessor->GetProceduralGeometryCount(m_obbRayTracingTypeHandle.GetWeakHandle()) == 0)
  1087. {
  1088. m_obbRayTracingTypeHandle.Free();
  1089. }
  1090. }
  1091. }
  1092. } // namespace DebugDraw