AuxGeomDrawQueue.cpp 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003
  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 "AuxGeomDrawQueue.h"
  9. #include <Atom/RPI.Public/Scene.h>
  10. #include <AzCore/Casting/numeric_cast.h>
  11. #include <AzCore/Math/Obb.h>
  12. #include <AzCore/Math/Matrix4x4.h>
  13. #include <AzCore/Math/ShapeIntersection.h>
  14. #include <AzCore/std/functional.h>
  15. namespace AZ
  16. {
  17. namespace Render
  18. {
  19. namespace
  20. {
  21. AZ::u32 PackColor(AZ::Color color)
  22. {
  23. // We use the format RHI::Format::R8G8B8A8_UNORM
  24. return (color.GetA8() << 24) | (color.GetB8() << 16) | (color.GetG8() << 8) | color.GetR8();
  25. }
  26. bool IsOpaque(AZ::Color color)
  27. {
  28. return color.GetA8() == 0xFF;
  29. }
  30. }
  31. const uint32_t VerticesPerPoint = 1;
  32. const uint32_t VerticesPerLine = 2;
  33. const uint32_t VerticesPerTriangle = 3;
  34. int32_t AuxGeomDrawQueue::AddViewProjOverride(const AZ::Matrix4x4& viewProj)
  35. {
  36. AZStd::lock_guard<AZStd::recursive_mutex> lock(m_buffersWriteLock);
  37. AuxGeomBufferData& buffer = m_buffers[m_currentBufferIndex];
  38. //the override matrix is pushed an array that persists until the frame is over, so that the matrix can be looked up later
  39. buffer.m_viewProjOverrides.push_back(viewProj);
  40. return aznumeric_cast<int32_t>(buffer.m_viewProjOverrides.size()) - 1;
  41. }
  42. int32_t AuxGeomDrawQueue::GetOrAdd2DViewProjOverride()
  43. {
  44. AZStd::lock_guard<AZStd::recursive_mutex> lock(m_buffersWriteLock);
  45. AuxGeomBufferData& buffer = m_buffers[m_currentBufferIndex];
  46. if (buffer.m_2DViewProjOverrideIndex == -1)
  47. {
  48. // matrix to convert 2d normalized screen coordinates (0.0-1.0 window lower-left based coordinates) to post projection space.
  49. static float s_Matrix4x4Floats[16] = {
  50. 2.0f, 0.0f, 0.0f, -1.0f,
  51. 0.0f, -2.0f, 0.0f, 1.0f,
  52. 0.0f, 0.0f, 1.0f, 0.0f,
  53. 0.0f, 0.0f, 0.0f, 1.0f};
  54. static Matrix4x4 s_proj2D = Matrix4x4::CreateFromRowMajorFloat16(s_Matrix4x4Floats);
  55. buffer.m_2DViewProjOverrideIndex = AddViewProjOverride(s_proj2D);
  56. }
  57. return buffer.m_2DViewProjOverrideIndex;
  58. }
  59. void AuxGeomDrawQueue::SetPointSize(float pointSize)
  60. {
  61. m_pointSize = pointSize;
  62. }
  63. float AuxGeomDrawQueue::GetPointSize()
  64. {
  65. return m_pointSize;
  66. }
  67. /////////////////////////////////////////////////////////////////////////////////////////////
  68. // dynamic draw functions
  69. void AuxGeomDrawQueue::DrawPoints(const AuxGeomDynamicDrawArguments& args)
  70. {
  71. AZ_Assert(args.m_colorCount == 1 || args.m_colorCount == args.m_vertCount, "DrawPolylines call with zero color entries");
  72. AZStd::function<AZ::u32(uint32_t)> packedColorFunction;
  73. bool isOpaque = true;
  74. if ( args.m_colorCount == 1 )
  75. {
  76. AZ::u32 packedColor = PackColor(args.m_colors[0]);
  77. packedColorFunction = [packedColor](uint32_t) { return packedColor; };
  78. isOpaque = IsOpaque(args.m_colors[0]);
  79. }
  80. else
  81. {
  82. packedColorFunction = [&args](uint32_t index) { return PackColor(args.m_colors[index]); };
  83. isOpaque = args.m_opacityType == OpacityType::Opaque;
  84. }
  85. DrawPrimitiveCommon(
  86. PrimitiveType_PointList,
  87. VerticesPerPoint,
  88. args.m_vertCount,
  89. args.m_verts,
  90. packedColorFunction,
  91. isOpaque,
  92. ConvertRPIDepthTestFlag(args.m_depthTest),
  93. ConvertRPIDepthWriteFlag(args.m_depthWrite),
  94. FaceCull_None,
  95. args.m_size,
  96. args.m_viewProjectionOverrideIndex);
  97. }
  98. void AuxGeomDrawQueue::DrawLines(const AuxGeomDynamicDrawArguments& args)
  99. {
  100. AZ_Assert(args.m_vertCount >= 2, "DrawLines call with insufficient vertices");
  101. AZ_Assert(args.m_colorCount == 1 || args.m_colorCount == args.m_vertCount, "DrawLines call with zero color entries");
  102. AZStd::function<AZ::u32(uint32_t)> packedColorFunction;
  103. bool isOpaque = true;
  104. if ( args.m_colorCount == 1 )
  105. {
  106. AZ::u32 packedColor = PackColor(args.m_colors[0]);
  107. packedColorFunction = [packedColor](uint32_t) { return packedColor; };
  108. isOpaque = IsOpaque(args.m_colors[0]);
  109. }
  110. else
  111. {
  112. packedColorFunction = [&args](uint32_t index) { return PackColor(args.m_colors[index]); };
  113. isOpaque = args.m_opacityType == OpacityType::Opaque;
  114. }
  115. DrawPrimitiveCommon(
  116. PrimitiveType_LineList,
  117. VerticesPerLine,
  118. args.m_vertCount,
  119. args.m_verts,
  120. packedColorFunction,
  121. isOpaque,
  122. ConvertRPIDepthTestFlag(args.m_depthTest),
  123. ConvertRPIDepthWriteFlag(args.m_depthWrite),
  124. FaceCull_None,
  125. args.m_size,
  126. args.m_viewProjectionOverrideIndex);
  127. }
  128. void AuxGeomDrawQueue::DrawLines(const AuxGeomDynamicIndexedDrawArguments& args)
  129. {
  130. AZ_Assert(args.m_vertCount >= 2, "DrawLines call with insufficient vertices");
  131. AZ_Assert(args.m_colorCount == 1 || args.m_colorCount == args.m_vertCount, "DrawLines call with zero color entries");
  132. AZStd::function<AZ::u32(uint32_t)> packedColorFunction;
  133. bool isOpaque = true;
  134. if ( args.m_colorCount == 1 )
  135. {
  136. AZ::u32 packedColor = PackColor(args.m_colors[0]);
  137. packedColorFunction = [packedColor](uint32_t) { return packedColor; };
  138. isOpaque = IsOpaque(args.m_colors[0]);
  139. }
  140. else
  141. {
  142. packedColorFunction = [&args](uint32_t index) { return PackColor(args.m_colors[index]); };
  143. isOpaque = args.m_opacityType == OpacityType::Opaque;
  144. }
  145. DrawPrimitiveWithSharedVerticesCommon(
  146. PrimitiveType_LineList,
  147. VerticesPerLine,
  148. args.m_vertCount,
  149. args.m_indexCount,
  150. args.m_verts,
  151. packedColorFunction,
  152. [&args](uint32_t index) { return args.m_indices[index]; },
  153. isOpaque,
  154. ConvertRPIDepthTestFlag(args.m_depthTest),
  155. ConvertRPIDepthWriteFlag(args.m_depthWrite),
  156. FaceCull_None,
  157. args.m_size,
  158. args.m_viewProjectionOverrideIndex);
  159. }
  160. void AuxGeomDrawQueue::DrawPolylines(const AuxGeomDynamicDrawArguments& args, PolylineEnd end)
  161. {
  162. AZ_Assert(args.m_vertCount >= 2, "DrawPolylines call with insufficient vertices");
  163. AZ_Assert(args.m_colorCount == 1 || args.m_colorCount == args.m_vertCount, "DrawPolylines call with zero color entries");
  164. AZStd::function<AZ::u32(uint32_t)> packedColorFunction;
  165. bool isOpaque = true;
  166. uint32_t indexCount = (end == PolylineEnd::Closed) ? args.m_vertCount * 2 : (args.m_vertCount - 1) * 2;
  167. if ( args.m_colorCount == 1 )
  168. {
  169. AZ::u32 packedColor = PackColor(args.m_colors[0]);
  170. packedColorFunction = [packedColor](uint32_t) { return packedColor; };
  171. isOpaque = IsOpaque(args.m_colors[0]);
  172. }
  173. else
  174. {
  175. packedColorFunction = [&args](uint32_t index) { return PackColor(args.m_colors[index]); };
  176. isOpaque = args.m_opacityType == OpacityType::Opaque;
  177. }
  178. DrawPrimitiveWithSharedVerticesCommon(
  179. PrimitiveType_LineList,
  180. VerticesPerLine,
  181. args.m_vertCount,
  182. indexCount,
  183. args.m_verts,
  184. packedColorFunction,
  185. [&args](uint32_t index) { return ((index / 2) + (index % 2)) % args.m_vertCount; },
  186. isOpaque,
  187. ConvertRPIDepthTestFlag(args.m_depthTest),
  188. ConvertRPIDepthWriteFlag(args.m_depthWrite),
  189. FaceCull_None,
  190. args.m_size,
  191. args.m_viewProjectionOverrideIndex);
  192. }
  193. void AuxGeomDrawQueue::DrawTriangles(const AuxGeomDynamicDrawArguments& args, FaceCullMode faceCull)
  194. {
  195. AZ_Assert(args.m_vertCount >= 3, "DrawTriangles call with insufficient vertices");
  196. AZ_Assert(args.m_colorCount == 1 || args.m_colorCount == args.m_vertCount, "DrawTriangles call with zero color entries");
  197. AZStd::function<AZ::u32(uint32_t)> packedColorFunction;
  198. bool isOpaque = true;
  199. if ( args.m_colorCount == 1 )
  200. {
  201. AZ::u32 packedColor = PackColor(args.m_colors[0]);
  202. packedColorFunction = [packedColor](uint32_t) { return packedColor; };
  203. isOpaque = IsOpaque(args.m_colors[0]);
  204. }
  205. else
  206. {
  207. packedColorFunction = [&args](uint32_t index) { return PackColor(args.m_colors[index]); };
  208. isOpaque = args.m_opacityType == OpacityType::Opaque;
  209. }
  210. DrawPrimitiveCommon(
  211. PrimitiveType_TriangleList,
  212. VerticesPerTriangle,
  213. args.m_vertCount,
  214. args.m_verts,
  215. packedColorFunction,
  216. isOpaque,
  217. ConvertRPIDepthTestFlag(args.m_depthTest),
  218. ConvertRPIDepthWriteFlag(args.m_depthWrite),
  219. ConvertRPIFaceCullFlag(faceCull),
  220. args.m_size,
  221. args.m_viewProjectionOverrideIndex);
  222. }
  223. void AuxGeomDrawQueue::DrawTriangles(const AuxGeomDynamicIndexedDrawArguments& args, FaceCullMode faceCull)
  224. {
  225. AZ_Assert(args.m_vertCount >= 3, "DrawTriangles call with insufficient vertices");
  226. AZ_Assert(args.m_colorCount == 1 || args.m_colorCount == args.m_vertCount, "DrawTriangles call with zero color entries");
  227. AZStd::function<AZ::u32(uint32_t)> packedColorFunction;
  228. bool isOpaque = true;
  229. if ( args.m_colorCount == 1 )
  230. {
  231. AZ::u32 packedColor = PackColor(args.m_colors[0]);
  232. packedColorFunction = [packedColor](uint32_t) { return packedColor; };
  233. isOpaque = IsOpaque(args.m_colors[0]);
  234. }
  235. else
  236. {
  237. packedColorFunction = [&args](uint32_t index) { return PackColor(args.m_colors[index]); };
  238. isOpaque = args.m_opacityType == OpacityType::Opaque;
  239. }
  240. DrawPrimitiveWithSharedVerticesCommon(
  241. PrimitiveType_TriangleList,
  242. VerticesPerTriangle,
  243. args.m_vertCount,
  244. args.m_indexCount,
  245. args.m_verts,
  246. packedColorFunction,
  247. [&args](uint32_t index) { return args.m_indices[index]; },
  248. isOpaque,
  249. ConvertRPIDepthTestFlag(args.m_depthTest),
  250. ConvertRPIDepthWriteFlag(args.m_depthWrite),
  251. ConvertRPIFaceCullFlag(faceCull),
  252. args.m_size,
  253. args.m_viewProjectionOverrideIndex);
  254. }
  255. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  256. // Fixed shape draw functions
  257. void AuxGeomDrawQueue::DrawQuad(
  258. float width,
  259. float height,
  260. const AZ::Matrix3x4& transform,
  261. const AZ::Color& color,
  262. DrawStyle style,
  263. DepthTest depthTest,
  264. DepthWrite depthWrite,
  265. FaceCullMode faceCull,
  266. int32_t viewProjOverrideIndex)
  267. {
  268. if (width <= 0.0f && height <= 0.0f)
  269. {
  270. return;
  271. }
  272. AZ::Matrix3x4 noScaleTransform = transform;
  273. AZ::Vector3 scale = noScaleTransform.ExtractScale();
  274. ShapeBufferEntry shape;
  275. shape.m_shapeType = ShapeType_Quad;
  276. shape.m_depthRead = ConvertRPIDepthTestFlag(depthTest);
  277. shape.m_depthWrite = ConvertRPIDepthWriteFlag(depthWrite);
  278. shape.m_faceCullMode = ConvertRPIFaceCullFlag(faceCull);
  279. shape.m_color = color;
  280. shape.m_rotationMatrix = Matrix3x3::CreateFromMatrix3x4(noScaleTransform);
  281. shape.m_position = transform.GetTranslation();
  282. shape.m_scale = scale * Vector3(width, 1.0f, height);
  283. shape.m_pointSize = m_pointSize;
  284. shape.m_viewProjOverrideIndex = viewProjOverrideIndex;
  285. AddShape(style, shape);
  286. }
  287. Matrix3x3 CreateMatrix3x3FromDirection(const AZ::Vector3& direction)
  288. {
  289. Vector3 unitDirection(direction.GetNormalized());
  290. Vector3 unitOrthogonal(direction.GetOrthogonalVector().GetNormalized());
  291. Vector3 unitCross(unitOrthogonal.Cross(unitDirection));
  292. return Matrix3x3::CreateFromColumns(unitOrthogonal, unitDirection, unitCross);
  293. }
  294. void AuxGeomDrawQueue::DrawSphere(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex)
  295. {
  296. DrawSphereCommon(center, direction, radius, color, style, depthTest, depthWrite, faceCull, viewProjOverrideIndex, false);
  297. }
  298. void AuxGeomDrawQueue::DrawSphere(const AZ::Vector3& center, float radius, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex)
  299. {
  300. DrawSphereCommon(center, AZ::Vector3::CreateAxisZ(), radius, color, style, depthTest, depthWrite, faceCull, viewProjOverrideIndex, false);
  301. }
  302. void AuxGeomDrawQueue::DrawHemisphere(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex)
  303. {
  304. DrawSphereCommon(center, direction, radius, color, style, depthTest, depthWrite, faceCull, viewProjOverrideIndex, true);
  305. }
  306. void AuxGeomDrawQueue::DrawSphereCommon(
  307. const AZ::Vector3& center,
  308. const AZ::Vector3& direction,
  309. float radius,
  310. const AZ::Color& color,
  311. DrawStyle style,
  312. DepthTest depthTest,
  313. DepthWrite depthWrite,
  314. FaceCullMode faceCull,
  315. int32_t viewProjOverrideIndex,
  316. bool isHemisphere)
  317. {
  318. if (radius <= 0.0f)
  319. {
  320. return;
  321. }
  322. ShapeBufferEntry shape;
  323. shape.m_shapeType = isHemisphere ? ShapeType_Hemisphere : ShapeType_Sphere;
  324. shape.m_depthRead = ConvertRPIDepthTestFlag(depthTest);
  325. shape.m_depthWrite = ConvertRPIDepthWriteFlag(depthWrite);
  326. shape.m_faceCullMode = ConvertRPIFaceCullFlag(faceCull);
  327. shape.m_color = color;
  328. shape.m_rotationMatrix = CreateMatrix3x3FromDirection(direction);
  329. shape.m_position = center;
  330. shape.m_scale = AZ::Vector3(radius, radius, radius);
  331. shape.m_pointSize = m_pointSize;
  332. shape.m_viewProjOverrideIndex = viewProjOverrideIndex;
  333. AddShape(style, shape);
  334. }
  335. void AuxGeomDrawQueue::DrawDisk(
  336. const AZ::Vector3& center,
  337. const AZ::Vector3& direction,
  338. float radius,
  339. const AZ::Color& color,
  340. DrawStyle style,
  341. DepthTest depthTest,
  342. DepthWrite depthWrite,
  343. FaceCullMode faceCull,
  344. int32_t viewProjOverrideIndex)
  345. {
  346. ShapeBufferEntry shape;
  347. shape.m_shapeType = ShapeType_Disk;
  348. shape.m_depthRead = ConvertRPIDepthTestFlag(depthTest);
  349. shape.m_depthWrite = ConvertRPIDepthWriteFlag(depthWrite);
  350. shape.m_faceCullMode = ConvertRPIFaceCullFlag(faceCull);
  351. shape.m_color = color;
  352. // The disk mesh is created with the top of the disk pointing along the positive Y axis. This creates a
  353. // rotation so that the top of the disk will point along the given direction vector.
  354. shape.m_rotationMatrix = CreateMatrix3x3FromDirection(direction);
  355. shape.m_position = center;
  356. shape.m_scale = AZ::Vector3(radius, 1.0f, radius);
  357. shape.m_pointSize = m_pointSize;
  358. shape.m_viewProjOverrideIndex = viewProjOverrideIndex;
  359. AddShape(style, shape);
  360. }
  361. void AuxGeomDrawQueue::DrawCone(
  362. const AZ::Vector3& center,
  363. const AZ::Vector3& direction,
  364. float radius,
  365. float height,
  366. const AZ::Color& color,
  367. DrawStyle style,
  368. DepthTest depthTest,
  369. DepthWrite depthWrite,
  370. FaceCullMode faceCull,
  371. int32_t viewProjOverrideIndex)
  372. {
  373. if (radius <= 0.0f || height <= 0.0f)
  374. {
  375. return;
  376. }
  377. ShapeBufferEntry shape;
  378. shape.m_shapeType = ShapeType_Cone;
  379. shape.m_depthRead = ConvertRPIDepthTestFlag(depthTest);
  380. shape.m_depthWrite = ConvertRPIDepthWriteFlag(depthWrite);
  381. shape.m_faceCullMode = ConvertRPIFaceCullFlag(faceCull);
  382. shape.m_color = color;
  383. shape.m_rotationMatrix = CreateMatrix3x3FromDirection(direction);
  384. shape.m_position = center;
  385. shape.m_scale = AZ::Vector3(radius, height, radius);
  386. shape.m_pointSize = m_pointSize;
  387. shape.m_viewProjOverrideIndex = viewProjOverrideIndex;
  388. AddShape(style, shape);
  389. }
  390. void AuxGeomDrawQueue::DrawCylinder(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, float height, const AZ::Color& color,
  391. DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex)
  392. {
  393. DrawCylinderCommon(center, direction, radius, height, color, style, depthTest, depthWrite, faceCull, viewProjOverrideIndex, true);
  394. }
  395. void AuxGeomDrawQueue::DrawCylinderNoEnds(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, float height, const AZ::Color& color,
  396. DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex)
  397. {
  398. DrawCylinderCommon(center, direction, radius, height, color, style, depthTest, depthWrite, faceCull, viewProjOverrideIndex, false);
  399. }
  400. void AuxGeomDrawQueue::DrawCylinderCommon(
  401. const AZ::Vector3& center,
  402. const AZ::Vector3& direction,
  403. float radius,
  404. float height,
  405. const AZ::Color& color,
  406. DrawStyle style,
  407. DepthTest depthTest,
  408. DepthWrite depthWrite,
  409. FaceCullMode faceCull,
  410. int32_t viewProjOverrideIndex,
  411. bool drawEnds)
  412. {
  413. if (radius <= 0.0f || height <= 0.0f)
  414. {
  415. return;
  416. }
  417. ShapeBufferEntry shape;
  418. shape.m_shapeType = drawEnds ? ShapeType_Cylinder : ShapeType_CylinderNoEnds;
  419. shape.m_depthRead = ConvertRPIDepthTestFlag(depthTest);
  420. shape.m_depthWrite = ConvertRPIDepthWriteFlag(depthWrite);
  421. shape.m_faceCullMode = ConvertRPIFaceCullFlag(faceCull);
  422. shape.m_color = color;
  423. // The cylinder mesh is created with the top end cap of the cylinder facing along the positive Y axis. This creates a
  424. // rotation so that the top face of the cylinder will face along the given direction vector.
  425. shape.m_rotationMatrix = CreateMatrix3x3FromDirection(direction);
  426. shape.m_position = center;
  427. shape.m_scale = AZ::Vector3(radius, height, radius);
  428. shape.m_pointSize = m_pointSize;
  429. shape.m_viewProjOverrideIndex = viewProjOverrideIndex;
  430. AddShape(style, shape);
  431. }
  432. void AuxGeomDrawQueue::DrawAabb(
  433. const AZ::Aabb& aabb,
  434. const AZ::Color& color,
  435. DrawStyle style,
  436. DepthTest depthTest,
  437. DepthWrite depthWrite,
  438. FaceCullMode faceCull,
  439. int32_t viewProjOverrideIndex)
  440. {
  441. BoxBufferEntry box;
  442. box.m_color = color;
  443. box.m_depthRead = ConvertRPIDepthTestFlag(depthTest);
  444. box.m_depthWrite = ConvertRPIDepthWriteFlag(depthWrite);
  445. box.m_faceCullMode = ConvertRPIFaceCullFlag(faceCull);
  446. box.m_position = aabb.GetCenter();
  447. box.m_scale = aabb.GetExtents();
  448. box.m_rotationMatrix = Matrix3x3::CreateIdentity();
  449. box.m_pointSize = m_pointSize;
  450. box.m_viewProjOverrideIndex = viewProjOverrideIndex;
  451. AddBox(style, box);
  452. }
  453. void AuxGeomDrawQueue::DrawAabb(
  454. const AZ::Aabb& aabb,
  455. const AZ::Matrix3x4& matrix3x4,
  456. const AZ::Color& color,
  457. DrawStyle style,
  458. DepthTest depthTest,
  459. DepthWrite depthWrite,
  460. FaceCullMode faceCull,
  461. int32_t viewProjOverrideIndex)
  462. {
  463. AZ::Vector3 center = aabb.GetCenter();
  464. AZ::Vector3 extents = aabb.GetExtents();
  465. AZ::Matrix3x4 localMatrix3x4 = matrix3x4;
  466. BoxBufferEntry box;
  467. box.m_depthRead = ConvertRPIDepthTestFlag(depthTest);
  468. box.m_depthWrite = ConvertRPIDepthWriteFlag(depthWrite);
  469. box.m_faceCullMode = ConvertRPIFaceCullFlag(faceCull);
  470. box.m_color = color;
  471. box.m_scale = localMatrix3x4.ExtractScale() * extents;
  472. box.m_position = matrix3x4 * center;
  473. box.m_rotationMatrix = Matrix3x3::CreateFromMatrix3x4(localMatrix3x4);
  474. box.m_pointSize = m_pointSize;
  475. box.m_viewProjOverrideIndex = viewProjOverrideIndex;
  476. AddBox(style, box);
  477. }
  478. void AuxGeomDrawQueue::DrawObb(
  479. const AZ::Obb& obb,
  480. const AZ::Vector3& position,
  481. const AZ::Color& color,
  482. DrawStyle style,
  483. DepthTest depthTest,
  484. DepthWrite depthWrite,
  485. FaceCullMode faceCull,
  486. int32_t viewProjOverrideIndex)
  487. {
  488. AZ::Vector3 center = obb.GetPosition();
  489. AZ::Vector3 extents(obb.GetHalfLengthX() * 2.0f, obb.GetHalfLengthY() * 2.0f, obb.GetHalfLengthZ() * 2.0f);
  490. BoxBufferEntry box;
  491. box.m_depthRead = ConvertRPIDepthTestFlag(depthTest);
  492. box.m_depthWrite = ConvertRPIDepthWriteFlag(depthWrite);
  493. box.m_faceCullMode = ConvertRPIFaceCullFlag(faceCull);
  494. box.m_color = color;
  495. box.m_scale = extents;
  496. box.m_position = position + center;
  497. box.m_rotationMatrix = Matrix3x3::CreateFromColumns(obb.GetAxisX(), obb.GetAxisY(), obb.GetAxisZ());
  498. box.m_pointSize = m_pointSize;
  499. box.m_viewProjOverrideIndex = viewProjOverrideIndex;
  500. AddBox(style, box);
  501. }
  502. void AuxGeomDrawQueue::DrawObb(
  503. const AZ::Obb& obb,
  504. const AZ::Matrix3x4& matrix3x4,
  505. const AZ::Color& color,
  506. DrawStyle style,
  507. DepthTest depthTest,
  508. DepthWrite depthWrite,
  509. FaceCullMode faceCull,
  510. int32_t viewProjOverrideIndex)
  511. {
  512. AZ::Vector3 center = obb.GetPosition();
  513. AZ::Vector3 extents(obb.GetHalfLengthX() * 2.0f, obb.GetHalfLengthY() * 2.0f, obb.GetHalfLengthZ() * 2.0f);
  514. AZ::Matrix3x4 localMatrix3x4 = matrix3x4;
  515. BoxBufferEntry box;
  516. box.m_depthRead = ConvertRPIDepthTestFlag(depthTest);
  517. box.m_depthWrite = ConvertRPIDepthWriteFlag(depthWrite);
  518. box.m_faceCullMode = ConvertRPIFaceCullFlag(faceCull);
  519. box.m_color = color;
  520. box.m_scale = localMatrix3x4.ExtractScale() * extents;
  521. box.m_position = localMatrix3x4.GetTranslation() + center;
  522. box.m_rotationMatrix = Matrix3x3::CreateFromMatrix3x4(localMatrix3x4) * Matrix3x3::CreateFromColumns(obb.GetAxisX(), obb.GetAxisY(), obb.GetAxisZ());
  523. box.m_pointSize = m_pointSize;
  524. box.m_viewProjOverrideIndex = viewProjOverrideIndex;
  525. AddBox(style, box);
  526. }
  527. void AuxGeomDrawQueue::DrawFrustum(
  528. const Frustum& frustum,
  529. const Color& color,
  530. bool drawNormals,
  531. DrawStyle style,
  532. DepthTest depthTest,
  533. DepthWrite depthWrite,
  534. FaceCullMode faceCull,
  535. int32_t viewProjOverrideIndex)
  536. {
  537. Frustum::CornerVertexArray corners;
  538. bool validFrustum = frustum.GetCorners(corners);
  539. if (validFrustum)
  540. {
  541. // This helps cut down on clutter below. Replace with a using-enum-declaration when c++20 support is required.
  542. enum CornerIndices
  543. {
  544. NearTopLeft = Frustum::CornerIndices::NearTopLeft,
  545. NearTopRight = Frustum::CornerIndices::NearTopRight,
  546. NearBottomLeft = Frustum::CornerIndices::NearBottomLeft,
  547. NearBottomRight = Frustum::CornerIndices::NearBottomRight,
  548. FarTopLeft = Frustum::CornerIndices::FarTopLeft,
  549. FarTopRight = Frustum::CornerIndices::FarTopRight,
  550. FarBottomLeft = Frustum::CornerIndices::FarBottomLeft,
  551. FarBottomRight = Frustum::CornerIndices::FarBottomRight,
  552. };
  553. RPI::AuxGeomDraw::AuxGeomDynamicIndexedDrawArguments drawArgs;
  554. drawArgs.m_verts = corners.data();
  555. drawArgs.m_vertCount = 8;
  556. drawArgs.m_colors = &color;
  557. drawArgs.m_colorCount = 1;
  558. drawArgs.m_depthTest = depthTest;
  559. drawArgs.m_depthWrite = depthWrite;
  560. drawArgs.m_viewProjectionOverrideIndex = viewProjOverrideIndex;
  561. if (style == DrawStyle::Point)
  562. {
  563. DrawPoints(drawArgs);
  564. }
  565. else
  566. {
  567. // Always draw lines if draw style isn't Point.
  568. uint32_t lineIndices[24]{
  569. //near plane
  570. NearTopLeft, NearTopRight,
  571. NearTopRight, NearBottomRight,
  572. NearBottomRight, NearBottomLeft,
  573. NearBottomLeft, NearTopLeft,
  574. //Far plane
  575. FarTopLeft, FarTopRight,
  576. FarTopRight, FarBottomRight,
  577. FarBottomRight, FarBottomLeft,
  578. FarBottomLeft, FarTopLeft,
  579. //Near-to-Far connecting lines
  580. NearTopLeft, FarTopLeft,
  581. NearTopRight, FarTopRight,
  582. NearBottomLeft, FarBottomLeft,
  583. NearBottomRight, FarBottomRight,
  584. };
  585. drawArgs.m_indices = lineIndices;
  586. drawArgs.m_indexCount = 24;
  587. DrawLines(drawArgs);
  588. if (style == DrawStyle::Solid || style == DrawStyle::Shaded)
  589. {
  590. // DrawTriangles doesn't support shaded drawing, so we can't support it here either.
  591. AZ_WarningOnce("AuxGeomDrawQueue", style != DrawStyle::Shaded, "Cannot draw frustum with Shaded DrawStyle, using Solid instead.");
  592. uint32_t triangleIndices[36]{
  593. //near
  594. NearBottomLeft, NearTopLeft, NearTopRight,
  595. NearBottomLeft, NearTopRight, NearBottomRight,
  596. //far
  597. FarBottomRight, FarTopRight, FarTopLeft,
  598. FarBottomRight, FarTopLeft, FarBottomLeft,
  599. //left
  600. NearTopLeft, NearBottomLeft, FarBottomLeft,
  601. NearTopLeft, FarBottomLeft, FarTopLeft,
  602. //right
  603. NearBottomRight, NearTopRight, FarTopRight,
  604. NearBottomRight, FarTopRight, FarBottomRight,
  605. //bottom
  606. FarBottomLeft, NearBottomLeft, NearBottomRight,
  607. FarBottomLeft, NearBottomRight, FarBottomRight,
  608. //top
  609. NearTopLeft, FarTopLeft, FarTopRight,
  610. NearTopLeft, FarTopRight, NearTopRight,
  611. };
  612. Color transparentColor(color.GetR(), color.GetG(), color.GetB(), color.GetA() * 0.3f);
  613. drawArgs.m_indices = triangleIndices;
  614. drawArgs.m_indexCount = 36;
  615. drawArgs.m_colors = &transparentColor;
  616. DrawTriangles(drawArgs, faceCull);
  617. }
  618. }
  619. if (drawNormals)
  620. {
  621. Vector3 planeNormals[] =
  622. {
  623. //near
  624. 0.25f * (corners[NearBottomLeft] + corners[NearBottomRight] + corners[NearTopLeft] + corners[NearTopRight]),
  625. 0.25f * (corners[NearBottomLeft] + corners[NearBottomRight] + corners[NearTopLeft] + corners[NearTopRight]) + frustum.GetPlane(Frustum::PlaneId::Near).GetNormal(),
  626. //far
  627. 0.25f * (corners[FarBottomLeft] + corners[FarBottomRight] + corners[FarTopLeft] + corners[FarTopRight]),
  628. 0.25f * (corners[FarBottomLeft] + corners[FarBottomRight] + corners[FarTopLeft] + corners[FarTopRight]) + frustum.GetPlane(Frustum::PlaneId::Far).GetNormal(),
  629. //left
  630. 0.5f * (corners[NearBottomLeft] + corners[NearTopLeft]),
  631. 0.5f * (corners[NearBottomLeft] + corners[NearTopLeft]) + frustum.GetPlane(Frustum::PlaneId::Left).GetNormal(),
  632. //right
  633. 0.5f * (corners[NearBottomRight] + corners[NearTopRight]),
  634. 0.5f * (corners[NearBottomRight] + corners[NearTopRight]) + frustum.GetPlane(Frustum::PlaneId::Right).GetNormal(),
  635. //bottom
  636. 0.5f * (corners[NearBottomLeft] + corners[NearBottomRight]),
  637. 0.5f * (corners[NearBottomLeft] + corners[NearBottomRight]) + frustum.GetPlane(Frustum::PlaneId::Bottom).GetNormal(),
  638. //top
  639. 0.5f * (corners[NearTopLeft] + corners[NearTopRight]),
  640. 0.5f * (corners[NearTopLeft] + corners[NearTopRight]) + frustum.GetPlane(Frustum::PlaneId::Top).GetNormal(),
  641. };
  642. Color planeNormalColors[] =
  643. {
  644. Colors::Red, Colors::Red, //near
  645. Colors::Green, Colors::Green, //far
  646. Colors::Blue, Colors::Blue, //left
  647. Colors::Orange, Colors::Orange, //right
  648. Colors::Pink, Colors::Pink, //bottom
  649. Colors::MediumPurple, Colors::MediumPurple, //top
  650. };
  651. RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments planeNormalLineArgs;
  652. planeNormalLineArgs.m_verts = planeNormals;
  653. planeNormalLineArgs.m_vertCount = 12;
  654. planeNormalLineArgs.m_colors = planeNormalColors;
  655. planeNormalLineArgs.m_colorCount = planeNormalLineArgs.m_vertCount;
  656. planeNormalLineArgs.m_depthTest = depthTest;
  657. DrawLines(planeNormalLineArgs);
  658. }
  659. }
  660. else
  661. {
  662. AZ_Assert(false, "invalid frustum, cannot draw");
  663. }
  664. }
  665. AuxGeomBufferData* AuxGeomDrawQueue::Commit()
  666. {
  667. AZ_PROFILE_SCOPE(AzRender, "AuxGeomDrawQueue: Commit");
  668. // get a mutually exclusive lock and then switch to the next buffer, returning a pointer to the current buffer (before the switch)
  669. // grab the lock
  670. AZStd::lock_guard<AZStd::recursive_mutex> lock(m_buffersWriteLock);
  671. // get a pointer to the buffer we have been filling
  672. AuxGeomBufferData* filledBufferData = &m_buffers[m_currentBufferIndex];
  673. // switch the buffer for future requests to the other buffer
  674. m_currentBufferIndex = (m_currentBufferIndex + 1) % NumBuffers;
  675. // Clear the buffers that new requests will get added to
  676. ClearCurrentBufferData();
  677. return filledBufferData;
  678. }
  679. void AuxGeomDrawQueue::ClearCurrentBufferData()
  680. {
  681. AZ_PROFILE_SCOPE(AzRender, "AuxGeomDrawQueue: ClearCurrentBufferData");
  682. // no need for mutex here, this function is only called from a function holding a lock
  683. AuxGeomBufferData& data = m_buffers[m_currentBufferIndex];
  684. DynamicPrimitiveData& primitives = data.m_primitiveData;
  685. primitives.m_primitiveBuffer.clear();
  686. primitives.m_vertexBuffer.clear();
  687. primitives.m_indexBuffer.clear();
  688. for (int drawStyle = 0; drawStyle < DrawStyle_Count; ++drawStyle)
  689. {
  690. data.m_opaqueShapes[drawStyle].clear();
  691. data.m_translucentShapes[drawStyle].clear();
  692. data.m_opaqueBoxes[drawStyle].clear();
  693. data.m_translucentBoxes[drawStyle].clear();
  694. }
  695. data.m_viewProjOverrides.clear();
  696. data.m_2DViewProjOverrideIndex = -1;
  697. }
  698. bool AuxGeomDrawQueue::ShouldBatchDraw(
  699. DynamicPrimitiveData& primBuffer,
  700. AuxGeomPrimitiveType primType,
  701. AuxGeomBlendMode blendMode,
  702. AuxGeomDepthReadType depthRead,
  703. AuxGeomDepthWriteType depthWrite,
  704. AuxGeomFaceCullMode faceCull,
  705. u8 width,
  706. int32_t viewProjOverrideIndex)
  707. {
  708. if (!primBuffer.m_primitiveBuffer.size())
  709. {
  710. return false;
  711. }
  712. auto& primitive = primBuffer.m_primitiveBuffer.back();
  713. if ( primitive.m_primitiveType == primType &&
  714. blendMode == BlendMode_Off &&
  715. primitive.m_blendMode == BlendMode_Off &&
  716. primitive.m_depthReadType == depthRead &&
  717. primitive.m_depthWriteType == depthWrite &&
  718. primitive.m_faceCullMode == faceCull &&
  719. primitive.m_width == width &&
  720. primitive.m_viewProjOverrideIndex == viewProjOverrideIndex)
  721. {
  722. return true;
  723. }
  724. return false;
  725. }
  726. void AuxGeomDrawQueue::DrawPrimitiveCommon(
  727. AuxGeomPrimitiveType primitiveType,
  728. [[maybe_unused]] uint32_t verticesPerPrimitiveType,
  729. uint32_t vertexCount,
  730. const AZ::Vector3* points,
  731. AZStd::function<AZ::u32(uint32_t)> packedColorFunction,
  732. bool isOpaque,
  733. AuxGeomDepthReadType depthRead,
  734. AuxGeomDepthWriteType depthWrite,
  735. AuxGeomFaceCullMode faceCull,
  736. AZ::u8 width,
  737. int32_t viewProjOverrideIndex)
  738. {
  739. // grab a mutex lock for the rest of this function so that a commit cannot happen during it and
  740. // other threads can't add geometry during it
  741. AZStd::lock_guard<AZStd::recursive_mutex> lock(m_buffersWriteLock);
  742. AuxGeomBufferData& buffer = m_buffers[m_currentBufferIndex];
  743. // We have a separate PrimitiveBufferEntry for each AuxGeomDraw call
  744. DynamicPrimitiveData& primBuffer = buffer.m_primitiveData;
  745. AuxGeomIndex vertexOffset = aznumeric_cast<AuxGeomIndex>(primBuffer.m_vertexBuffer.size());
  746. AuxGeomIndex indexOffset = aznumeric_cast<AuxGeomIndex>(primBuffer.m_indexBuffer.size());
  747. const size_t vertexCountTotal = aznumeric_cast<size_t>(vertexOffset) + vertexCount;
  748. if (vertexCountTotal > MaxDynamicVertexCount)
  749. {
  750. AZ_WarningOnce("AuxGeom", false, "Draw function ignored, would exceed maximum allowed index of %d", MaxDynamicVertexCount);
  751. return;
  752. }
  753. AZ::Vector3 center(0.0f, 0.0f, 0.0f);
  754. for (uint32_t vertexIndex = 0; vertexIndex < vertexCount; ++vertexIndex)
  755. {
  756. AZ::u32 packedColor = packedColorFunction(vertexIndex);
  757. const AZ::Vector3& vertex = points[vertexIndex];
  758. primBuffer.m_vertexBuffer.push_back(AuxGeomDynamicVertex(vertex, packedColor));
  759. primBuffer.m_indexBuffer.push_back(vertexOffset + vertexIndex);
  760. center += vertex;
  761. }
  762. center /= static_cast<float>(vertexCount);
  763. AuxGeomBlendMode blendMode = isOpaque ? BlendMode_Off : BlendMode_Alpha;
  764. if (ShouldBatchDraw(primBuffer, primitiveType, blendMode, depthRead, depthWrite, faceCull, width, viewProjOverrideIndex))
  765. {
  766. auto& primitive = primBuffer.m_primitiveBuffer.back();
  767. primitive.m_indexCount += vertexCount;
  768. }
  769. else
  770. {
  771. auto& primitive = primBuffer.m_primitiveBuffer.emplace_back();
  772. primitive.m_primitiveType = primitiveType;
  773. primitive.m_depthReadType = depthRead;
  774. primitive.m_depthWriteType = depthWrite;
  775. primitive.m_blendMode = blendMode;
  776. primitive.m_faceCullMode = faceCull;
  777. primitive.m_width = width;
  778. primitive.m_indexOffset = indexOffset;
  779. primitive.m_indexCount = vertexCount;
  780. primitive.m_center = center;
  781. primitive.m_viewProjOverrideIndex = viewProjOverrideIndex;
  782. }
  783. }
  784. void AuxGeomDrawQueue::DrawPrimitiveWithSharedVerticesCommon(
  785. AuxGeomPrimitiveType primitiveType,
  786. [[maybe_unused]] uint32_t verticesPerPrimitiveType,
  787. uint32_t vertexCount,
  788. uint32_t indexCount,
  789. const AZ::Vector3* points,
  790. AZStd::function<AZ::u32(uint32_t)> packedColorFunction,
  791. AZStd::function<AuxGeomIndex(uint32_t)> indexFunction,
  792. bool isOpaque,
  793. AuxGeomDepthReadType depthRead,
  794. AuxGeomDepthWriteType depthWrite,
  795. AuxGeomFaceCullMode faceCull,
  796. AZ::u8 width,
  797. int32_t viewProjOverrideIndex)
  798. {
  799. AZ_Assert(indexCount >= verticesPerPrimitiveType && (indexCount % verticesPerPrimitiveType == 0),
  800. "Index count must be at least %d and must be a multiple of %d",
  801. verticesPerPrimitiveType, verticesPerPrimitiveType);
  802. // grab a mutex lock for the rest of this function so that a commit cannot happen during it and
  803. // other threads can't add geometry during it
  804. AZStd::lock_guard<AZStd::recursive_mutex> lock(m_buffersWriteLock);
  805. AuxGeomBufferData& buffer = m_buffers[m_currentBufferIndex];
  806. // We have a separate PrimitiveBufferEntry for each AuxGeomDraw call
  807. DynamicPrimitiveData& primBuffer = buffer.m_primitiveData;
  808. AuxGeomIndex vertexOffset = aznumeric_cast<AuxGeomIndex>(primBuffer.m_vertexBuffer.size());
  809. AuxGeomIndex indexOffset = aznumeric_cast<AuxGeomIndex>(primBuffer.m_indexBuffer.size());
  810. const size_t vertexCountTotal = aznumeric_cast<size_t>(vertexOffset) + vertexCount;
  811. if (vertexCountTotal > MaxDynamicVertexCount)
  812. {
  813. AZ_WarningOnce("AuxGeom", false, "Draw function ignored, would exceed maximum allowed index of %d", MaxDynamicVertexCount);
  814. return;
  815. }
  816. AZ::Vector3 center(0.0f, 0.0f, 0.0f);
  817. for (uint32_t vertexIndex = 0; vertexIndex < vertexCount; ++vertexIndex)
  818. {
  819. AZ::u32 packedColor = packedColorFunction(vertexIndex);
  820. const AZ::Vector3& vertex = points[vertexIndex];
  821. primBuffer.m_vertexBuffer.push_back(AuxGeomDynamicVertex(vertex, packedColor));
  822. center += vertex;
  823. }
  824. center /= aznumeric_cast<float>(vertexCount);
  825. for (uint32_t index = 0; index < indexCount; ++index)
  826. {
  827. primBuffer.m_indexBuffer.push_back(vertexOffset + indexFunction(index));
  828. }
  829. AuxGeomBlendMode blendMode = isOpaque ? BlendMode_Off : BlendMode_Alpha;
  830. if (ShouldBatchDraw(primBuffer, primitiveType, blendMode, depthRead, depthWrite, faceCull, width, viewProjOverrideIndex))
  831. {
  832. auto& primitive = primBuffer.m_primitiveBuffer.back();
  833. primitive.m_indexCount += indexCount;
  834. }
  835. else
  836. {
  837. auto& primitive = primBuffer.m_primitiveBuffer.emplace_back();
  838. primitive.m_primitiveType = primitiveType;
  839. primitive.m_depthReadType = depthRead;
  840. primitive.m_depthWriteType = depthWrite;
  841. primitive.m_blendMode = blendMode;
  842. primitive.m_faceCullMode = faceCull;
  843. primitive.m_width = width;
  844. primitive.m_indexOffset = indexOffset;
  845. primitive.m_indexCount = indexCount;
  846. primitive.m_center = center;
  847. primitive.m_viewProjOverrideIndex = viewProjOverrideIndex;
  848. }
  849. }
  850. void AuxGeomDrawQueue::AddShape(DrawStyle style, const ShapeBufferEntry& shape)
  851. {
  852. AuxGeomDrawStyle drawStyle = ConvertRPIDrawStyle(style);
  853. // grab a mutex lock for the rest of this function so that a commit cannot happen during it and
  854. // other threads can't add geometry during it
  855. AZStd::lock_guard<AZStd::recursive_mutex> lock(m_buffersWriteLock);
  856. AuxGeomBufferData& buffer = m_buffers[m_currentBufferIndex];
  857. if (IsOpaque(shape.m_color))
  858. {
  859. buffer.m_opaqueShapes[drawStyle].push_back(shape);
  860. }
  861. else
  862. {
  863. buffer.m_translucentShapes[drawStyle].push_back(shape);
  864. }
  865. }
  866. void AuxGeomDrawQueue::AddBox(DrawStyle style, BoxBufferEntry& box)
  867. {
  868. AuxGeomDrawStyle drawStyle = ConvertRPIDrawStyle(style);
  869. // grab a mutex lock for the rest of this function so that a commit cannot happen during it and
  870. // other threads can't add geometry during it
  871. AZStd::lock_guard<AZStd::recursive_mutex> lock(m_buffersWriteLock);
  872. AuxGeomBufferData& buffer = m_buffers[m_currentBufferIndex];
  873. if (IsOpaque(box.m_color))
  874. {
  875. buffer.m_opaqueBoxes[drawStyle].push_back(box);
  876. }
  877. else
  878. {
  879. buffer.m_translucentBoxes[drawStyle].push_back(box);
  880. }
  881. }
  882. } // namespace Render
  883. } // namespace AZ