3
0

AtomDebugDisplayViewportInterface.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  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. #pragma once
  9. #include <AzCore/Casting/numeric_cast.h>
  10. #include <AzCore/Component/Component.h>
  11. #include <AzCore/std/containers/fixed_vector.h>
  12. #include <AzCore/Math/Matrix3x4.h>
  13. #include <AzFramework/Entity/EntityDebugDisplayBus.h>
  14. #include <Atom/RPI.Public/AuxGeom/AuxGeomFeatureProcessorInterface.h>
  15. #include <Atom/RPI.Public/RPISystemInterface.h>
  16. #include <Atom/RPI.Public/AuxGeom/AuxGeomDraw.h>
  17. #include <Atom/RPI.Public/ViewportContext.h>
  18. #include <Atom/RPI.Public/ViewportContextBus.h>
  19. namespace AZ::AtomBridge
  20. {
  21. struct RenderState
  22. {
  23. AZ::Color m_color = AZ::Color(0.0f, 0.0f, 0.0f, 1.0f);
  24. uint8_t m_lineWidth = 1u;
  25. uint16_t m_currentTransform = 0;
  26. enum { TransformStackSize = 32 };
  27. AZ::Matrix3x4 m_transformStack[TransformStackSize];
  28. AZ::RPI::AuxGeomDraw::OpacityType m_opacityType = AZ::RPI::AuxGeomDraw::OpacityType::Opaque;
  29. AZ::RPI::AuxGeomDraw::DepthTest m_depthTest = AZ::RPI::AuxGeomDraw::DepthTest::On;
  30. AZ::RPI::AuxGeomDraw::DepthWrite m_depthWrite = AZ::RPI::AuxGeomDraw::DepthWrite::On;
  31. AZ::RPI::AuxGeomDraw::FaceCullMode m_faceCullMode = AZ::RPI::AuxGeomDraw::FaceCullMode::Back;
  32. int32_t m_viewProjOverrideIndex = -1; // will be used to implement SetDrawInFrontMode & 2D mode
  33. // separate tracking for Cry only state
  34. bool m_drawInFront = false;
  35. bool m_2dMode = false;
  36. };
  37. //! Utility class to collect line segments when the number of segments is known at compile time.
  38. template <int MaxNumLines>
  39. struct SingleColorStaticSizeLineHelper
  40. {
  41. bool AddLineSegment(const AZ::Vector3& lineStart, const AZ::Vector3& lineEnd)
  42. {
  43. if ((m_points.size()+2) < m_points.capacity())
  44. {
  45. m_points.push_back(lineStart);
  46. m_points.push_back(lineEnd);
  47. return true;
  48. }
  49. return false;
  50. }
  51. void Draw(AZ::RPI::AuxGeomDrawPtr auxGeomDrawPtr, const RenderState& rendState) const
  52. {
  53. if (auxGeomDrawPtr && !m_points.empty())
  54. {
  55. AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs;
  56. drawArgs.m_verts = m_points.data();
  57. drawArgs.m_vertCount = aznumeric_cast<uint32_t>(m_points.size());
  58. drawArgs.m_colors = &rendState.m_color;
  59. drawArgs.m_colorCount = 1;
  60. drawArgs.m_size = rendState.m_lineWidth;
  61. drawArgs.m_opacityType = rendState.m_opacityType;
  62. drawArgs.m_depthTest = rendState.m_depthTest;
  63. drawArgs.m_depthWrite = rendState.m_depthWrite;
  64. drawArgs.m_viewProjectionOverrideIndex = rendState.m_viewProjOverrideIndex;
  65. auxGeomDrawPtr->DrawLines( drawArgs );
  66. }
  67. }
  68. void Draw2d(AZ::RPI::AuxGeomDrawPtr auxGeomDrawPtr, const RenderState& rendState) const
  69. {
  70. if (auxGeomDrawPtr && !m_points.empty())
  71. {
  72. AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs;
  73. drawArgs.m_verts = m_points.data();
  74. drawArgs.m_vertCount = aznumeric_cast<uint32_t>(m_points.size());
  75. drawArgs.m_colors = &rendState.m_color;
  76. drawArgs.m_colorCount = 1;
  77. drawArgs.m_size = rendState.m_lineWidth;
  78. drawArgs.m_opacityType = rendState.m_opacityType;
  79. drawArgs.m_depthTest = rendState.m_depthTest;
  80. drawArgs.m_depthWrite = rendState.m_depthWrite;
  81. drawArgs.m_viewProjectionOverrideIndex = auxGeomDrawPtr->GetOrAdd2DViewProjOverride();
  82. auxGeomDrawPtr->DrawLines( drawArgs );
  83. }
  84. }
  85. void Reset()
  86. {
  87. m_points.clear();
  88. }
  89. AZStd::fixed_vector<AZ::Vector3, 2 * MaxNumLines> m_points;
  90. };
  91. //! Utility class to collect line segments
  92. struct SingleColorDynamicSizeLineHelper final
  93. {
  94. SingleColorDynamicSizeLineHelper(int estimatedNumLineSegments);
  95. void AddLineSegment(const AZ::Vector3& lineStart, const AZ::Vector3& lineEnd);
  96. void Draw(AZ::RPI::AuxGeomDrawPtr auxGeomDrawPtr, const RenderState& rendState) const;
  97. void Draw2d(AZ::RPI::AuxGeomDrawPtr auxGeomDrawPtr, const RenderState& rendState) const;
  98. void Reset();
  99. AZStd::vector<AZ::Vector3> m_points;
  100. };
  101. class AtomDebugDisplayViewportInterface final
  102. : public AzFramework::DebugDisplayRequestBus::Handler
  103. , public AZ::RPI::ViewportContextIdNotificationBus::Handler
  104. {
  105. public:
  106. AZ_RTTI(AtomDebugDisplayViewportInterface, "{09AF6A46-0100-4FBF-8F94-E6B221322D14}", AzFramework::DebugDisplayRequestBus::Handler);
  107. explicit AtomDebugDisplayViewportInterface(AZ::RPI::ViewportContextPtr viewportContextPtr);
  108. explicit AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress, RPI::Scene* scene);
  109. ~AtomDebugDisplayViewportInterface();
  110. void ResetRenderState();
  111. ////////////////////////////////////////////////////////////////////////////
  112. // AzFramework/Entity/DebugDisplayRequestBus::Handler overrides ...
  113. // Partial implementation of the DebugDisplayRequestBus on Atom.
  114. // Commented out function prototypes are remaining part of the api
  115. // waiting to be implemented.
  116. // work tracked in [ATOM-3459]
  117. void SetColor(const AZ::Color& color) override;
  118. void SetAlpha(float a) override;
  119. void DrawQuad(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3, const AZ::Vector3& p4) override;
  120. void DrawQuad(float width, float height, bool drawShaded) override;
  121. void DrawWireQuad(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3, const AZ::Vector3& p4) override;
  122. void DrawWireQuad(float width, float height) override;
  123. void DrawQuadGradient(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3, const AZ::Vector3& p4, const AZ::Vector4& firstColor, const AZ::Vector4& secondColor) override;
  124. void DrawQuad2dGradient(const Vector2& p1, const Vector2& p2, const Vector2& p3, const Vector2& p4, float z, const Color& firstColor, const Color& secondColor) override;
  125. void DrawTri(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3) override;
  126. void DrawTriangles(const AZStd::vector<AZ::Vector3>& vertices, const AZ::Color& color) override;
  127. void DrawTrianglesIndexed(const AZStd::vector<AZ::Vector3>& vertices, const AZStd::vector<AZ::u32>& indices, const AZ::Color& color) override;
  128. void DrawWireBox(const AZ::Vector3& min, const AZ::Vector3& max) override;
  129. void DrawSolidBox(const AZ::Vector3& min, const AZ::Vector3& max) override;
  130. void DrawWireOBB(const AZ::Vector3& center, const AZ::Vector3& axisX, const AZ::Vector3& axisY, const AZ::Vector3& axisZ, const AZ::Vector3& halfExtents) override;
  131. void DrawSolidOBB(const AZ::Vector3& center, const AZ::Vector3& axisX, const AZ::Vector3& axisY, const AZ::Vector3& axisZ, const AZ::Vector3& halfExtents) override;
  132. void DrawPoint(const AZ::Vector3& p, int nSize = 1) override;
  133. void DrawLine(const AZ::Vector3& p1, const AZ::Vector3& p2) override;
  134. void DrawLine(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector4& col1, const AZ::Vector4& col2) override;
  135. void DrawLines(const AZStd::vector<AZ::Vector3>& lines, const AZ::Color& color) override;
  136. void DrawPolyLine(const AZ::Vector3* pnts, int numPoints, bool cycled = true) override;
  137. void DrawPolyLine(AZStd::span<const AZ::Vector3>, bool cycled = true) override;
  138. void DrawWireQuad2d(const AZ::Vector2& p1, const AZ::Vector2& p2, float z) override;
  139. void DrawLine2d(const AZ::Vector2& p1, const AZ::Vector2& p2, float z) override;
  140. void DrawLine2dGradient(const AZ::Vector2& p1, const AZ::Vector2& p2, float z, const AZ::Vector4& firstColor, const AZ::Vector4& secondColor) override;
  141. void DrawWireCircle2d(const AZ::Vector2& center, float radius, float z) override;
  142. void DrawArc(const AZ::Vector3& pos, float radius, float startAngleDegrees, float sweepAngleDegrees, float angularStepDegrees, int referenceAxis = 2) override;
  143. void DrawArc(const AZ::Vector3& pos, float radius, float startAngleDegrees, float sweepAngleDegrees, float angularStepDegrees, const AZ::Vector3& fixedAxis) override;
  144. void DrawCircle(const AZ::Vector3& pos, float radius, int nUnchangedAxis = 2 /*z axis*/) override;
  145. void DrawHalfDottedCircle(const AZ::Vector3& pos, float radius, const AZ::Vector3& viewPos, int nUnchangedAxis = 2 /*z axis*/) override;
  146. void DrawWireCone(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius, float height) override;
  147. void DrawSolidCone(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius, float height, bool drawShaded) override;
  148. void DrawWireCylinder(const AZ::Vector3& center, const AZ::Vector3& axis, float radius, float height) override;
  149. void DrawSolidCylinder(const AZ::Vector3& center, const AZ::Vector3& axis, float radius, float height, bool drawShaded) override;
  150. void DrawWireCylinderNoEnds(const AZ::Vector3& center, const AZ::Vector3& axis, float radius, float height) override;
  151. void DrawSolidCylinderNoEnds(const AZ::Vector3& center, const AZ::Vector3& axis, float radius, float height, bool drawShaded) override;
  152. void DrawWireCapsule(const AZ::Vector3& center, const AZ::Vector3& axis, float radius, float heightStraightSection) override;
  153. void DrawWireSphere(const AZ::Vector3& pos, float radius) override;
  154. void DrawWireSphere(const AZ::Vector3& pos, const AZ::Vector3 radius) override;
  155. void DrawWireHemisphere(const AZ::Vector3& pos, const AZ::Vector3& axis, float radius) override;
  156. void DrawWireDisk(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius) override;
  157. void DrawBall(const AZ::Vector3& pos, float radius, bool drawShaded) override;
  158. void DrawDisk(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius, bool drawShaded) override;
  159. void DrawArrow(const AZ::Vector3& src, const AZ::Vector3& trg, float headScale = 1.0f, bool dualEndedArrow = false) override;
  160. void DrawTextLabel(const AZ::Vector3& pos, float size, const char* text, const bool bCenter = false, int srcOffsetX = 0, int srcOffsetY = 0) override;
  161. void Draw2dTextLabel(float x, float y, float size, const char* text, bool bCenter = false) override;
  162. void DrawTextOn2DBox(const AZ::Vector3& pos, const char* text, float textScale, const AZ::Vector4& TextColor, const AZ::Vector4& TextBackColor) override;
  163. void SetLineWidth(float width) override;
  164. bool IsVisible(const AZ::Aabb& bounds) override;
  165. float GetLineWidth() override;
  166. float GetAspectRatio() override;
  167. void DepthTestOff() override;
  168. void DepthTestOn() override;
  169. void DepthWriteOff() override;
  170. void DepthWriteOn() override;
  171. void CullOff() override;
  172. void CullOn() override;
  173. bool SetDrawInFrontMode(bool on) override;
  174. AZ::u32 GetState() override;
  175. AZ::u32 SetState(AZ::u32 state) override;
  176. void PushMatrix(const AZ::Transform& tm) override;
  177. void PopMatrix() override;
  178. void PushPremultipliedMatrix(const AZ::Matrix3x4& matrix) override;
  179. AZ::Matrix3x4 PopPremultipliedMatrix() override;
  180. private:
  181. // ViewportContextIdNotificationBus handlers
  182. void OnViewportDefaultViewChanged(AZ::RPI::ViewPtr view) override;
  183. // internal helper functions
  184. using LineSegmentFilterFunc = AZStd::function<bool(const AZ::Vector3& lineStart, const AZ::Vector3& lineEnd, int segmentIndex)>;
  185. enum CircleAxis
  186. {
  187. CircleAxisX = 0,
  188. CircleAxisY = 1,
  189. CircleAxisZ = 2,
  190. CircleAxisMax = 3,
  191. };
  192. template<typename LineStorageType>
  193. void CreateAxisAlignedArc(
  194. LineStorageType& lines,
  195. float segmentAngle, // radians
  196. float minAngle, // radians
  197. float maxAngle, // radians
  198. const AZ::Vector3& position,
  199. const AZ::Vector3& radiusV3,
  200. CircleAxis circleAxis,
  201. LineSegmentFilterFunc filterFunc =
  202. [](const AZ::Vector3&, const AZ::Vector3&, int)
  203. {return true;}
  204. );
  205. template<typename LineStorageType>
  206. void CreateArbitraryAxisArc(
  207. LineStorageType& lines,
  208. float segmentAngle, // radians
  209. float minAngle, // radians
  210. float maxAngle, // radians
  211. const AZ::Vector3& position,
  212. const AZ::Vector3& radiusV3,
  213. const AZ::Vector3& axis,
  214. LineSegmentFilterFunc filterFunc =
  215. [](const AZ::Vector3&, const AZ::Vector3&, int)
  216. {return true;}
  217. );
  218. //! Convert position to world space.
  219. AZ::Vector3 ToWorldSpacePosition(const AZ::Vector3& v) const { return m_rendState.m_transformStack[m_rendState.m_currentTransform] * v; }
  220. //! Convert direction to world space (translation is not considered)
  221. AZ::Vector3 ToWorldSpaceVector(const AZ::Vector3& v) const { return m_rendState.m_transformStack[m_rendState.m_currentTransform].Multiply3x3(v); }
  222. //! Convert positions to world space.
  223. AZStd::vector<AZ::Vector3> ToWorldSpacePosition(const AZStd::vector<AZ::Vector3>& positions) const;
  224. //! Convert directions to world space (translation is not considered)
  225. AZStd::vector<AZ::Vector3> ToWorldSpaceVector(const AZStd::vector<AZ::Vector3>& vectors) const;
  226. void CalcBasisVectors(const AZ::Vector3& n, AZ::Vector3& b1, AZ::Vector3& b2) const;
  227. const AZ::Matrix3x4& GetCurrentTransform() const;
  228. void UpdateAuxGeom(RPI::Scene* scene, AZ::RPI::View* view);
  229. void InitInternal(RPI::Scene* scene, AZ::RPI::ViewportContextPtr viewportContextPtr);
  230. AZ::RPI::ViewportContextPtr GetViewportContext() const;
  231. uint32_t ConvertRenderStateToCry() const;
  232. RenderState m_rendState;
  233. AZ::RPI::AuxGeomDrawPtr m_auxGeomPtr;
  234. // m_defaultInstance is true for the instance that multicasts the debug draws to all viewports
  235. // (with an AuxGeom render pass) in the default scene.
  236. bool m_defaultInstance = false;
  237. AzFramework::ViewportId m_viewportId = AzFramework::InvalidViewportId; // Address this instance answers on.
  238. AZ::RPI::ViewportContext::SceneChangedEvent::Handler m_sceneChangeHandler;
  239. };
  240. // this is duplicated from Cry_Math.h, GetBasisVectors.
  241. // Need to match it's behavior to get the same orientations on curves.
  242. inline void AtomDebugDisplayViewportInterface::CalcBasisVectors(
  243. const AZ::Vector3& unitVector,
  244. AZ::Vector3& basis1,
  245. AZ::Vector3& basis2
  246. ) const
  247. {
  248. if (unitVector.GetZ() < FLT_EPSILON - 1.0f)
  249. {
  250. basis1 = AZ::Vector3(0.0f, -1.0f, 0.0f);
  251. basis2 = AZ::Vector3(-1.0f, 0.0f, 0.0f);
  252. return;
  253. }
  254. const float a = 1.0f / (1.0f + unitVector.GetZ());
  255. const float b = -unitVector.GetX() * unitVector.GetY() * a;
  256. basis1 = AZ::Vector3(1.0f - unitVector.GetX() * unitVector.GetX() * a, b, -unitVector.GetX());
  257. basis2 = AZ::Vector3(b, 1.0f - unitVector.GetY() * unitVector.GetY() * a, -unitVector.GetY());
  258. }
  259. template<typename LineStorageType>
  260. void AtomDebugDisplayViewportInterface::CreateAxisAlignedArc(
  261. LineStorageType& lines,
  262. float segmentAngle, // radians
  263. float minAngle, // radians
  264. float maxAngle, // radians
  265. const AZ::Vector3& position,
  266. const AZ::Vector3& radiusV3,
  267. CircleAxis circleAxis,
  268. LineSegmentFilterFunc filterFunc)
  269. {
  270. AZ::Vector3 p1;
  271. AZ::Vector3 sinCos = AZ::Vector3::CreateZero();
  272. const uint32_t circleAxis1 = (circleAxis + 1) % CircleAxisMax;
  273. const uint32_t circleAxis2 = (circleAxis + 2) % CircleAxisMax;
  274. sinCos.SetElement(circleAxis1, sinf(minAngle));
  275. sinCos.SetElement(circleAxis2, cosf(minAngle));
  276. AZ::Vector3 p0 = position + radiusV3 * sinCos;
  277. p0 = ToWorldSpacePosition(p0);
  278. int segmentIndex = 0;
  279. for (float angle = minAngle + segmentAngle; angle < maxAngle; angle += segmentAngle)
  280. {
  281. float calcAngle = AZStd::clamp(angle, minAngle, maxAngle);
  282. sinCos.SetElement(circleAxis1, sinf(calcAngle));
  283. sinCos.SetElement(circleAxis2, cosf(calcAngle));
  284. p1 = position + radiusV3 * sinCos;
  285. p1 = ToWorldSpacePosition(p1);
  286. if (filterFunc(p0, p1, segmentIndex))
  287. {
  288. lines.AddLineSegment(p0, p1);
  289. }
  290. p0 = p1;
  291. ++segmentIndex;
  292. }
  293. // Complete the arc by drawing the last bit
  294. sinCos.SetElement(circleAxis1, sinf(maxAngle));
  295. sinCos.SetElement(circleAxis2, cosf(maxAngle));
  296. p1 = position + radiusV3 * sinCos;
  297. p1 = ToWorldSpacePosition(p1);
  298. if (filterFunc(p0, p1, segmentIndex))
  299. {
  300. lines.AddLineSegment(p0, p1);
  301. }
  302. }
  303. template<typename LineStorageType>
  304. void AtomDebugDisplayViewportInterface::CreateArbitraryAxisArc(
  305. LineStorageType& lines,
  306. float segmentAngle, // radians
  307. float minAngle, // radians
  308. float maxAngle, // radians
  309. const AZ::Vector3& position,
  310. const AZ::Vector3& radiusV3,
  311. const AZ::Vector3& axis,
  312. LineSegmentFilterFunc filterFunc)
  313. {
  314. AZ::Vector3 p1;
  315. float sinVF;
  316. float cosVF;
  317. AZ::SinCos(minAngle, sinVF, cosVF);
  318. AZ::Vector3 a, b;
  319. CalcBasisVectors(axis, a, b);
  320. AZ::Vector3 p0 = position + radiusV3 * (cosVF * a + sinVF * b);
  321. p0 = ToWorldSpacePosition(p0);
  322. int segmentIndex = 0;
  323. for (float angle = minAngle + segmentAngle; angle < maxAngle; angle += segmentAngle)
  324. {
  325. float calcAngle = AZ::GetClamp(angle, minAngle, maxAngle);
  326. AZ::SinCos(calcAngle, sinVF, cosVF);
  327. p1 = position + radiusV3 * (cosVF * a + sinVF * b);
  328. p1 = ToWorldSpacePosition(p1);
  329. if (filterFunc(p0, p1, segmentIndex))
  330. {
  331. lines.AddLineSegment(p0, p1);
  332. }
  333. p0 = p1;
  334. ++segmentIndex;
  335. }
  336. // Complete the arc by drawing the last bit
  337. AZ::SinCos(maxAngle, sinVF, cosVF);
  338. p1 = position + radiusV3 * (cosVF * a + sinVF * b);
  339. p1 = ToWorldSpacePosition(p1);
  340. if (filterFunc(p0, p1, segmentIndex))
  341. {
  342. lines.AddLineSegment(p0, p1);
  343. }
  344. }
  345. } // namespace AZ::AtomBridge