3
0

FixedShapeProcessor.cpp 79 KB

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