FixedShapeProcessor.cpp 76 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740
  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 "FixedShapeProcessor.h"
  9. #include "AuxGeomDrawProcessorShared.h"
  10. #include <AzCore/std/algorithm.h>
  11. #include <AzCore/std/containers/array.h>
  12. #include <Atom/RHI/Factory.h>
  13. #include <Atom/RHI/DrawPacketBuilder.h>
  14. #include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
  15. #include <Atom/RPI.Reflect/Shader/ShaderOptionGroup.h>
  16. #include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
  17. #include <Atom/RPI.Public/RPIUtils.h>
  18. #include <Atom/RPI.Public/Scene.h>
  19. #include <Atom/RPI.Public/Shader/Shader.h>
  20. #include <Atom/RPI.Public/Shader/ShaderVariant.h>
  21. #include <Atom/RPI.Public/View.h>
  22. namespace AZ
  23. {
  24. namespace Render
  25. {
  26. namespace
  27. {
  28. static constexpr u8 PositionStreamIndex = 0;
  29. static constexpr u8 NormalStreamIndex = 1;
  30. static const char* const ShapePerspectiveTypeViewProjection = "ViewProjectionMode::ViewProjection";
  31. static const char* const ShapePerspectiveTypeManualOverride = "ViewProjectionMode::ManualOverride";
  32. AZ::Name GetAuxGeomPerspectiveTypeName(AuxGeomShapePerpectiveType shapePerspectiveType)
  33. {
  34. switch (shapePerspectiveType)
  35. {
  36. case PerspectiveType_ViewProjection:
  37. return Name(ShapePerspectiveTypeViewProjection);
  38. case PerspectiveType_ManualOverride:
  39. return Name(ShapePerspectiveTypeManualOverride);
  40. default:
  41. AZ_Assert(false, "Invalid perspective type value %d", aznumeric_cast<int>(shapePerspectiveType));
  42. return Name(ShapePerspectiveTypeViewProjection);
  43. }
  44. }
  45. }
  46. bool FixedShapeProcessor::Initialize(RHI::MultiDevice::DeviceMask deviceMask, const AZ::RPI::Scene* scene)
  47. {
  48. RHI::BufferPoolDescriptor desc;
  49. desc.m_heapMemoryLevel = RHI::HeapMemoryLevel::Device;
  50. desc.m_bindFlags = RHI::BufferBindFlags::InputAssembly;
  51. desc.m_deviceMask = deviceMask;
  52. m_bufferPool = aznew RHI::BufferPool;
  53. m_bufferPool->SetName(Name("AuxGeomFixedShapeBufferPool"));
  54. RHI::ResultCode resultCode = m_bufferPool->Init(desc);
  55. if (resultCode != RHI::ResultCode::Success)
  56. {
  57. AZ_Error("FixedShapeProcessor", false, "Failed to initialize AuxGeom fixed shape buffer pool");
  58. return false;
  59. }
  60. SetupInputStreamLayout(m_objectStreamLayout[DrawStyle_Point], RHI::PrimitiveTopology::PointList, false);
  61. SetupInputStreamLayout(m_objectStreamLayout[DrawStyle_Line], RHI::PrimitiveTopology::LineList, false);
  62. SetupInputStreamLayout(m_objectStreamLayout[DrawStyle_Solid], RHI::PrimitiveTopology::TriangleList, false);
  63. SetupInputStreamLayout(m_objectStreamLayout[DrawStyle_Shaded], RHI::PrimitiveTopology::TriangleList, true);
  64. CreateSphereBuffersAndViews(AuxGeomShapeType::ShapeType_Sphere);
  65. CreateSphereBuffersAndViews(AuxGeomShapeType::ShapeType_Hemisphere);
  66. CreateQuadBuffersAndViews();
  67. CreateDiskBuffersAndViews();
  68. CreateConeBuffersAndViews();
  69. CreateCylinderBuffersAndViews(AuxGeomShapeType::ShapeType_Cylinder);
  70. CreateCylinderBuffersAndViews(AuxGeomShapeType::ShapeType_CylinderNoEnds);
  71. CreateBoxBuffersAndViews();
  72. // cache scene pointer for RHI::PipelineState creation.
  73. m_scene = scene;
  74. LoadShaders();
  75. return true;
  76. }
  77. void FixedShapeProcessor::Release()
  78. {
  79. if (m_bufferPool)
  80. {
  81. m_bufferPool.reset();
  82. }
  83. m_processSrgs.clear();
  84. m_drawPackets.clear();
  85. m_litShader = nullptr;
  86. m_unlitShader = nullptr;
  87. m_scene = nullptr;
  88. for (RPI::Ptr<RPI::PipelineStateForDraw>* pipelineState : m_createdPipelineStates)
  89. {
  90. pipelineState->reset();
  91. }
  92. m_createdPipelineStates.clear();
  93. m_needUpdatePipelineStates = false;
  94. }
  95. void FixedShapeProcessor::PrepareFrame()
  96. {
  97. if (m_needUpdatePipelineStates)
  98. {
  99. // for created pipeline state, re-set their data from scene
  100. for (RPI::Ptr<RPI::PipelineStateForDraw>* pipelineState : m_createdPipelineStates)
  101. {
  102. (*pipelineState)->SetOutputFromScene(m_scene);
  103. (*pipelineState)->Finalize();
  104. }
  105. m_needUpdatePipelineStates = false;
  106. }
  107. }
  108. void FixedShapeProcessor::FrameEnd()
  109. {
  110. m_processSrgs.clear();
  111. m_drawPackets.clear();
  112. }
  113. void FixedShapeProcessor::ProcessObjects(const AuxGeomBufferData* bufferData, const RPI::FeatureProcessor::RenderPacket& fpPacket)
  114. {
  115. AZ_PROFILE_SCOPE(AzRender, "FixedShapeProcessor: ProcessObjects");
  116. RHI::DrawPacketBuilder drawPacketBuilder{RHI::MultiDevice::AllDevices};
  117. // Draw opaque shapes with LODs. This requires a separate draw packet per shape per view that it is in (usually only one)
  118. // We do each draw style together to reduce state changes
  119. for (int drawStyle = 0; drawStyle < DrawStyle_Count; ++drawStyle)
  120. {
  121. auto drawListTag = GetShaderDataForDrawStyle(drawStyle).m_drawListTag;
  122. // Skip this draw style if the owner scene doesn't have this drawListTag (which means this FP won't even create the RHI PipelineState for draw)
  123. if (!m_scene->HasOutputForPipelineState(drawListTag))
  124. {
  125. return;
  126. }
  127. // Draw all of the opaque shapes of this draw style
  128. // Possible TODO: Batch together shapes of the same type and LOD using instanced draw [ATOM-1032]
  129. // Note that this optimization may not be worth it for shapes because of LODs
  130. for (const auto& shape : bufferData->m_opaqueShapes[drawStyle])
  131. {
  132. PipelineStateOptions pipelineStateOptions;
  133. pipelineStateOptions.m_perpectiveType = (AuxGeomShapePerpectiveType)(shape.m_viewProjOverrideIndex >= 0);
  134. pipelineStateOptions.m_blendMode = BlendMode_Off;
  135. pipelineStateOptions.m_drawStyle = (AuxGeomDrawStyle)drawStyle;
  136. pipelineStateOptions.m_depthReadType = shape.m_depthRead;
  137. pipelineStateOptions.m_depthWriteType = shape.m_depthWrite;
  138. pipelineStateOptions.m_faceCullMode = shape.m_faceCullMode;
  139. RPI::Ptr<RPI::PipelineStateForDraw> pipelineState = GetPipelineState(pipelineStateOptions);
  140. const AZ::Vector3 position = shape.m_position;
  141. const AZ::Vector3 scale = shape.m_scale;
  142. for (auto& view : fpPacket.m_views)
  143. {
  144. // If this view is ignoring packets with our draw list tag then skip this view
  145. if (!view->HasDrawListTag(drawListTag))
  146. {
  147. continue;
  148. }
  149. LodIndex lodIndex = GetLodIndexForShape(shape.m_shapeType, view.get(), position, scale);
  150. auto drawPacket = BuildDrawPacketForShape(
  151. drawPacketBuilder, shape, drawStyle, bufferData->m_viewProjOverrides, pipelineState, lodIndex);
  152. if (drawPacket)
  153. {
  154. m_drawPackets.emplace_back(drawPacket);
  155. view->AddDrawPacket(drawPacket.get());
  156. }
  157. }
  158. }
  159. for (const auto& box : bufferData->m_opaqueBoxes[drawStyle])
  160. {
  161. PipelineStateOptions pipelineStateOptions;
  162. pipelineStateOptions.m_perpectiveType = (AuxGeomShapePerpectiveType)(box.m_viewProjOverrideIndex >= 0);
  163. pipelineStateOptions.m_blendMode = BlendMode_Off;
  164. pipelineStateOptions.m_drawStyle = (AuxGeomDrawStyle)drawStyle;
  165. pipelineStateOptions.m_depthReadType = box.m_depthRead;
  166. pipelineStateOptions.m_depthWriteType = box.m_depthWrite;
  167. pipelineStateOptions.m_faceCullMode = box.m_faceCullMode;
  168. RPI::Ptr<RPI::PipelineStateForDraw> pipelineState = GetPipelineState(pipelineStateOptions);
  169. auto drawPacket =
  170. BuildDrawPacketForBox(drawPacketBuilder, box, drawStyle, bufferData->m_viewProjOverrides, pipelineState);
  171. if (drawPacket)
  172. {
  173. m_drawPackets.emplace_back(drawPacket);
  174. for (auto& view : fpPacket.m_views)
  175. {
  176. // If this view is ignoring packets with our draw list tag then skip this view
  177. if (!view->HasDrawListTag(drawListTag))
  178. {
  179. continue;
  180. }
  181. view->AddDrawPacket(drawPacket.get());
  182. }
  183. }
  184. }
  185. }
  186. // Draw all of the translucent objects (shapes and boxes) with a distance sort key per view
  187. // We have to create separate draw packets for each view that the AuxGeom is in (typically only one)
  188. // because of distance sorting
  189. for (int drawStyle = 0; drawStyle < DrawStyle_Count; ++drawStyle)
  190. {
  191. auto drawListTag = GetShaderDataForDrawStyle(drawStyle).m_drawListTag;
  192. // Skip this draw style if the owner scene doesn't have this drawListTag (which means this FP won't even create the RHI PipelineState for draw)
  193. if (!m_scene->HasOutputForPipelineState(drawListTag))
  194. {
  195. return;
  196. }
  197. // Draw all the shapes of this draw style
  198. for (const auto& shape : bufferData->m_translucentShapes[drawStyle])
  199. {
  200. PipelineStateOptions pipelineStateOptions;
  201. pipelineStateOptions.m_perpectiveType = (AuxGeomShapePerpectiveType)(shape.m_viewProjOverrideIndex >= 0);
  202. pipelineStateOptions.m_blendMode = BlendMode_Alpha;
  203. pipelineStateOptions.m_drawStyle = (AuxGeomDrawStyle)drawStyle;
  204. pipelineStateOptions.m_depthReadType = shape.m_depthRead;
  205. pipelineStateOptions.m_depthWriteType = shape.m_depthWrite;
  206. pipelineStateOptions.m_faceCullMode = shape.m_faceCullMode;
  207. RPI::Ptr<RPI::PipelineStateForDraw> pipelineState = GetPipelineState(pipelineStateOptions);
  208. const AZ::Vector3 position = shape.m_position;
  209. const AZ::Vector3 scale = shape.m_scale;
  210. for (auto& view : fpPacket.m_views)
  211. {
  212. // If this view is ignoring packets with our draw list tag then skip this view
  213. if (!view->HasDrawListTag(drawListTag))
  214. {
  215. continue;
  216. }
  217. RHI::DrawItemSortKey sortKey = view->GetSortKeyForPosition(position);
  218. LodIndex lodIndex = GetLodIndexForShape(shape.m_shapeType, view.get(), position, scale);
  219. auto drawPacket = BuildDrawPacketForShape(
  220. drawPacketBuilder, shape, drawStyle, bufferData->m_viewProjOverrides, pipelineState, lodIndex, sortKey);
  221. if (drawPacket)
  222. {
  223. m_drawPackets.emplace_back(drawPacket);
  224. view->AddDrawPacket(drawPacket.get());
  225. }
  226. }
  227. }
  228. // Draw all the boxes of this draw style
  229. for (const auto& box : bufferData->m_translucentBoxes[drawStyle])
  230. {
  231. PipelineStateOptions pipelineStateOptions;
  232. pipelineStateOptions.m_perpectiveType = (AuxGeomShapePerpectiveType)(box.m_viewProjOverrideIndex >= 0);
  233. pipelineStateOptions.m_blendMode = BlendMode_Alpha;
  234. pipelineStateOptions.m_drawStyle = (AuxGeomDrawStyle)drawStyle;
  235. pipelineStateOptions.m_depthReadType = box.m_depthRead;
  236. pipelineStateOptions.m_depthWriteType = box.m_depthWrite;
  237. pipelineStateOptions.m_faceCullMode = box.m_faceCullMode;
  238. RPI::Ptr<RPI::PipelineStateForDraw> pipelineState = GetPipelineState(pipelineStateOptions);
  239. const AZ::Vector3 position = box.m_position;
  240. for (auto& view : fpPacket.m_views)
  241. {
  242. // If this view is ignoring packets with our draw list tag then skip this view
  243. if (!view->HasDrawListTag(drawListTag))
  244. {
  245. continue;
  246. }
  247. RHI::DrawItemSortKey sortKey = view->GetSortKeyForPosition(position);
  248. auto drawPacket = BuildDrawPacketForBox(
  249. drawPacketBuilder, box, drawStyle, bufferData->m_viewProjOverrides, pipelineState, sortKey);
  250. if (drawPacket)
  251. {
  252. m_drawPackets.emplace_back(drawPacket);
  253. view->AddDrawPacket(drawPacket.get());
  254. }
  255. }
  256. }
  257. }
  258. }
  259. bool FixedShapeProcessor::CreateSphereBuffersAndViews(AuxGeomShapeType sphereShapeType)
  260. {
  261. AZ_Assert(sphereShapeType == ShapeType_Sphere || sphereShapeType == ShapeType_Hemisphere,
  262. "Trying to create sphere buffers and views with a non-sphere shape type!");
  263. const uint32_t numSphereLods = 5;
  264. struct LodInfo
  265. {
  266. uint32_t numRings;
  267. uint32_t numSections;
  268. float screenPercentage;
  269. };
  270. const AZStd::array<LodInfo, numSphereLods> lodInfo =
  271. {{
  272. { 25, 25, 0.1000f},
  273. { 21, 21, 0.0100f},
  274. { 17, 17, 0.0010f},
  275. { 13, 13, 0.0001f},
  276. { 9, 9, 0.0000f}
  277. }};
  278. auto& m_shape = m_shapes[sphereShapeType];
  279. m_shape.m_numLods = numSphereLods;
  280. for (uint32_t lodIndex = 0; lodIndex < numSphereLods; ++lodIndex)
  281. {
  282. MeshData meshData;
  283. CreateSphereMeshData(meshData, lodInfo[lodIndex].numRings, lodInfo[lodIndex].numSections, sphereShapeType);
  284. ObjectBuffers objectBuffers;
  285. if (!CreateBuffersAndViews(objectBuffers, meshData))
  286. {
  287. m_shape.m_numLods = 0;
  288. return false;
  289. }
  290. m_shape.m_lodBuffers.emplace_back(objectBuffers);
  291. m_shape.m_lodScreenPercentages.push_back(lodInfo[lodIndex].screenPercentage);
  292. }
  293. return true;
  294. }
  295. void FixedShapeProcessor::CreateSphereMeshData(MeshData& meshData, uint32_t numRings, uint32_t numSections, AuxGeomShapeType sphereShapeType)
  296. {
  297. const float radius = 1.0f;
  298. // calculate "inner" vertices
  299. float sectionAngle(DegToRad(360.0f / static_cast<float>(numSections)));
  300. float ringSlice(DegToRad(180.0f / static_cast<float>(numRings)));
  301. uint32_t numberOfPoles = 2;
  302. if (sphereShapeType == ShapeType_Hemisphere)
  303. {
  304. numberOfPoles = 1;
  305. numRings = (numRings + 1) / 2;
  306. ringSlice = DegToRad(90.0f / static_cast<float>(numRings));
  307. }
  308. // calc required number of vertices/indices/triangles to build a sphere for the given parameters
  309. uint32_t numVertices = (numRings - 1) * numSections + numberOfPoles;
  310. // setup buffers
  311. auto& positions = meshData.m_positions;
  312. positions.clear();
  313. positions.reserve(numVertices);
  314. auto& normals = meshData.m_normals;
  315. normals.clear();
  316. normals.reserve(numVertices);
  317. using PosType = AuxGeomPosition;
  318. using NormalType = AuxGeomNormal;
  319. // 1st pole vertex
  320. positions.push_back(PosType(0.0f, radius, 0.0f));
  321. normals.push_back(NormalType(0.0f, 1.0f, 0.0f));
  322. for (uint32_t ring = 1; ring < numRings - numberOfPoles + 2; ++ring)
  323. {
  324. float w(sinf(ring * ringSlice));
  325. for (uint32_t section = 0; section < numSections; ++section)
  326. {
  327. float x = radius * cosf(section * sectionAngle) * w;
  328. float y = radius * cosf(ring * ringSlice);
  329. float z = radius * sinf(section * sectionAngle) * w;
  330. Vector3 radialVector(x, y, z);
  331. positions.push_back(radialVector);
  332. normals.push_back(radialVector.GetNormalized());
  333. }
  334. }
  335. if (sphereShapeType == ShapeType_Sphere)
  336. {
  337. // 2nd vertex of pole (for end cap)
  338. positions.push_back(PosType(0.0f, -radius, 0.0f));
  339. normals.push_back(NormalType(0.0f, -1.0f, 0.0f));
  340. }
  341. // point indices
  342. {
  343. auto& indices = meshData.m_pointIndices;
  344. indices.clear();
  345. indices.reserve(positions.size());
  346. for (uint16_t index = 0; index < aznumeric_cast<uint16_t>(positions.size()); ++index)
  347. {
  348. indices.push_back(index);
  349. }
  350. }
  351. // line indices
  352. {
  353. // NumEdges = NumRingEdges + NumSectionEdges = (numRings * numSections) + (numRings * numSections)
  354. const uint32_t numEdges = numRings * numSections * 2;
  355. const uint32_t numLineIndices = numEdges * 2;
  356. // build "inner" faces
  357. auto& indices = meshData.m_lineIndices;
  358. indices.clear();
  359. indices.reserve(numLineIndices);
  360. for (uint16_t ring = 0; ring < numRings - numberOfPoles + 1; ++ring)
  361. {
  362. uint16_t firstVertOfThisRing = static_cast<uint16_t>(1 + ring * numSections);
  363. for (uint16_t section = 0; section < numSections; ++section)
  364. {
  365. uint32_t nextSection = (section + 1) % numSections;
  366. // line around ring
  367. indices.push_back(firstVertOfThisRing + section);
  368. indices.push_back(static_cast<uint16_t>(firstVertOfThisRing + nextSection));
  369. // line around section
  370. int currentVertexIndex = firstVertOfThisRing + section;
  371. // max 0 will implicitly handle the top pole
  372. int previousVertexIndex = AZStd::max(currentVertexIndex - (int)numSections, 0);
  373. indices.push_back(static_cast<uint16_t>(currentVertexIndex));
  374. indices.push_back(static_cast<uint16_t>(previousVertexIndex));
  375. }
  376. }
  377. if (sphereShapeType == ShapeType_Sphere)
  378. {
  379. // build faces for bottom pole (to connect "inner" vertices with poles)
  380. uint16_t lastPoleVert = static_cast<uint16_t>((numRings - 1) * numSections + 1);
  381. uint16_t firstVertOfLastRing = static_cast<uint16_t>(1 + (numRings - 2) * numSections);
  382. for (uint16_t section = 0; section < numSections; ++section)
  383. {
  384. indices.push_back(firstVertOfLastRing + section);
  385. indices.push_back(lastPoleVert);
  386. }
  387. }
  388. }
  389. // triangle indices
  390. {
  391. // NumTriangles = NumTrianglesAtPoles + NumQuads * 2
  392. // = (numSections * 2) + ((numRings - 2) * numSections * 2)
  393. // = (numSections * 2) * (numRings - 2 + 1)
  394. const uint32_t numTriangles = (numRings - 1) * numSections * 2;
  395. const uint32_t numTriangleIndices = numTriangles * 3;
  396. // build "inner" faces
  397. auto& indices = meshData.m_triangleIndices;
  398. indices.clear();
  399. indices.reserve(numTriangleIndices);
  400. for (uint32_t ring = 0; ring < numRings - numberOfPoles; ++ring)
  401. {
  402. uint32_t firstVertOfThisRing = 1 + ring * numSections;
  403. uint32_t firstVertOfNextRing = firstVertOfThisRing + numSections;
  404. for (uint32_t section = 0; section < numSections; ++section)
  405. {
  406. uint32_t nextSection = (section + 1) % numSections;
  407. indices.push_back(static_cast<uint16_t>(firstVertOfThisRing + section));
  408. indices.push_back(static_cast<uint16_t>(firstVertOfThisRing + nextSection));
  409. indices.push_back(static_cast<uint16_t>(firstVertOfNextRing + nextSection));
  410. indices.push_back(static_cast<uint16_t>(firstVertOfNextRing + nextSection));
  411. indices.push_back(static_cast<uint16_t>(firstVertOfNextRing + section));
  412. indices.push_back(static_cast<uint16_t>(firstVertOfThisRing + section));
  413. }
  414. }
  415. // build faces for end caps (to connect "inner" vertices with poles)
  416. uint32_t firstPoleVert = 0;
  417. uint32_t firstVertOfFirstRing = 1 + (0) * numSections;
  418. for (uint32_t section = 0; section < numSections; ++section)
  419. {
  420. uint32_t nextSection = (section + 1) % numSections;
  421. indices.push_back(static_cast<uint16_t>(firstVertOfFirstRing + nextSection));
  422. indices.push_back(static_cast<uint16_t>(firstVertOfFirstRing + section));
  423. indices.push_back(static_cast<uint16_t>(firstPoleVert));
  424. }
  425. if (sphereShapeType == ShapeType_Sphere)
  426. {
  427. uint32_t lastPoleVert = (numRings - 1) * numSections + 1;
  428. uint32_t firstVertOfLastRing = 1 + (numRings - 2) * numSections;
  429. for (uint32_t section = 0; section < numSections; ++section)
  430. {
  431. uint32_t nextSection = (section + 1) % numSections;
  432. indices.push_back(static_cast<uint16_t>(firstVertOfLastRing + section));
  433. indices.push_back(static_cast<uint16_t>(firstVertOfLastRing + nextSection));
  434. indices.push_back(static_cast<uint16_t>(lastPoleVert));
  435. }
  436. }
  437. }
  438. }
  439. bool FixedShapeProcessor::CreateQuadBuffersAndViews()
  440. {
  441. auto& m_shape = m_shapes[ShapeType_Quad];
  442. m_shape.m_numLods = 1;
  443. MeshData meshData;
  444. CreateQuadMeshData(meshData, Facing::Both);
  445. ObjectBuffers objectBuffers;
  446. if (!CreateBuffersAndViews(objectBuffers, meshData))
  447. {
  448. m_shape.m_numLods = 0;
  449. return false;
  450. }
  451. m_shape.m_lodBuffers.emplace_back(objectBuffers);
  452. m_shape.m_lodScreenPercentages.push_back(0.0f);
  453. return true;
  454. }
  455. void FixedShapeProcessor::CreateQuadMeshDataSide(MeshData& meshData, bool isUp, bool drawLines)
  456. {
  457. uint16_t startPos = aznumeric_cast<uint16_t>(meshData.m_positions.size());
  458. // Positions
  459. meshData.m_positions.push_back(AuxGeomPosition(-0.5f, 0.0f, 0.5f));
  460. meshData.m_positions.push_back(AuxGeomPosition( 0.5f, 0.0f, 0.5f));
  461. meshData.m_positions.push_back(AuxGeomPosition(-0.5f, 0.0f, -0.5f));
  462. meshData.m_positions.push_back(AuxGeomPosition( 0.5f, 0.0f, -0.5f));
  463. // Normals
  464. AuxGeomNormal normal(0.0f, isUp ? 1.0f : -1.0f, 0.0f);
  465. meshData.m_normals.insert(meshData.m_normals.end(), { normal, normal, normal, normal });
  466. // Triangles
  467. if (isUp)
  468. {
  469. meshData.m_triangleIndices.insert(meshData.m_triangleIndices.end(), { 1, 2, 0, 3, 2, 1 });
  470. }
  471. else
  472. {
  473. meshData.m_triangleIndices.insert(meshData.m_triangleIndices.end(), { 0, 2, 1, 1, 2, 3 });
  474. }
  475. // Update indices based on starting position of vertex.
  476. for (size_t index = meshData.m_triangleIndices.size(); index < meshData.m_triangleIndices.size(); ++index)
  477. {
  478. meshData.m_triangleIndices.at(index) += startPos;
  479. }
  480. // Lines
  481. if (drawLines)
  482. {
  483. meshData.m_lineIndices.insert(meshData.m_lineIndices.end(), { 0, 1, 1, 2, 2, 3, 3, 0 });
  484. meshData.m_pointIndices.insert(meshData.m_pointIndices.end(), { 0, 1, 2, 3 });
  485. }
  486. }
  487. void FixedShapeProcessor::CreateQuadMeshData(MeshData& meshData, Facing facing)
  488. {
  489. if (facing == Facing::Up || facing == Facing::Both)
  490. {
  491. const bool isUp = true;
  492. const bool drawLines = true;
  493. CreateQuadMeshDataSide(meshData, isUp, drawLines);
  494. }
  495. if (facing == Facing::Down || facing == Facing::Both)
  496. {
  497. const bool isUp = false;
  498. const bool drawLines = facing != Facing::Both;
  499. CreateQuadMeshDataSide(meshData, isUp, drawLines);
  500. }
  501. }
  502. bool FixedShapeProcessor::CreateDiskBuffersAndViews()
  503. {
  504. const uint32_t numDiskLods = 5;
  505. struct LodInfo
  506. {
  507. uint32_t numSections;
  508. float screenPercentage;
  509. };
  510. const AZStd::array<LodInfo, numDiskLods> lodInfo =
  511. {{
  512. {38, 0.1000f},
  513. {22, 0.0100f},
  514. {14, 0.0010f},
  515. {10, 0.0001f},
  516. { 8, 0.0000f}
  517. }};
  518. auto& m_shape = m_shapes[ShapeType_Disk];
  519. m_shape.m_numLods = numDiskLods;
  520. for (uint32_t lodIndex = 0; lodIndex < numDiskLods; ++lodIndex)
  521. {
  522. MeshData meshData;
  523. CreateDiskMeshData(meshData, lodInfo[lodIndex].numSections, Facing::Both);
  524. ObjectBuffers objectBuffers;
  525. if (!CreateBuffersAndViews(objectBuffers, meshData))
  526. {
  527. m_shape.m_numLods = 0;
  528. return false;
  529. }
  530. m_shape.m_lodBuffers.emplace_back(objectBuffers);
  531. m_shape.m_lodScreenPercentages.push_back(lodInfo[lodIndex].screenPercentage);
  532. }
  533. return true;
  534. }
  535. void FixedShapeProcessor::CreateDiskMeshDataSide(MeshData& meshData, uint32_t numSections, bool isUp, float yPosition)
  536. {
  537. AuxGeomNormal normal(0.0f, isUp ? 1.0f : -1.0f, 0.0f);
  538. // Create center position
  539. uint16_t centerIndex = aznumeric_cast<uint16_t>(meshData.m_positions.size());
  540. uint16_t firstSection = centerIndex + 1;
  541. meshData.m_positions.push_back(AuxGeomPosition(0.0f, yPosition, 0.0f));
  542. meshData.m_normals.push_back(normal);
  543. // Create ring around it
  544. const float radius = 1.0f;
  545. float sectionAngle(DegToRad(360.0f / (float)numSections));
  546. for (uint32_t section = 0; section < numSections; ++section)
  547. {
  548. meshData.m_positions.push_back(AuxGeomPosition(radius * cosf(section * sectionAngle), yPosition, radius * sinf(section * sectionAngle)));
  549. meshData.m_normals.push_back(normal);
  550. }
  551. // Create point indices
  552. for (uint16_t index = 0; index < aznumeric_cast<uint16_t>(meshData.m_positions.size()); ++index)
  553. {
  554. meshData.m_pointIndices.push_back(index);
  555. }
  556. // Create line indices
  557. for (uint32_t section = 0; section < numSections; ++section)
  558. {
  559. // Line from center of disk to outer edge
  560. meshData.m_lineIndices.push_back(centerIndex);
  561. meshData.m_lineIndices.push_back(static_cast<uint16_t>(firstSection + section));
  562. // Line from outer edge to next edge
  563. meshData.m_lineIndices.push_back(static_cast<uint16_t>(firstSection + section));
  564. uint32_t nextSection = (section + 1) % numSections;
  565. meshData.m_lineIndices.push_back(static_cast<uint16_t>(firstSection + nextSection));
  566. }
  567. // Create triangle indices
  568. for (uint32_t section = 0; section < numSections; ++section)
  569. {
  570. uint32_t nextSection = (section + 1) % numSections;
  571. meshData.m_triangleIndices.push_back(centerIndex);
  572. if (isUp)
  573. {
  574. meshData.m_triangleIndices.push_back(static_cast<uint16_t>(firstSection + nextSection));
  575. meshData.m_triangleIndices.push_back(static_cast<uint16_t>(firstSection + section));
  576. }
  577. else
  578. {
  579. meshData.m_triangleIndices.push_back(static_cast<uint16_t>(firstSection + section));
  580. meshData.m_triangleIndices.push_back(static_cast<uint16_t>(firstSection + nextSection));
  581. }
  582. }
  583. }
  584. void FixedShapeProcessor::CreateDiskMeshData(MeshData& meshData, uint32_t numSections, Facing facing, float yPosition)
  585. {
  586. if (facing == Facing::Up || facing == Facing::Both)
  587. {
  588. CreateDiskMeshDataSide(meshData, numSections, true, yPosition);
  589. }
  590. if (facing == Facing::Down || facing == Facing::Both)
  591. {
  592. CreateDiskMeshDataSide(meshData, numSections, false, yPosition);
  593. }
  594. }
  595. bool FixedShapeProcessor::CreateConeBuffersAndViews()
  596. {
  597. const uint32_t numConeLods = 5;
  598. struct LodInfo
  599. {
  600. uint32_t numRings;
  601. uint32_t numSections;
  602. float screenPercentage;
  603. };
  604. const AZStd::array<LodInfo, numConeLods> lodInfo =
  605. {{
  606. { 16, 38, 0.1000f},
  607. { 8, 22, 0.0100f},
  608. { 4, 14, 0.0010f},
  609. { 2, 10, 0.0001f},
  610. { 1, 8, 0.0000f}
  611. }};
  612. auto& m_shape = m_shapes[ShapeType_Cone];
  613. m_shape.m_numLods = numConeLods;
  614. for (uint32_t lodIndex = 0; lodIndex < numConeLods; ++lodIndex)
  615. {
  616. MeshData meshData;
  617. CreateConeMeshData(meshData, lodInfo[lodIndex].numRings, lodInfo[lodIndex].numSections);
  618. ObjectBuffers objectBuffers;
  619. if (!CreateBuffersAndViews(objectBuffers, meshData))
  620. {
  621. m_shape.m_numLods = 0;
  622. return false;
  623. }
  624. m_shape.m_lodBuffers.emplace_back(objectBuffers);
  625. m_shape.m_lodScreenPercentages.push_back(lodInfo[lodIndex].screenPercentage);
  626. }
  627. return true;
  628. }
  629. void FixedShapeProcessor::CreateConeMeshData(MeshData& meshData, uint32_t numRings, uint32_t numSections)
  630. {
  631. AZ_Assert(numRings >= 1, "CreateConeMeshData: at least one ring is required");
  632. // Because we support DrawStyle::Shaded we need normals. Creating normals for a cone that shade
  633. // smoothly is actually not trival. One option is to create one vertex for the point with the normal
  634. // point along the Y axis. This doesn't give good shading anywhere except by the bottom cap.
  635. // That is what we do when numRings is one.
  636. // One approach is to create a ring of coincident verts at the point with the correct normals. But
  637. // that would give non-smooth shading.
  638. // So we sub-divide the cone into rings, the first subdivision being halfway between the base and the point.
  639. const float radius = 1.0f;
  640. const float height = 1.0f;
  641. // calc required number of vertices to build a cone for the given parameters
  642. uint32_t numVertices = numRings * numSections + numSections + 2;
  643. // setup buffers
  644. auto& positions = meshData.m_positions;
  645. positions.clear();
  646. positions.reserve(numVertices);
  647. auto& normals = meshData.m_normals;
  648. normals.clear();
  649. normals.reserve(numVertices);
  650. // Create bottom cap with normal facing down
  651. CreateDiskMeshData(meshData, numSections, Facing::Down);
  652. // Create vertices for the sides, the sides never quite reach the point. There is a single point vertex for that
  653. float sectionAngle(DegToRad(360.0f / (float)numSections));
  654. Vector3 conePoint(0.0f, height, 0.0f);
  655. for (uint32_t section = 0; section < numSections; ++section)
  656. {
  657. Vector3 pointOnCapEdge(radius * cosf(section * sectionAngle), 0.0f, radius * sinf(section * sectionAngle));
  658. Vector3 vecAlongConeSide(conePoint - pointOnCapEdge);
  659. Vector3 vecAlongCapEdge = pointOnCapEdge.Cross(vecAlongConeSide);
  660. Vector3 normal = vecAlongConeSide.Cross(vecAlongCapEdge).GetNormalized();
  661. float ringDistance = 0.0f;
  662. float ringSpacing = height * 0.5f;
  663. for (uint32_t ring = 0; ring < numRings; ++ring)
  664. {
  665. Vector3 pointOnRing = pointOnCapEdge + vecAlongConeSide * ringDistance;
  666. positions.push_back(pointOnRing);
  667. normals.push_back(normal);
  668. ringDistance += ringSpacing;
  669. ringSpacing *= 0.5f;
  670. }
  671. }
  672. // cone point vertex
  673. positions.push_back(conePoint);
  674. normals.push_back(AuxGeomNormal(0.0f, 1.0f, 0.0f));
  675. // vertex indexes for start of the cone sides and for the cone point
  676. uint16_t indexOfSidesStart = static_cast<uint16_t>(numSections + 1);
  677. uint32_t indexOfConePoint = indexOfSidesStart + numRings * numSections;
  678. // indices for points
  679. {
  680. auto& indices = meshData.m_pointIndices;
  681. for (uint16_t index = 0; index < aznumeric_cast<uint16_t>(meshData.m_positions.size()); ++index)
  682. {
  683. indices.push_back(index);
  684. }
  685. }
  686. // indices for lines (we ignore the rings beyond the first (at base) when drawing lines)
  687. {
  688. auto& indices = meshData.m_lineIndices;
  689. // build lines between already completed cap for each section
  690. for (uint16_t section = 0; section < numSections; ++section)
  691. {
  692. indices.push_back(static_cast<uint16_t>(indexOfSidesStart + numRings * section));
  693. indices.push_back(static_cast<uint16_t>(indexOfConePoint));
  694. }
  695. }
  696. // indices for triangles
  697. {
  698. auto& indices = meshData.m_triangleIndices;
  699. // build faces
  700. for (uint16_t section = 0; section < numSections; ++section)
  701. {
  702. uint16_t nextSection = (section + 1) % numSections;
  703. // faces from end cap to close to point
  704. for (uint32_t ring = 0; ring < numRings - 1; ++ring)
  705. {
  706. indices.push_back(static_cast<uint16_t>(indexOfSidesStart + numRings * nextSection + ring + 1));
  707. indices.push_back(static_cast<uint16_t>(indexOfSidesStart + numRings * nextSection + ring));
  708. indices.push_back(static_cast<uint16_t>(indexOfSidesStart + numRings * section + ring));
  709. indices.push_back(static_cast<uint16_t>(indexOfSidesStart + numRings * section + ring));
  710. indices.push_back(static_cast<uint16_t>(indexOfSidesStart + numRings * section + ring + 1));
  711. indices.push_back(static_cast<uint16_t>(indexOfSidesStart + numRings * nextSection + ring + 1));
  712. }
  713. // faces for point (from last ring of verts to point)
  714. indices.push_back(static_cast<uint16_t>(indexOfConePoint));
  715. indices.push_back(static_cast<uint16_t>(indexOfSidesStart + numRings * nextSection + numRings - 1));
  716. indices.push_back(static_cast<uint16_t>(indexOfSidesStart + numRings * section + numRings - 1));
  717. }
  718. }
  719. }
  720. bool FixedShapeProcessor::CreateCylinderBuffersAndViews(AuxGeomShapeType cylinderShapeType)
  721. {
  722. AZ_Assert(cylinderShapeType == ShapeType_Cylinder || cylinderShapeType == ShapeType_CylinderNoEnds,
  723. "Trying to create cylinder buffers and views with a non-cylinder shape type!");
  724. const uint32_t numCylinderLods = 5;
  725. struct LodInfo
  726. {
  727. uint32_t numSections;
  728. float screenPercentage;
  729. };
  730. const AZStd::array<LodInfo, numCylinderLods> lodInfo =
  731. { {
  732. { 38, 0.1000f},
  733. { 22, 0.0100f},
  734. { 14, 0.0010f},
  735. { 10, 0.0001f},
  736. { 8, 0.0000f}
  737. } };
  738. auto& m_shape = m_shapes[cylinderShapeType];
  739. m_shape.m_numLods = numCylinderLods;
  740. for (uint32_t lodIndex = 0; lodIndex < numCylinderLods; ++lodIndex)
  741. {
  742. MeshData meshData;
  743. CreateCylinderMeshData(meshData, lodInfo[lodIndex].numSections, cylinderShapeType);
  744. ObjectBuffers objectBuffers;
  745. if (!CreateBuffersAndViews(objectBuffers, meshData))
  746. {
  747. m_shape.m_numLods = 0;
  748. return false;
  749. }
  750. m_shape.m_lodBuffers.emplace_back(objectBuffers);
  751. m_shape.m_lodScreenPercentages.push_back(lodInfo[lodIndex].screenPercentage);
  752. }
  753. return true;
  754. }
  755. void FixedShapeProcessor::CreateCylinderMeshData(MeshData& meshData, uint32_t numSections, AuxGeomShapeType cylinderShapeType)
  756. {
  757. const float radius = 1.0f;
  758. const float height = 1.0f;
  759. //uint16_t indexOfBottomCenter = 0;
  760. //uint16_t indexOfBottomStart = 1;
  761. //uint16_t indexOfTopCenter = numSections + 1;
  762. //uint16_t indexOfTopStart = numSections + 2;
  763. uint16_t indexOfSidesStart = static_cast<uint16_t>(2 * numSections + 2);
  764. if (cylinderShapeType == ShapeType_CylinderNoEnds)
  765. {
  766. // We won't draw disks at the ends of the cylinder, so no need to offset side indices
  767. indexOfSidesStart = 0;
  768. }
  769. // calc required number of vertices to build a cylinder for the given parameters
  770. uint32_t numVertices = indexOfSidesStart + 2 * numSections;
  771. // setup buffers
  772. auto& positions = meshData.m_positions;
  773. positions.clear();
  774. positions.reserve(numVertices);
  775. auto& normals = meshData.m_normals;
  776. normals.clear();
  777. normals.reserve(numVertices);
  778. float bottomHeight = -height * 0.5f;
  779. float topHeight = height * 0.5f;
  780. // Create caps
  781. if (cylinderShapeType == ShapeType_Cylinder)
  782. {
  783. CreateDiskMeshData(meshData, numSections, Facing::Down, bottomHeight);
  784. CreateDiskMeshData(meshData, numSections, Facing::Up, topHeight);
  785. }
  786. // create vertices for side (so normal points out correctly)
  787. float sectionAngle(DegToRad(360.0f / (float)numSections));
  788. for (uint32_t section = 0; section < numSections; ++section)
  789. {
  790. Vector3 bottom(radius * cosf(section * sectionAngle), bottomHeight, radius * sinf(section * sectionAngle));
  791. Vector3 top = bottom + Vector3(0.0f, height, 0.0f);
  792. Vector3 normal = bottom.GetNormalized();
  793. positions.push_back(bottom);
  794. normals.push_back(normal);
  795. positions.push_back(top);
  796. normals.push_back(normal);
  797. }
  798. // build point indices
  799. {
  800. auto& indices = meshData.m_pointIndices;
  801. for (uint16_t index = 0; index < aznumeric_cast<uint16_t>(positions.size()); ++index)
  802. {
  803. indices.push_back(index);
  804. }
  805. }
  806. // build lines for each section between the already created caps
  807. {
  808. auto& indices = meshData.m_lineIndices;
  809. for (uint16_t section = 0; section < numSections; ++section)
  810. {
  811. // line between the caps
  812. indices.push_back(indexOfSidesStart + 2 * section);
  813. indices.push_back(indexOfSidesStart + 2 * section + 1);
  814. }
  815. // If we're not drawing the disks at the ends of the cylinder, we still want to
  816. // draw a ring around the end to join the tips of lines we created just above
  817. if (cylinderShapeType == ShapeType_CylinderNoEnds)
  818. {
  819. for (uint16_t section = 0; section < numSections; ++section)
  820. {
  821. uint16_t nextSection = (section + 1) % numSections;
  822. // line around the bottom cap
  823. indices.push_back(section * 2);
  824. indices.push_back(nextSection * 2);
  825. // line around the top cap
  826. indices.push_back(section * 2 + 1);
  827. indices.push_back(nextSection * 2 + 1);
  828. }
  829. }
  830. }
  831. // indices for triangles
  832. {
  833. auto& indices = meshData.m_triangleIndices;
  834. // build faces for end cap
  835. for (uint16_t section = 0; section < numSections; ++section)
  836. {
  837. uint16_t nextSection = (section + 1) % numSections;
  838. // face from end cap to point
  839. indices.push_back(indexOfSidesStart + 2 * nextSection + 1);
  840. indices.push_back(indexOfSidesStart + 2 * nextSection);
  841. indices.push_back(indexOfSidesStart + 2 * section);
  842. indices.push_back(indexOfSidesStart + 2 * section);
  843. indices.push_back(indexOfSidesStart + 2 * section + 1);
  844. indices.push_back(indexOfSidesStart + 2 * nextSection + 1);
  845. }
  846. }
  847. }
  848. bool FixedShapeProcessor::CreateBoxBuffersAndViews()
  849. {
  850. MeshData meshData;
  851. CreateBoxMeshData(meshData);
  852. if (!CreateBuffersAndViews(m_boxBuffers, meshData))
  853. {
  854. return false;
  855. }
  856. return true;
  857. }
  858. void FixedShapeProcessor::CreateBoxMeshData(MeshData& meshData)
  859. {
  860. // calc required number of vertices/indices/triangles to build a sphere for the given parameters
  861. const uint32_t numVertices = 24;
  862. const uint32_t numTriangles = 12;
  863. const uint32_t numEdges = 12;
  864. const uint32_t numTriangleIndices = numTriangles * 3;
  865. const uint32_t numLineIndices = numEdges * 2;
  866. // setup vertex buffer
  867. auto& positions = meshData.m_positions;
  868. positions.clear();
  869. positions.reserve(numVertices);
  870. auto& normals = meshData.m_normals;
  871. normals.clear();
  872. normals.reserve(numVertices);
  873. using PosType = AuxGeomPosition;
  874. using NormalType = AuxGeomNormal;
  875. const uint32_t numVertsPerFace = 4;
  876. // Front face verts (looking along negative z-axis)
  877. positions.push_back(PosType(-0.5f, -0.5f, 0.5f));
  878. positions.push_back(PosType( 0.5f, -0.5f, 0.5f));
  879. positions.push_back(PosType( 0.5f, 0.5f, 0.5f));
  880. positions.push_back(PosType(-0.5f, 0.5f, 0.5f));
  881. for (uint32_t vertex = 0; vertex < numVertsPerFace; ++vertex)
  882. {
  883. normals.push_back(NormalType(0.0, 0.0f, 1.0f));
  884. }
  885. // Back Face verts
  886. positions.push_back(PosType(-0.5f, -0.5f, -0.5f));
  887. positions.push_back(PosType( 0.5f, -0.5f, -0.5f));
  888. positions.push_back(PosType( 0.5f, 0.5f, -0.5f));
  889. positions.push_back(PosType(-0.5f, 0.5f, -0.5f));
  890. for (uint32_t vertex = 0; vertex < numVertsPerFace; ++vertex)
  891. {
  892. normals.push_back(NormalType(0.0, 0.0f, -1.0f));
  893. }
  894. // Left Face verts
  895. positions.push_back(PosType(-0.5f, -0.5f, 0.5f));
  896. positions.push_back(PosType(-0.5f, 0.5f, 0.5f));
  897. positions.push_back(PosType(-0.5f, 0.5f, -0.5f));
  898. positions.push_back(PosType(-0.5f, -0.5f, -0.5f));
  899. for (uint32_t vertex = 0; vertex < numVertsPerFace; ++vertex)
  900. {
  901. normals.push_back(NormalType(-1.0, 0.0f, 0.0f));
  902. }
  903. // Right Face verts
  904. positions.push_back(PosType(0.5f, -0.5f, 0.5f));
  905. positions.push_back(PosType(0.5f, 0.5f, 0.5f));
  906. positions.push_back(PosType(0.5f, 0.5f, -0.5f));
  907. positions.push_back(PosType(0.5f, -0.5f, -0.5f));
  908. for (uint32_t vertex = 0; vertex < numVertsPerFace; ++vertex)
  909. {
  910. normals.push_back(NormalType(1.0, 0.0f, 0.0f));
  911. }
  912. // Bottom Face verts
  913. positions.push_back(PosType(-0.5f, -0.5f, 0.5f));
  914. positions.push_back(PosType( 0.5f, -0.5f, 0.5f));
  915. positions.push_back(PosType( 0.5f, -0.5f, -0.5f));
  916. positions.push_back(PosType(-0.5f, -0.5f, -0.5f));
  917. for (uint32_t vertex = 0; vertex < numVertsPerFace; ++vertex)
  918. {
  919. normals.push_back(NormalType(0.0, -1.0f, 0.0f));
  920. }
  921. // Top Face verts
  922. positions.push_back(PosType(-0.5f, 0.5f, 0.5f));
  923. positions.push_back(PosType( 0.5f, 0.5f, 0.5f));
  924. positions.push_back(PosType( 0.5f, 0.5f, -0.5f));
  925. positions.push_back(PosType(-0.5f, 0.5f, -0.5f));
  926. for (uint32_t vertex = 0; vertex < numVertsPerFace; ++vertex)
  927. {
  928. normals.push_back(NormalType(0.0, 1.0f, 0.0f));
  929. }
  930. // Setup point index buffer
  931. {
  932. auto& indices = meshData.m_pointIndices;
  933. indices.clear();
  934. indices.reserve(8);
  935. // indices - front face points
  936. indices.push_back(0);
  937. indices.push_back(1);
  938. indices.push_back(2);
  939. indices.push_back(3);
  940. // indices - back face points
  941. indices.push_back(4);
  942. indices.push_back(5);
  943. indices.push_back(6);
  944. indices.push_back(7);
  945. }
  946. // Setup line index buffer
  947. {
  948. auto& indices = meshData.m_lineIndices;
  949. indices.clear();
  950. indices.reserve(numLineIndices);
  951. // indices - front face edges
  952. indices.push_back(0);
  953. indices.push_back(1);
  954. indices.push_back(1);
  955. indices.push_back(2);
  956. indices.push_back(2);
  957. indices.push_back(3);
  958. indices.push_back(3);
  959. indices.push_back(0);
  960. // indices - back face edges
  961. indices.push_back(4);
  962. indices.push_back(5);
  963. indices.push_back(5);
  964. indices.push_back(6);
  965. indices.push_back(6);
  966. indices.push_back(7);
  967. indices.push_back(7);
  968. indices.push_back(4);
  969. // indices - side edges
  970. indices.push_back(0);
  971. indices.push_back(4);
  972. indices.push_back(1);
  973. indices.push_back(5);
  974. indices.push_back(2);
  975. indices.push_back(6);
  976. indices.push_back(3);
  977. indices.push_back(7);
  978. }
  979. // Setup triangle index buffer
  980. {
  981. auto& indices = meshData.m_triangleIndices;
  982. indices.clear();
  983. indices.reserve(numTriangleIndices);
  984. // indices - front face
  985. indices.push_back(0);
  986. indices.push_back(1);
  987. indices.push_back(2);
  988. indices.push_back(2);
  989. indices.push_back(3);
  990. indices.push_back(0);
  991. // indices - back face
  992. indices.push_back(5);
  993. indices.push_back(4);
  994. indices.push_back(7);
  995. indices.push_back(7);
  996. indices.push_back(6);
  997. indices.push_back(5);
  998. // indices - left face
  999. indices.push_back(8);
  1000. indices.push_back(9);
  1001. indices.push_back(10);
  1002. indices.push_back(10);
  1003. indices.push_back(11);
  1004. indices.push_back(8);
  1005. // indices - right face
  1006. indices.push_back(14);
  1007. indices.push_back(13);
  1008. indices.push_back(12);
  1009. indices.push_back(12);
  1010. indices.push_back(15);
  1011. indices.push_back(14);
  1012. // indices - bottom face
  1013. indices.push_back(18);
  1014. indices.push_back(17);
  1015. indices.push_back(16);
  1016. indices.push_back(16);
  1017. indices.push_back(19);
  1018. indices.push_back(18);
  1019. // indices - top face
  1020. indices.push_back(23);
  1021. indices.push_back(20);
  1022. indices.push_back(21);
  1023. indices.push_back(21);
  1024. indices.push_back(22);
  1025. indices.push_back(23);
  1026. }
  1027. }
  1028. bool FixedShapeProcessor::CreateBuffersAndViews(ObjectBuffers& objectBuffers, const MeshData& meshData)
  1029. {
  1030. AZ::RHI::ResultCode result = AZ::RHI::ResultCode::Fail;
  1031. AZ::RHI::BufferInitRequest request;
  1032. // setup m_pointIndexBuffer
  1033. objectBuffers.m_pointIndexBuffer = aznew RHI::Buffer;
  1034. const auto pointIndexDataSize = static_cast<uint32_t>(meshData.m_pointIndices.size() * sizeof(uint16_t));
  1035. request.m_buffer = objectBuffers.m_pointIndexBuffer.get();
  1036. request.m_descriptor = AZ::RHI::BufferDescriptor{ AZ::RHI::BufferBindFlags::InputAssembly, pointIndexDataSize };
  1037. request.m_initialData = meshData.m_pointIndices.data();
  1038. result = m_bufferPool->InitBuffer(request);
  1039. if (result != AZ::RHI::ResultCode::Success)
  1040. {
  1041. AZ_Error( "FixedShapeProcessor", false, "Failed to initialize shape index buffer with error code: %d", result);
  1042. return false;
  1043. }
  1044. // setup m_lineIndexBuffer
  1045. objectBuffers.m_lineIndexBuffer = aznew RHI::Buffer;
  1046. const auto lineIndexDataSize = static_cast<uint32_t>(meshData.m_lineIndices.size() * sizeof(uint16_t));
  1047. request.m_buffer = objectBuffers.m_lineIndexBuffer.get();
  1048. request.m_descriptor = AZ::RHI::BufferDescriptor{ AZ::RHI::BufferBindFlags::InputAssembly, lineIndexDataSize };
  1049. request.m_initialData = meshData.m_lineIndices.data();
  1050. result = m_bufferPool->InitBuffer(request);
  1051. if (result != AZ::RHI::ResultCode::Success)
  1052. {
  1053. AZ_Error("FixedShapeProcessor", false, "Failed to initialize shape index buffer with error code: %d", result);
  1054. return false;
  1055. }
  1056. // setup m_triangleIndexBuffer
  1057. objectBuffers.m_triangleIndexBuffer = aznew RHI::Buffer;
  1058. const auto triangleIndexDataSize = static_cast<uint32_t>(meshData.m_triangleIndices.size() * sizeof(uint16_t));
  1059. request.m_buffer = objectBuffers.m_triangleIndexBuffer.get();
  1060. request.m_descriptor = AZ::RHI::BufferDescriptor{ AZ::RHI::BufferBindFlags::InputAssembly, triangleIndexDataSize };
  1061. request.m_initialData = meshData.m_triangleIndices.data();
  1062. result = m_bufferPool->InitBuffer(request);
  1063. if (result != AZ::RHI::ResultCode::Success)
  1064. {
  1065. AZ_Error("FixedShapeProcessor", false, "Failed to initialize shape index buffer with error code: %d", result);
  1066. return false;
  1067. }
  1068. // setup m_positionBuffer
  1069. objectBuffers.m_positionBuffer = aznew RHI::Buffer;
  1070. const auto positionDataSize = static_cast<uint32_t>(meshData.m_positions.size() * sizeof(AuxGeomPosition));
  1071. request.m_buffer = objectBuffers.m_positionBuffer.get();
  1072. request.m_descriptor = AZ::RHI::BufferDescriptor{ AZ::RHI::BufferBindFlags::InputAssembly, positionDataSize };
  1073. request.m_initialData = meshData.m_positions.data();
  1074. result = m_bufferPool->InitBuffer(request);
  1075. if (result != AZ::RHI::ResultCode::Success)
  1076. {
  1077. AZ_Error("FixedShapeProcessor", false, "Failed to initialize shape position buffer with error code: %d", result);
  1078. return false;
  1079. }
  1080. // setup m_normalBuffer
  1081. objectBuffers.m_normalBuffer = aznew RHI::Buffer;
  1082. const auto normalDataSize = static_cast<uint32_t>(meshData.m_normals.size() * sizeof(AuxGeomNormal));
  1083. request.m_buffer = objectBuffers.m_normalBuffer.get();
  1084. request.m_descriptor = AZ::RHI::BufferDescriptor{ AZ::RHI::BufferBindFlags::InputAssembly, normalDataSize };
  1085. request.m_initialData = meshData.m_normals.data();
  1086. result = m_bufferPool->InitBuffer(request);
  1087. if (result != AZ::RHI::ResultCode::Success)
  1088. {
  1089. AZ_Error("FixedShapeProcessor", false, "Failed to initialize shape normal buffer with error code: %d", result);
  1090. return false;
  1091. }
  1092. // Setup point index buffer view
  1093. u32 pointIndexCount = static_cast<uint32_t>(meshData.m_pointIndices.size());
  1094. objectBuffers.m_pointGeometryView.SetDrawArguments(RHI::DrawIndexed{ 0, pointIndexCount, 0 });
  1095. objectBuffers.m_pointGeometryView.SetIndexBufferView(
  1096. {
  1097. *objectBuffers.m_pointIndexBuffer,
  1098. 0,
  1099. static_cast<uint32_t>(pointIndexCount * sizeof(uint16_t)),
  1100. AZ::RHI::IndexFormat::Uint16,
  1101. });
  1102. // Setup line index buffer view
  1103. u32 lineIndexCount = static_cast<uint32_t>(meshData.m_lineIndices.size());
  1104. objectBuffers.m_lineGeometryView.SetDrawArguments(RHI::DrawIndexed{ 0, lineIndexCount, 0 });
  1105. objectBuffers.m_lineGeometryView.SetIndexBufferView(
  1106. {
  1107. *objectBuffers.m_lineIndexBuffer,
  1108. 0,
  1109. static_cast<uint32_t>(lineIndexCount * sizeof(uint16_t)),
  1110. AZ::RHI::IndexFormat::Uint16,
  1111. });
  1112. // Setup triangle index buffer view
  1113. u32 triangleIndexCount = static_cast<uint32_t>(meshData.m_triangleIndices.size());
  1114. objectBuffers.m_triangleGeometryView.SetDrawArguments(RHI::DrawIndexed{ 0, triangleIndexCount, 0 });
  1115. objectBuffers.m_triangleGeometryView.SetIndexBufferView(
  1116. {
  1117. *objectBuffers.m_triangleIndexBuffer,
  1118. 0,
  1119. static_cast<uint32_t>(triangleIndexCount * sizeof(uint16_t)),
  1120. AZ::RHI::IndexFormat::Uint16,
  1121. });
  1122. // Setup vertex buffer view
  1123. const auto positionCount = static_cast<uint32_t>(meshData.m_positions.size());
  1124. const uint32_t positionSize = sizeof(float) * 3;
  1125. AZ::RHI::StreamBufferView positionBufferView =
  1126. {
  1127. *objectBuffers.m_positionBuffer,
  1128. 0,
  1129. positionCount * positionSize,
  1130. positionSize,
  1131. };
  1132. // Setup normal buffer view
  1133. const auto normalCount = static_cast<uint32_t>(meshData.m_normals.size());
  1134. const uint32_t normalSize = sizeof(float) * 3;
  1135. AZ::RHI::StreamBufferView normalBufferView =
  1136. {
  1137. *objectBuffers.m_normalBuffer,
  1138. 0,
  1139. normalCount * normalSize,
  1140. normalSize,
  1141. };
  1142. objectBuffers.m_pointGeometryView.AddStreamBufferView(positionBufferView);
  1143. objectBuffers.m_lineGeometryView.AddStreamBufferView(positionBufferView);
  1144. objectBuffers.m_triangleGeometryView.AddStreamBufferView(positionBufferView);
  1145. objectBuffers.m_triangleGeometryView.AddStreamBufferView(normalBufferView);
  1146. RHI::StreamBufferIndices streamIndices;
  1147. streamIndices.AddIndex(PositionStreamIndex);
  1148. // Validate for each draw style
  1149. AZ::RHI::ValidateStreamBufferViews(m_objectStreamLayout[DrawStyle_Point], objectBuffers.m_pointGeometryView, streamIndices);
  1150. AZ::RHI::ValidateStreamBufferViews(m_objectStreamLayout[DrawStyle_Line], objectBuffers.m_lineGeometryView, streamIndices);
  1151. AZ::RHI::ValidateStreamBufferViews(m_objectStreamLayout[DrawStyle_Solid], objectBuffers.m_triangleGeometryView, streamIndices);
  1152. streamIndices.AddIndex(NormalStreamIndex);
  1153. AZ::RHI::ValidateStreamBufferViews(m_objectStreamLayout[DrawStyle_Shaded], objectBuffers.m_triangleGeometryView, streamIndices);
  1154. return true;
  1155. }
  1156. FixedShapeProcessor::LodIndex FixedShapeProcessor::GetLodIndexForShape(AuxGeomShapeType shapeType, const AZ::RPI::View* view, const AZ::Vector3& worldPosition, const AZ::Vector3& scale)
  1157. {
  1158. const Shape& shape = m_shapes[shapeType];
  1159. if (shape.m_numLods <= 1)
  1160. {
  1161. return 0; // No LODs for this shape
  1162. }
  1163. // For LODs we really only care about the radius of the curve. i.e. a really long cylinder with a radius R
  1164. // and a short cylinder with radius R should use same LOD if same distance from screen since the LOD is just used
  1165. // to make the curved part look smoother. For all our curved geometries X and Z scale are the radius and Y scale is the length.
  1166. float radius = scale.GetX();
  1167. float screenPercentage = view->CalculateSphereAreaInClipSpace(worldPosition, radius);
  1168. LodIndex lodIndex = shape.m_numLods - 1;
  1169. // No need to test the last LOD since we always choose it if we get that far
  1170. // (unless at some point we implement a test to not draw at all if below that value - but
  1171. // that concern might be better addressed by frustum culling before this)
  1172. for (LodIndex testIndex = 0; testIndex < shape.m_numLods - 1; ++testIndex)
  1173. {
  1174. if (screenPercentage >= shape.m_lodScreenPercentages[testIndex])
  1175. {
  1176. lodIndex = testIndex;
  1177. break;
  1178. }
  1179. }
  1180. return lodIndex;
  1181. }
  1182. void FixedShapeProcessor::SetupInputStreamLayout(RHI::InputStreamLayout& inputStreamLayout, RHI::PrimitiveTopology topology, bool includeNormals)
  1183. {
  1184. RHI::InputStreamLayoutBuilder layoutBuilder;
  1185. layoutBuilder.AddBuffer()->Channel("POSITION", RHI::Format::R32G32B32_FLOAT);
  1186. if (includeNormals)
  1187. {
  1188. layoutBuilder.AddBuffer()->Channel("NORMAL", RHI::Format::R32G32B32_FLOAT);
  1189. }
  1190. layoutBuilder.SetTopology(topology);
  1191. inputStreamLayout = layoutBuilder.End();
  1192. }
  1193. void FixedShapeProcessor::FillShaderData(Data::Instance<RPI::Shader>& shader, ShaderData& shaderData)
  1194. {
  1195. // Get the per-object SRG and store the indices of the data we need to set per object
  1196. shaderData.m_shaderAsset = shader->GetAsset();
  1197. shaderData.m_supervariantIndex = shader->GetSupervariantIndex();
  1198. shaderData.m_perObjectSrgLayout = shader->FindShaderResourceGroupLayout(Name{ "ObjectSrg" });
  1199. if (!shaderData.m_perObjectSrgLayout)
  1200. {
  1201. AZ_Error("FixedShapeProcessor", false, "Failed to get shader resource group layout");
  1202. return;
  1203. }
  1204. shaderData.m_drawListTag = shader->GetDrawListTag();
  1205. }
  1206. void FixedShapeProcessor::LoadShaders()
  1207. {
  1208. // load shaders for constant color and direction light
  1209. constexpr const char* unlitObjectShaderFilePath = "Shaders/auxgeom/auxgeomobject.azshader";
  1210. constexpr const char* litObjectShaderFilePath = "Shaders/auxgeom/auxgeomobjectlit.azshader";
  1211. // constant color shader
  1212. m_unlitShader = RPI::LoadCriticalShader(unlitObjectShaderFilePath);
  1213. // direction light shader
  1214. m_litShader = RPI::LoadCriticalShader(litObjectShaderFilePath);
  1215. if (m_unlitShader == nullptr || m_litShader == nullptr)
  1216. {
  1217. return;
  1218. }
  1219. FillShaderData(m_unlitShader, m_perObjectShaderData[ShapeLightingStyle_ConstantColor]);
  1220. FillShaderData(m_litShader, m_perObjectShaderData[ShapeLightingStyle_Directional]);
  1221. // Initialize all pipeline states
  1222. PipelineStateOptions pipelineStateOptions;
  1223. // initialize two base pipeline state first to preserve the blend functions
  1224. pipelineStateOptions.m_perpectiveType = PerspectiveType_ViewProjection;
  1225. InitPipelineState(pipelineStateOptions);
  1226. pipelineStateOptions.m_perpectiveType = PerspectiveType_ManualOverride;
  1227. InitPipelineState(pipelineStateOptions);
  1228. for (uint32_t perspectiveType = 0; perspectiveType < PerspectiveType_Count; perspectiveType++)
  1229. {
  1230. pipelineStateOptions.m_perpectiveType = (AuxGeomShapePerpectiveType)perspectiveType;
  1231. for (uint32_t blendMode = 0; blendMode < BlendMode_Count; blendMode++)
  1232. {
  1233. pipelineStateOptions.m_blendMode = (AuxGeomBlendMode)blendMode;
  1234. for (uint32_t drawStyle = 0; drawStyle < DrawStyle_Count; drawStyle++)
  1235. {
  1236. pipelineStateOptions.m_drawStyle = (AuxGeomDrawStyle)drawStyle;
  1237. for (uint32_t depthRead = 0; depthRead < DepthRead_Count; depthRead++)
  1238. {
  1239. pipelineStateOptions.m_depthReadType = (AuxGeomDepthReadType)depthRead;
  1240. for (uint32_t depthWrite = 0; depthWrite < DepthWrite_Count; depthWrite++)
  1241. {
  1242. pipelineStateOptions.m_depthWriteType = (AuxGeomDepthWriteType)depthWrite;
  1243. for (uint32_t faceCullMode = 0; faceCullMode < FaceCull_Count; faceCullMode++)
  1244. {
  1245. pipelineStateOptions.m_faceCullMode = (AuxGeomFaceCullMode)faceCullMode;
  1246. InitPipelineState(pipelineStateOptions);
  1247. }
  1248. }
  1249. }
  1250. }
  1251. }
  1252. }
  1253. }
  1254. RPI::Ptr<RPI::PipelineStateForDraw>& FixedShapeProcessor::GetPipelineState(const PipelineStateOptions& pipelineStateOptions)
  1255. {
  1256. // The declaration: m_pipelineStates[PerspectiveType_Count][BlendMode_Count][DrawStyle_Count][DepthRead_Count][DepthWrite_Count][FaceCull_Count];
  1257. return m_pipelineStates[pipelineStateOptions.m_perpectiveType][pipelineStateOptions.m_blendMode][pipelineStateOptions.m_drawStyle]
  1258. [pipelineStateOptions.m_depthReadType][pipelineStateOptions.m_depthWriteType][pipelineStateOptions.m_faceCullMode];
  1259. }
  1260. void FixedShapeProcessor::SetUpdatePipelineStates()
  1261. {
  1262. m_needUpdatePipelineStates = true;
  1263. }
  1264. void FixedShapeProcessor::InitPipelineState(const PipelineStateOptions& pipelineStateOptions)
  1265. {
  1266. // Use the the pipeline state for PipelineStateOptions with default values and input perspective type as base pipeline state. Create one if it was empty.
  1267. PipelineStateOptions defaultOptions;
  1268. defaultOptions.m_perpectiveType = pipelineStateOptions.m_perpectiveType;
  1269. defaultOptions.m_drawStyle = pipelineStateOptions.m_drawStyle;
  1270. RPI::Ptr<RPI::PipelineStateForDraw>& basePipelineState = GetPipelineState(defaultOptions);
  1271. if (basePipelineState.get() == nullptr)
  1272. {
  1273. // Only DrawStyle_Shaded uses the lit shader. Others use unlit shader
  1274. auto& shader = (pipelineStateOptions.m_drawStyle == DrawStyle_Shaded) ? m_litShader : m_unlitShader;
  1275. basePipelineState = aznew RPI::PipelineStateForDraw;
  1276. // shader option data for shader variant
  1277. Name optionViewProjectionModeName = Name("o_viewProjMode");
  1278. RPI::ShaderOptionList shaderOptionAndValues;
  1279. shaderOptionAndValues.push_back(RPI::ShaderOption(optionViewProjectionModeName, GetAuxGeomPerspectiveTypeName(pipelineStateOptions.m_perpectiveType)));
  1280. // initialize pipeline state with shader and shader options
  1281. basePipelineState->Init(shader, &shaderOptionAndValues);
  1282. m_createdPipelineStates.push_back(&basePipelineState);
  1283. }
  1284. RPI::Ptr<RPI::PipelineStateForDraw>& destPipelineState = GetPipelineState(pipelineStateOptions);
  1285. // Copy from base pipeline state. Skip if it's the base pipeline state
  1286. if (destPipelineState.get() == nullptr)
  1287. {
  1288. destPipelineState = aznew RPI::PipelineStateForDraw(*basePipelineState.get());
  1289. m_createdPipelineStates.push_back(&destPipelineState);
  1290. }
  1291. // blendMode
  1292. RHI::TargetBlendState& blendState = destPipelineState->RenderStatesOverlay().m_blendState.m_targets[0];
  1293. blendState.m_enable = pipelineStateOptions.m_blendMode == AuxGeomBlendMode::BlendMode_Alpha;
  1294. blendState.m_blendSource = RHI::BlendFactor::AlphaSource;
  1295. blendState.m_blendDest = RHI::BlendFactor::AlphaSourceInverse;
  1296. // primitiveType
  1297. destPipelineState->InputStreamLayout() = m_objectStreamLayout[pipelineStateOptions.m_drawStyle];
  1298. // depthReadType
  1299. // Keep the default depth comparison function and only set it when depth read is off
  1300. // Note: since the default PipelineStateOptions::m_depthReadType is DepthRead_On, the basePipelineState keeps the comparison function read from shader variant
  1301. if (pipelineStateOptions.m_depthReadType == AuxGeomDepthReadType::DepthRead_Off)
  1302. {
  1303. destPipelineState->RenderStatesOverlay().m_depthStencilState.m_depth.m_func = RHI::ComparisonFunc::Always;
  1304. }
  1305. // depthWriteType
  1306. destPipelineState->RenderStatesOverlay().m_depthStencilState.m_depth.m_writeMask =
  1307. ConvertToRHIDepthWriteMask(pipelineStateOptions.m_depthWriteType);
  1308. // faceCullMode
  1309. destPipelineState->RenderStatesOverlay().m_rasterState.m_cullMode =
  1310. ConvertToRHICullMode(pipelineStateOptions.m_faceCullMode);
  1311. // finalize
  1312. destPipelineState->SetOutputFromScene(m_scene);
  1313. destPipelineState->Finalize();
  1314. }
  1315. RHI::GeometryView* FixedShapeProcessor::GetGeometryView(ObjectBuffers& objectBuffers, int drawStyle)
  1316. {
  1317. switch (drawStyle)
  1318. {
  1319. case DrawStyle_Point:
  1320. return &objectBuffers.m_pointGeometryView;
  1321. case DrawStyle_Line:
  1322. return &objectBuffers.m_lineGeometryView;
  1323. case DrawStyle_Solid: // intentional fall through
  1324. case DrawStyle_Shaded:
  1325. return &objectBuffers.m_triangleGeometryView;
  1326. default:
  1327. AZ_Assert(false, "Unknown AuxGeom Draw Style %d.", drawStyle);
  1328. return &objectBuffers.m_triangleGeometryView; // default to triangle since it should be drawable for any draw style
  1329. }
  1330. }
  1331. RHI::GeometryView* FixedShapeProcessor::GetGeometryView(AuxGeomShapeType shapeType, int drawStyle, LodIndex lodIndex)
  1332. {
  1333. return GetGeometryView(m_shapes[shapeType].m_lodBuffers[lodIndex], drawStyle);
  1334. }
  1335. RHI::ConstPtr<RHI::DrawPacket> FixedShapeProcessor::BuildDrawPacketForShape(
  1336. RHI::DrawPacketBuilder& drawPacketBuilder,
  1337. const ShapeBufferEntry& shape,
  1338. int drawStyle,
  1339. const AZStd::vector<AZ::Matrix4x4>& viewProjOverrides,
  1340. const RPI::Ptr<RPI::PipelineStateForDraw>& pipelineState,
  1341. LodIndex lodIndex,
  1342. RHI::DrawItemSortKey sortKey)
  1343. {
  1344. ShaderData& shaderData = m_perObjectShaderData[drawStyle==DrawStyle_Shaded?1:0];
  1345. // Create a SRG for the shape to specify its transform and color
  1346. // [GFX TODO] [ATOM-2333] Try to avoid doing SRG create/compile per draw. Possibly using instancing.
  1347. auto srg = RPI::ShaderResourceGroup::Create(shaderData.m_shaderAsset, shaderData.m_supervariantIndex, shaderData.m_perObjectSrgLayout->GetName());
  1348. if (!srg)
  1349. {
  1350. AZ_Warning("AuxGeom", false, "Failed to create a shader resource group for an AuxGeom draw, Ignoring the draw");
  1351. return nullptr;
  1352. }
  1353. const AZ::Matrix3x4 drawMatrix = AZ::Matrix3x4::CreateFromMatrix3x3AndTranslation(shape.m_rotationMatrix, shape.m_position) * AZ::Matrix3x4::CreateScale(shape.m_scale);
  1354. if (drawStyle == DrawStyle_Shaded)
  1355. {
  1356. Matrix3x3 rotation = shape.m_rotationMatrix;
  1357. rotation.MultiplyByScale(shape.m_scale.GetReciprocal());
  1358. srg->SetConstant(shaderData.m_colorIndex, shape.m_color);
  1359. srg->SetConstant(shaderData.m_modelToWorldIndex, drawMatrix);
  1360. srg->SetConstant(shaderData.m_normalMatrixIndex, rotation);
  1361. }
  1362. else
  1363. {
  1364. srg->SetConstant(shaderData.m_colorIndex, shape.m_color);
  1365. srg->SetConstant(shaderData.m_modelToWorldIndex, drawMatrix);
  1366. }
  1367. if (drawStyle == DrawStyle_Point)
  1368. {
  1369. srg->SetConstant(shaderData.m_pointSizeIndex, shape.m_pointSize);
  1370. }
  1371. if (shape.m_viewProjOverrideIndex >= 0)
  1372. {
  1373. srg->SetConstant(shaderData.m_viewProjectionOverrideIndex, viewProjOverrides[shape.m_viewProjOverrideIndex]);
  1374. }
  1375. pipelineState->UpdateSrgVariantFallback(srg);
  1376. srg->Compile();
  1377. m_processSrgs.push_back(srg);
  1378. if (m_shapes[shape.m_shapeType].m_lodBuffers.size() > 0)
  1379. {
  1380. RHI::GeometryView* geometryView = GetGeometryView(shape.m_shapeType, drawStyle, lodIndex);
  1381. auto& drawListTag = shaderData.m_drawListTag;
  1382. return BuildDrawPacket(
  1383. drawPacketBuilder, srg, geometryView, drawListTag,
  1384. pipelineState->GetRHIPipelineState(), sortKey, drawStyle);
  1385. }
  1386. return nullptr;
  1387. }
  1388. RHI::GeometryView* FixedShapeProcessor::GetBoxGeometryView(int drawStyle)
  1389. {
  1390. return GetGeometryView(m_boxBuffers, drawStyle);
  1391. }
  1392. RHI::ConstPtr<RHI::DrawPacket> FixedShapeProcessor::BuildDrawPacketForBox(
  1393. RHI::DrawPacketBuilder& drawPacketBuilder,
  1394. const BoxBufferEntry& box,
  1395. int drawStyle,
  1396. const AZStd::vector<AZ::Matrix4x4>& viewProjOverrides,
  1397. const RPI::Ptr<RPI::PipelineStateForDraw>& pipelineState,
  1398. RHI::DrawItemSortKey sortKey)
  1399. {
  1400. ShaderData& shaderData = m_perObjectShaderData[drawStyle==DrawStyle_Shaded?1:0];
  1401. // Create a SRG for the box to specify its transform and color
  1402. auto srg = RPI::ShaderResourceGroup::Create(shaderData.m_shaderAsset, shaderData.m_supervariantIndex, shaderData.m_perObjectSrgLayout->GetName());
  1403. if (!srg)
  1404. {
  1405. AZ_Warning("AuxGeom", false, "Failed to create a shader resource group for an AuxGeom draw, Ignoring the draw");
  1406. return nullptr;
  1407. }
  1408. const AZ::Matrix3x4 drawMatrix = AZ::Matrix3x4::CreateFromMatrix3x3AndTranslation(box.m_rotationMatrix, box.m_position) * AZ::Matrix3x4::CreateScale(box.m_scale);
  1409. if (drawStyle == DrawStyle_Shaded)
  1410. {
  1411. Matrix3x3 rotation = box.m_rotationMatrix;
  1412. rotation.MultiplyByScale(box.m_scale.GetReciprocal());
  1413. srg->SetConstant(shaderData.m_colorIndex, box.m_color);
  1414. srg->SetConstant(shaderData.m_modelToWorldIndex, drawMatrix);
  1415. srg->SetConstant(shaderData.m_normalMatrixIndex, rotation);
  1416. }
  1417. else
  1418. {
  1419. srg->SetConstant(shaderData.m_colorIndex, box.m_color);
  1420. srg->SetConstant(shaderData.m_modelToWorldIndex, drawMatrix);
  1421. }
  1422. if (drawStyle == DrawStyle_Point)
  1423. {
  1424. srg->SetConstant(shaderData.m_pointSizeIndex, box.m_pointSize);
  1425. }
  1426. if (box.m_viewProjOverrideIndex >= 0)
  1427. {
  1428. srg->SetConstant(shaderData.m_viewProjectionOverrideIndex, viewProjOverrides[box.m_viewProjOverrideIndex]);
  1429. }
  1430. pipelineState->UpdateSrgVariantFallback(srg);
  1431. srg->Compile();
  1432. m_processSrgs.push_back(srg);
  1433. RHI::GeometryView* geometryView = GetBoxGeometryView(drawStyle);
  1434. auto& drawListTag = shaderData.m_drawListTag;
  1435. return BuildDrawPacket(drawPacketBuilder, srg, geometryView,
  1436. drawListTag, pipelineState->GetRHIPipelineState(), sortKey, drawStyle);
  1437. }
  1438. RHI::ConstPtr<RHI::DrawPacket> FixedShapeProcessor::BuildDrawPacket(
  1439. RHI::DrawPacketBuilder& drawPacketBuilder,
  1440. AZ::Data::Instance<RPI::ShaderResourceGroup>& srg,
  1441. RHI::GeometryView* geometryView,
  1442. RHI::DrawListTag drawListTag,
  1443. const RHI::PipelineState* pipelineState,
  1444. RHI::DrawItemSortKey sortKey,
  1445. int drawStyle)
  1446. {
  1447. drawPacketBuilder.Begin(nullptr);
  1448. drawPacketBuilder.SetGeometryView(geometryView);
  1449. drawPacketBuilder.AddShaderResourceGroup(srg->GetRHIShaderResourceGroup());
  1450. RHI::StreamBufferIndices streamIndices;
  1451. streamIndices.AddIndex(PositionStreamIndex);
  1452. if (drawStyle == DrawStyle_Shaded)
  1453. {
  1454. streamIndices.AddIndex(NormalStreamIndex);
  1455. }
  1456. RHI::DrawPacketBuilder::DrawRequest drawRequest;
  1457. drawRequest.m_listTag = drawListTag;
  1458. drawRequest.m_streamIndices = streamIndices;
  1459. drawRequest.m_pipelineState = pipelineState;
  1460. drawRequest.m_sortKey = sortKey;
  1461. drawPacketBuilder.AddDrawItem(drawRequest);
  1462. return drawPacketBuilder.End();
  1463. }
  1464. } // namespace Render
  1465. } // namespace AZ