HighInstanceExampleComponent.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  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 <Performance/HighInstanceExampleComponent.h>
  9. #include <SampleComponentManager.h>
  10. #include <SampleComponentConfig.h>
  11. #include <Atom/Component/DebugCamera/NoClipControllerBus.h>
  12. #include <Atom/RPI.Reflect/Model/ModelAsset.h>
  13. #include <Atom/RPI.Reflect/Material/MaterialAsset.h>
  14. #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
  15. #include <Atom/RPI.Public/AuxGeom/AuxGeomFeatureProcessorInterface.h>
  16. #include <Atom/RPI.Public/AuxGeom/AuxGeomDraw.h>
  17. #include <Automation/ScriptRunnerBus.h>
  18. #include <AzCore/Serialization/SerializeContext.h>
  19. #include <AzFramework/Windowing/WindowBus.h>
  20. #include <RHI/BasicRHIComponent.h>
  21. AZ_DECLARE_BUDGET(AtomSampleViewer);
  22. namespace AtomSampleViewer
  23. {
  24. using namespace AZ;
  25. void HighInstanceTestComponent::Reflect(AZ::ReflectContext* context)
  26. {
  27. if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  28. {
  29. serializeContext->Class<HighInstanceTestComponent, EntityLatticeTestComponent>()
  30. ->Version(0)
  31. ;
  32. }
  33. }
  34. HighInstanceTestComponent::HighInstanceTestComponent()
  35. : m_materialBrowser("@user@/HighInstanceTestComponent/material_browser.xml")
  36. , m_modelBrowser("@user@/HighInstanceTestComponent/model_browser.xml")
  37. , m_imguiSidebar("@user@/HighInstanceTestComponent/sidebar.xml")
  38. {
  39. m_materialBrowser.SetFilter([](const AZ::Data::AssetInfo& assetInfo)
  40. {
  41. return assetInfo.m_assetType == azrtti_typeid<AZ::RPI::MaterialAsset>();
  42. });
  43. m_modelBrowser.SetFilter([](const AZ::Data::AssetInfo& assetInfo)
  44. {
  45. return assetInfo.m_assetType == azrtti_typeid<AZ::RPI::ModelAsset>();
  46. });
  47. // Only use a diffuse white material so light colors are easily visible.
  48. const AZStd::vector<AZStd::string> materialAllowlist =
  49. {
  50. "materials/presets/macbeth/19_white_9-5_0-05d.azmaterial",
  51. };
  52. m_materialBrowser.SetDefaultPinnedAssets(materialAllowlist);
  53. m_pinnedMaterialCount = static_cast<uint32_t>(m_materialBrowser.GetPinnedAssets().size());
  54. m_expandedModelList =
  55. {
  56. "materialeditor/viewportmodels/cone.fbx.azmodel",
  57. "materialeditor/viewportmodels/cube.fbx.azmodel",
  58. "materialeditor/viewportmodels/cylinder.fbx.azmodel",
  59. "materialeditor/viewportmodels/platonicsphere.fbx.azmodel",
  60. "materialeditor/viewportmodels/polarsphere.fbx.azmodel",
  61. "materialeditor/viewportmodels/quadsphere.fbx.azmodel",
  62. "materialeditor/viewportmodels/torus.fbx.azmodel",
  63. "objects/cube.fbx.azmodel",
  64. "objects/cylinder.fbx.azmodel",
  65. };
  66. m_simpleModelList =
  67. {
  68. "objects/cube.fbx.azmodel"
  69. };
  70. m_modelBrowser.SetDefaultPinnedAssets(m_simpleModelList);
  71. }
  72. void HighInstanceTestComponent::Activate()
  73. {
  74. BuildDiskLightParameters();
  75. m_directionalLightFeatureProcessor = m_scene->GetFeatureProcessor<Render::DirectionalLightFeatureProcessorInterface>();
  76. m_diskLightFeatureProcessor = m_scene->GetFeatureProcessor<Render::DiskLightFeatureProcessorInterface>();
  77. AZ::TickBus::Handler::BusConnect();
  78. m_imguiSidebar.Activate();
  79. m_imguiSidebar.SetHideSidebar(true);
  80. m_materialBrowser.Activate();
  81. m_modelBrowser.Activate();
  82. m_materialBrowser.ResetPinnedAssetsToDefault();
  83. m_modelBrowser.ResetPinnedAssetsToDefault();
  84. SetLatticeDimensions(
  85. m_testParameters.m_latticeSize[0],
  86. m_testParameters.m_latticeSize[1],
  87. m_testParameters.m_latticeSize[2]);
  88. SetLatticeSpacing(
  89. m_testParameters.m_latticeSpacing[0],
  90. m_testParameters.m_latticeSpacing[1],
  91. m_testParameters.m_latticeSpacing[2]);
  92. SetLatticeEntityScale(m_testParameters.m_entityScale);
  93. Base::Activate();
  94. AzFramework::NativeWindowHandle windowHandle = nullptr;
  95. AzFramework::WindowSystemRequestBus::BroadcastResult(
  96. windowHandle,
  97. &AzFramework::WindowSystemRequestBus::Events::GetDefaultWindowHandle);
  98. AzFramework::WindowRequestBus::EventResult(
  99. m_preActivateVSyncInterval,
  100. windowHandle,
  101. &AzFramework::WindowRequestBus::Events::GetSyncInterval);
  102. AzFramework::WindowRequestBus::Event(
  103. windowHandle,
  104. &AzFramework::WindowRequestBus::Events::SetSyncInterval,
  105. 0);
  106. SaveCameraConfiguration();
  107. ResetNoClipController();
  108. SetIBLExposure(m_testParameters.m_iblExposure);
  109. }
  110. void HighInstanceTestComponent::Deactivate()
  111. {
  112. DestroyLights();
  113. RestoreCameraConfiguration();
  114. AzFramework::NativeWindowHandle windowHandle = nullptr;
  115. AzFramework::WindowSystemRequestBus::BroadcastResult(
  116. windowHandle,
  117. &AzFramework::WindowSystemRequestBus::Events::GetDefaultWindowHandle);
  118. AzFramework::WindowRequestBus::Event(
  119. windowHandle,
  120. &AzFramework::WindowRequestBus::Events::SetSyncInterval,
  121. m_preActivateVSyncInterval);
  122. m_materialBrowser.Deactivate();
  123. m_modelBrowser.Deactivate();
  124. AZ::TickBus::Handler::BusDisconnect();
  125. m_imguiSidebar.Deactivate();
  126. Base::Deactivate();
  127. }
  128. void HighInstanceTestComponent::PrepareCreateLatticeInstances(uint32_t instanceCount)
  129. {
  130. m_modelInstanceData.reserve(instanceCount);
  131. DestroyLights();
  132. }
  133. void HighInstanceTestComponent::CreateLatticeInstance(const AZ::Transform& transform)
  134. {
  135. m_modelInstanceData.emplace_back<ModelInstanceData>({});
  136. ModelInstanceData& data = m_modelInstanceData.back();
  137. data.m_modelAssetId = GetRandomModelId();
  138. data.m_materialAssetId = GetRandomMaterialId();
  139. data.m_transform = transform;
  140. }
  141. void HighInstanceTestComponent::FinalizeLatticeInstances()
  142. {
  143. AZStd::set<AZ::Data::AssetId> assetIds;
  144. for (ModelInstanceData& instanceData : m_modelInstanceData)
  145. {
  146. if (instanceData.m_materialAssetId.IsValid())
  147. {
  148. assetIds.insert(instanceData.m_materialAssetId);
  149. }
  150. if (instanceData.m_modelAssetId.IsValid())
  151. {
  152. assetIds.insert(instanceData.m_modelAssetId);
  153. }
  154. }
  155. AZStd::vector<AZ::AssetCollectionAsyncLoader::AssetToLoadInfo> assetList;
  156. for (auto& assetId : assetIds)
  157. {
  158. AZ::Data::AssetInfo assetInfo;
  159. AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetInfo, &AZ::Data::AssetCatalogRequests::GetAssetInfoById, assetId);
  160. if (assetInfo.m_assetId.IsValid())
  161. {
  162. AZ::AssetCollectionAsyncLoader::AssetToLoadInfo info;
  163. info.m_assetPath = assetInfo.m_relativePath;
  164. info.m_assetType = assetInfo.m_assetType;
  165. assetList.push_back(info);
  166. }
  167. }
  168. PreloadAssets(assetList);
  169. // pause script and tick until assets are ready
  170. ScriptRunnerRequestBus::Broadcast(&ScriptRunnerRequests::PauseScriptWithTimeout, 120.0f);
  171. AZ::TickBus::Handler::BusDisconnect();
  172. if (m_testParameters.m_numShadowCastingSpotLights > 0 && m_diskLightsEnabled)
  173. {
  174. CreateSpotLights();
  175. }
  176. if (m_testParameters.m_activateDirectionalLight && m_directionalLightEnabled)
  177. {
  178. CreateDirectionalLight();
  179. }
  180. }
  181. void HighInstanceTestComponent::OnAllAssetsReadyActivate()
  182. {
  183. for (ModelInstanceData& instanceData : m_modelInstanceData)
  184. {
  185. AZ::Data::Instance<AZ::RPI::Material> materialInstance;
  186. if (instanceData.m_materialAssetId.IsValid())
  187. {
  188. AZ::Data::Asset<RPI::MaterialAsset> materialAsset;
  189. materialAsset.Create(instanceData.m_materialAssetId);
  190. materialInstance = AZ::RPI::Material::FindOrCreate(materialAsset);
  191. // cache the material when its loaded
  192. m_cachedMaterials.insert(materialAsset);
  193. }
  194. if (instanceData.m_modelAssetId.IsValid())
  195. {
  196. AZ::Data::Asset<AZ::RPI::ModelAsset> modelAsset;
  197. modelAsset.Create(instanceData.m_modelAssetId);
  198. instanceData.m_meshHandle = GetMeshFeatureProcessor()->AcquireMesh(AZ::Render::MeshHandleDescriptor(modelAsset, materialInstance));
  199. GetMeshFeatureProcessor()->SetTransform(instanceData.m_meshHandle, instanceData.m_transform);
  200. }
  201. }
  202. ScriptRunnerRequestBus::Broadcast(&ScriptRunnerRequests::ResumeScript);
  203. AZ::TickBus::Handler::BusConnect();
  204. }
  205. void HighInstanceTestComponent::DestroyLatticeInstances()
  206. {
  207. DestroyHandles();
  208. m_modelInstanceData.clear();
  209. }
  210. void HighInstanceTestComponent::DestroyLights()
  211. {
  212. m_directionalLightFeatureProcessor->ReleaseLight(m_directionalLightHandle);
  213. m_directionalLightHandle = {};
  214. for (int index = 0; index < m_diskLights.size(); ++index)
  215. {
  216. DiskLightHandle& handle = m_diskLights[index].m_handle;
  217. m_diskLightFeatureProcessor->ReleaseLight(handle);
  218. handle = {};
  219. }
  220. }
  221. void HighInstanceTestComponent::DestroyHandles()
  222. {
  223. for (ModelInstanceData& instanceData : m_modelInstanceData)
  224. {
  225. GetMeshFeatureProcessor()->ReleaseMesh(instanceData.m_meshHandle);
  226. instanceData.m_meshHandle = {};
  227. }
  228. }
  229. AZ::Data::AssetId HighInstanceTestComponent::GetRandomModelId() const
  230. {
  231. auto& modelAllowlist = m_modelBrowser.GetPinnedAssets();
  232. if (modelAllowlist.size())
  233. {
  234. const size_t randomModelIndex = rand() % modelAllowlist.size();
  235. return modelAllowlist[randomModelIndex].m_assetId;
  236. }
  237. else
  238. {
  239. return AZ::RPI::AssetUtils::GetAssetIdForProductPath("testdata/objects/cube/cube.fbx.azmodel", AZ::RPI::AssetUtils::TraceLevel::Error);
  240. }
  241. }
  242. AZ::Data::AssetId HighInstanceTestComponent::GetRandomMaterialId() const
  243. {
  244. auto& materialAllowlist = m_materialBrowser.GetPinnedAssets();
  245. if (materialAllowlist.size())
  246. {
  247. const size_t randomMaterialIndex = rand() % materialAllowlist.size();
  248. return materialAllowlist[randomMaterialIndex].m_assetId;
  249. }
  250. else
  251. {
  252. return AZ::RPI::AssetUtils::GetAssetIdForProductPath(DefaultPbrMaterialPath, AZ::RPI::AssetUtils::TraceLevel::Error);
  253. }
  254. }
  255. void HighInstanceTestComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint scriptTime)
  256. {
  257. AZ_PROFILE_FUNCTION(AtomSampleViewer);
  258. if (m_updateTransformEnabled)
  259. {
  260. float radians = static_cast<float>(fmod(scriptTime.GetSeconds(), AZ::Constants::TwoPi));
  261. AZ::Vector3 rotation(radians, radians, radians);
  262. AZ::Transform rotationTransform;
  263. rotationTransform.SetFromEulerRadians(rotation);
  264. for (ModelInstanceData& instanceData : m_modelInstanceData)
  265. {
  266. GetMeshFeatureProcessor()->SetTransform(instanceData.m_meshHandle, instanceData.m_transform * rotationTransform);
  267. }
  268. }
  269. bool currentUseSimpleModels = m_useSimpleModels;
  270. bool diskLightsEnabled = m_diskLightsEnabled;
  271. bool directionalLightEnabled = m_directionalLightEnabled;
  272. if (m_imguiSidebar.Begin())
  273. {
  274. ImGui::Checkbox("Update Transforms Every Frame", &m_updateTransformEnabled);
  275. ImGui::Spacing();
  276. ImGui::Separator();
  277. ImGui::Spacing();
  278. RenderImGuiLatticeControls();
  279. ImGui::Spacing();
  280. ImGui::Separator();
  281. ImGui::Spacing();
  282. ImGui::Checkbox("Use simple models", &m_useSimpleModels);
  283. ImGui::Spacing();
  284. ImGui::Separator();
  285. ImGui::Spacing();
  286. ImGui::Checkbox("Display SpotLight Debug", &m_drawDiskLightDebug);
  287. ImGui::Spacing();
  288. ImGui::Separator();
  289. ImGui::Spacing();
  290. if (m_testParameters.m_numShadowCastingSpotLights > 0)
  291. {
  292. ImGui::Checkbox("Enable SpotLights", &m_diskLightsEnabled);
  293. }
  294. if (m_testParameters.m_activateDirectionalLight)
  295. {
  296. ImGui::Checkbox("Enable Directional Light", &m_directionalLightEnabled);
  297. }
  298. m_imguiSidebar.End();
  299. }
  300. if(diskLightsEnabled != m_diskLightsEnabled || directionalLightEnabled != m_directionalLightEnabled)
  301. {
  302. DestroyLights();
  303. if (m_testParameters.m_numShadowCastingSpotLights > 0 && m_diskLightsEnabled)
  304. {
  305. CreateSpotLights();
  306. }
  307. if(m_testParameters.m_activateDirectionalLight && m_directionalLightEnabled)
  308. {
  309. CreateDirectionalLight();
  310. }
  311. }
  312. if (currentUseSimpleModels != m_useSimpleModels)
  313. {
  314. m_modelBrowser.SetPinnedAssets(m_useSimpleModels?m_simpleModelList:m_expandedModelList);
  315. for (ModelInstanceData& instanceData : m_modelInstanceData)
  316. {
  317. instanceData.m_modelAssetId = GetRandomModelId();
  318. }
  319. DestroyHandles();
  320. DestroyLights();
  321. FinalizeLatticeInstances();
  322. }
  323. DrawDiskLightDebugObjects();
  324. }
  325. void HighInstanceTestComponent::ResetNoClipController()
  326. {
  327. using namespace AZ;
  328. using namespace AZ::Debug;
  329. AZ::Vector3 camPos = AZ::Vector3::CreateFromFloat3(m_testParameters.m_cameraPosition);
  330. Camera::CameraRequestBus::Event(GetCameraEntityId(), &Camera::CameraRequestBus::Events::SetFarClipDistance, 2000.0f);
  331. NoClipControllerRequestBus::Event(GetCameraEntityId(), &NoClipControllerRequestBus::Events::SetPosition, camPos);
  332. NoClipControllerRequestBus::Event(GetCameraEntityId(), &NoClipControllerRequestBus::Events::SetHeading, AZ::DegToRad(m_testParameters.m_cameraHeadingDeg));
  333. NoClipControllerRequestBus::Event(GetCameraEntityId(), &NoClipControllerRequestBus::Events::SetPitch, AZ::DegToRad(m_testParameters.m_cameraPitchDeg));
  334. }
  335. void HighInstanceTestComponent::SaveCameraConfiguration()
  336. {
  337. Camera::CameraRequestBus::EventResult(m_originalFarClipDistance, GetCameraEntityId(), &Camera::CameraRequestBus::Events::GetFarClipDistance);
  338. }
  339. void HighInstanceTestComponent::RestoreCameraConfiguration()
  340. {
  341. Camera::CameraRequestBus::Event(GetCameraEntityId(), &Camera::CameraRequestBus::Events::SetFarClipDistance, m_originalFarClipDistance);
  342. }
  343. void HighInstanceTestComponent::CreateSpotLights()
  344. {
  345. for (int index = 0; index < m_testParameters.m_numShadowCastingSpotLights; ++index)
  346. {
  347. CreateSpotLight(index);
  348. }
  349. }
  350. void HighInstanceTestComponent::CreateSpotLight(int index)
  351. {
  352. Render::DiskLightFeatureProcessorInterface* const featureProcessor = m_diskLightFeatureProcessor;
  353. const DiskLightHandle handle = featureProcessor->AcquireLight();
  354. AZ::Render::PhotometricColor<AZ::Render::PhotometricUnit::Candela> lightColor(m_diskLights[index].m_color * m_testParameters.m_shadowSpotlightIntensity);
  355. featureProcessor->SetRgbIntensity(handle, lightColor);
  356. featureProcessor->SetAttenuationRadius(handle, m_testParameters.m_shadowSpotlightMaxDistance);
  357. featureProcessor->SetConeAngles(
  358. handle,
  359. DegToRad(m_testParameters.m_shadowSpotlightInnerAngleDeg),
  360. DegToRad(m_testParameters.m_shadowSpotlightOuterAngleDeg));
  361. featureProcessor->SetShadowsEnabled(handle, true);
  362. featureProcessor->SetShadowmapMaxResolution(handle, m_testParameters.m_shadowmapSize);
  363. featureProcessor->SetShadowFilterMethod(handle, m_testParameters.m_shadowFilterMethod);
  364. featureProcessor->SetFilteringSampleCount(handle, 1);
  365. const Vector3 aabbOffset = m_diskLights[index].m_relativePosition.GetNormalized() * (0.5f * m_testParameters.m_shadowSpotlightMaxDistance);
  366. const Vector3 position = m_worldAabb.GetCenter() + aabbOffset;
  367. featureProcessor->SetPosition(handle, position);
  368. featureProcessor->SetDirection(handle, (-aabbOffset).GetNormalized());
  369. m_diskLights[index].m_handle = handle;
  370. }
  371. const AZ::Color& HighInstanceTestComponent::GetNextLightColor()
  372. {
  373. static uint16_t colorIndex = 0;
  374. static const AZStd::vector<AZ::Color> colors =
  375. {
  376. AZ::Colors::Red,
  377. AZ::Colors::Green,
  378. AZ::Colors::Blue,
  379. AZ::Colors::Cyan,
  380. AZ::Colors::Fuchsia,
  381. AZ::Colors::Yellow,
  382. AZ::Colors::SpringGreen
  383. };
  384. const AZ::Color& result = colors[colorIndex];
  385. colorIndex = (colorIndex + 1) % colors.size();
  386. return result;
  387. }
  388. AZ::Vector3 HighInstanceTestComponent::GetRandomDirection()
  389. {
  390. return AZ::Vector3(
  391. m_random.GetRandomFloat() - 0.5f,
  392. m_random.GetRandomFloat() - 0.5f,
  393. m_random.GetRandomFloat() - 0.5f).GetNormalized();
  394. }
  395. void HighInstanceTestComponent::BuildDiskLightParameters()
  396. {
  397. m_random.SetSeed(0);
  398. m_diskLights.clear();
  399. m_diskLights.reserve(m_testParameters.m_numShadowCastingSpotLights);
  400. for (int index = 0; index < m_testParameters.m_numShadowCastingSpotLights; ++index)
  401. {
  402. m_diskLights.emplace_back(
  403. GetNextLightColor(),
  404. GetRandomDirection(),
  405. m_testParameters.m_shadowmapSize);
  406. }
  407. }
  408. void HighInstanceTestComponent::CreateDirectionalLight()
  409. {
  410. Render::DirectionalLightFeatureProcessorInterface* featureProcessor = m_directionalLightFeatureProcessor;
  411. const DirectionalLightHandle handle = featureProcessor->AcquireLight();
  412. const auto lightTransform = Transform::CreateLookAt(
  413. -m_worldAabb.GetMax(),
  414. Vector3::CreateZero());
  415. featureProcessor->SetDirection(
  416. handle,
  417. lightTransform.GetBasis(1));
  418. featureProcessor->SetRgbIntensity(handle, AZ::Render::PhotometricColor<AZ::Render::PhotometricUnit::Lux>(AZ::Color::CreateOne() * m_testParameters.m_directionalLightIntensity));
  419. featureProcessor->SetShadowEnabled(handle, true);
  420. featureProcessor->SetCascadeCount(handle, m_testParameters.m_numDirectionalLightShadowCascades);
  421. featureProcessor->SetShadowmapSize(handle, m_testParameters.m_shadowmapSize);
  422. featureProcessor->SetViewFrustumCorrectionEnabled(handle, false);
  423. featureProcessor->SetShadowFilterMethod(handle, m_testParameters.m_shadowFilterMethod);
  424. featureProcessor->SetFilteringSampleCount(handle, 1);
  425. featureProcessor->SetGroundHeight(handle, 0.f);
  426. m_directionalLightHandle = handle;
  427. }
  428. void HighInstanceTestComponent::DrawDiskLightDebugObjects()
  429. {
  430. if (auto auxGeom = AZ::RPI::AuxGeomFeatureProcessorInterface::GetDrawQueueForScene(m_scene);
  431. m_drawDiskLightDebug && auxGeom)
  432. {
  433. for (int i = 0; i < m_diskLights.size(); ++i)
  434. {
  435. const auto& light = m_diskLights[i];
  436. if (light.m_handle.IsValid())
  437. {
  438. const Render::DiskLightData& lightData = m_diskLightFeatureProcessor->GetDiskData(light.m_handle);
  439. const float lightDistance = sqrt(1.0f/lightData.m_invAttenuationRadiusSquared);
  440. AZ::Vector3 position = AZ::Vector3::CreateFromFloat3(lightData.m_position.data());
  441. AZ::Vector3 direction = AZ::Vector3::CreateFromFloat3(lightData.m_direction.data()).GetNormalized();
  442. position += direction * lightDistance;
  443. direction *= -1.0f;
  444. float coneSlantLength = lightDistance / lightData.m_cosOuterConeAngle;
  445. float farEndCapRadius = sqrt(coneSlantLength * coneSlantLength - lightDistance * lightDistance);
  446. auxGeom->DrawCone(position, direction, farEndCapRadius, lightDistance, light.m_color, AZ::RPI::AuxGeomDraw::DrawStyle::Line);
  447. }
  448. }
  449. }
  450. }
  451. } // namespace AtomSampleViewer