DebugDrawSystemComponent.cpp 55 KB

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