3
0

MeshFeatureProcessor.cpp 151 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001
  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 <Atom/Feature/CoreLights/PhotometricValue.h>
  9. #include <Atom/Feature/Mesh/MeshCommon.h>
  10. #include <Atom/Feature/Mesh/MeshFeatureProcessor.h>
  11. #include <Atom/Feature/Mesh/ModelReloaderSystemInterface.h>
  12. #include <Atom/Feature/RenderCommon.h>
  13. #include <Atom/Feature/Utils/GpuBufferHandler.h>
  14. #include <Atom/RHI.Reflect/InputStreamLayoutBuilder.h>
  15. #include <Atom/RHI/RHISystemInterface.h>
  16. #include <Atom/RHI/RHIUtils.h>
  17. #include <Atom/RPI.Public/AssetQuality.h>
  18. #include <Atom/RPI.Public/Culling.h>
  19. #include <Atom/RPI.Public/Model/ModelLodUtils.h>
  20. #include <Atom/RPI.Public/Model/ModelTagSystemComponent.h>
  21. #include <Atom/RPI.Public/RPIUtils.h>
  22. #include <Atom/RPI.Public/Scene.h>
  23. #include <Material/ConvertEmissiveUnitFunctor.h>
  24. #include <Atom/Utils/StableDynamicArray.h>
  25. #include <ReflectionProbe/ReflectionProbeFeatureProcessor.h>
  26. #include <Atom/RPI.Reflect/Model/ModelAssetCreator.h>
  27. #include <AzFramework/Asset/AssetSystemBus.h>
  28. #include <AtomCore/Instance/InstanceDatabase.h>
  29. #include <AzCore/Asset/AssetCommon.h>
  30. #include <AzCore/Console/IConsole.h>
  31. #include <AzCore/Jobs/Algorithms.h>
  32. #include <AzCore/Jobs/JobCompletion.h>
  33. #include <AzCore/Jobs/JobFunction.h>
  34. #include <AzCore/Math/ShapeIntersection.h>
  35. #include <AzCore/Name/NameDictionary.h>
  36. #include <AzCore/RTTI/RTTI.h>
  37. #include <AzCore/RTTI/TypeInfo.h>
  38. #include <AzCore/Serialization/SerializeContext.h>
  39. #include <algorithm>
  40. namespace AZ
  41. {
  42. namespace Render
  43. {
  44. static AZ::Name s_o_meshUseForwardPassIBLSpecular_Name =
  45. AZ::Name::FromStringLiteral("o_meshUseForwardPassIBLSpecular", AZ::Interface<AZ::NameDictionary>::Get());
  46. static AZ::Name s_Manual_Name = AZ::Name::FromStringLiteral("Manual", AZ::Interface<AZ::NameDictionary>::Get());
  47. static AZ::Name s_Multiply_Name = AZ::Name::FromStringLiteral("Multiply", AZ::Interface<AZ::NameDictionary>::Get());
  48. static AZ::Name s_BaseColorTint_Name = AZ::Name::FromStringLiteral("BaseColorTint", AZ::Interface<AZ::NameDictionary>::Get());
  49. static AZ::Name s_BaseColor_Name = AZ::Name::FromStringLiteral("BaseColor", AZ::Interface<AZ::NameDictionary>::Get());
  50. static AZ::Name s_baseColor_color_Name = AZ::Name::FromStringLiteral("baseColor.color", AZ::Interface<AZ::NameDictionary>::Get());
  51. static AZ::Name s_baseColor_factor_Name = AZ::Name::FromStringLiteral("baseColor.factor", AZ::Interface<AZ::NameDictionary>::Get());
  52. static AZ::Name s_baseColor_useTexture_Name =
  53. AZ::Name::FromStringLiteral("baseColor.useTexture", AZ::Interface<AZ::NameDictionary>::Get());
  54. static AZ::Name s_metallic_factor_Name = AZ::Name::FromStringLiteral("metallic.factor", AZ::Interface<AZ::NameDictionary>::Get());
  55. static AZ::Name s_roughness_factor_Name = AZ::Name::FromStringLiteral("roughness.factor", AZ::Interface<AZ::NameDictionary>::Get());
  56. static AZ::Name s_emissive_enable_Name = AZ::Name::FromStringLiteral("emissive.enable", AZ::Interface<AZ::NameDictionary>::Get());
  57. static AZ::Name s_emissive_color_Name = AZ::Name::FromStringLiteral("emissive.color", AZ::Interface<AZ::NameDictionary>::Get());
  58. static AZ::Name s_emissive_intensity_Name =
  59. AZ::Name::FromStringLiteral("emissive.intensity", AZ::Interface<AZ::NameDictionary>::Get());
  60. static AZ::Name s_emissive_unit_Name = AZ::Name::FromStringLiteral("emissive.unit", AZ::Interface<AZ::NameDictionary>::Get());
  61. static AZ::Name s_baseColor_textureMap_Name =
  62. AZ::Name::FromStringLiteral("baseColor.textureMap", AZ::Interface<AZ::NameDictionary>::Get());
  63. static AZ::Name s_normal_textureMap_Name =
  64. AZ::Name::FromStringLiteral("normal.textureMap", AZ::Interface<AZ::NameDictionary>::Get());
  65. static AZ::Name s_metallic_textureMap_Name =
  66. AZ::Name::FromStringLiteral("metallic.textureMap", AZ::Interface<AZ::NameDictionary>::Get());
  67. static AZ::Name s_roughness_textureMap_Name =
  68. AZ::Name::FromStringLiteral("roughness.textureMap", AZ::Interface<AZ::NameDictionary>::Get());
  69. static AZ::Name s_irradiance_irradianceColorSource_Name =
  70. AZ::Name::FromStringLiteral("irradiance.irradianceColorSource", AZ::Interface<AZ::NameDictionary>::Get());
  71. static AZ::Name s_emissive_textureMap_Name =
  72. AZ::Name::FromStringLiteral("emissive.textureMap", AZ::Interface<AZ::NameDictionary>::Get());
  73. static AZ::Name s_irradiance_manualColor_Name =
  74. AZ::Name::FromStringLiteral("irradiance.manualColor", AZ::Interface<AZ::NameDictionary>::Get());
  75. static AZ::Name s_irradiance_color_Name = AZ::Name::FromStringLiteral("irradiance.color", AZ::Interface<AZ::NameDictionary>::Get());
  76. static AZ::Name s_baseColor_textureBlendMode_Name =
  77. AZ::Name::FromStringLiteral("baseColor.textureBlendMode", AZ::Interface<AZ::NameDictionary>::Get());
  78. static AZ::Name s_irradiance_factor_Name =
  79. AZ::Name::FromStringLiteral("irradiance.factor", AZ::Interface<AZ::NameDictionary>::Get());
  80. static AZ::Name s_opacity_mode_Name = AZ::Name::FromStringLiteral("opacity.mode", AZ::Interface<AZ::NameDictionary>::Get());
  81. static AZ::Name s_opacity_factor_Name = AZ::Name::FromStringLiteral("opacity.factor", AZ::Interface<AZ::NameDictionary>::Get());
  82. static AZ::Name s_m_rootConstantInstanceDataOffset_Name =
  83. AZ::Name::FromStringLiteral("m_rootConstantInstanceDataOffset", AZ::Interface<AZ::NameDictionary>::Get());
  84. static AZ::Name s_o_meshInstancingIsEnabled_Name =
  85. AZ::Name::FromStringLiteral("o_meshInstancingIsEnabled", AZ::Interface<AZ::NameDictionary>::Get());
  86. static AZ::Name s_transparent_Name = AZ::Name::FromStringLiteral("transparent", AZ::Interface<AZ::NameDictionary>::Get());
  87. static AZ::Name s_block_silhouette_Name = AZ::Name::FromStringLiteral("silhouette.blockSilhouette", AZ::Interface<AZ::NameDictionary>::Get());
  88. static void CacheRootConstantInterval(MeshInstanceGroupData& meshInstanceGroupData)
  89. {
  90. meshInstanceGroupData.m_drawRootConstantOffset = 0;
  91. RHI::ConstPtr<RHI::ConstantsLayout> rootConstantsLayout = meshInstanceGroupData.m_drawPacket.GetRootConstantsLayout();
  92. if (rootConstantsLayout)
  93. {
  94. // Get the root constant layout
  95. RHI::ShaderInputConstantIndex shaderInputIndex =
  96. rootConstantsLayout->FindShaderInputIndex(s_m_rootConstantInstanceDataOffset_Name);
  97. if (shaderInputIndex.IsValid())
  98. {
  99. RHI::Interval interval = rootConstantsLayout->GetInterval(shaderInputIndex);
  100. meshInstanceGroupData.m_drawRootConstantOffset = interval.m_min;
  101. }
  102. }
  103. }
  104. void MeshFeatureProcessor::Reflect(ReflectContext* context)
  105. {
  106. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  107. {
  108. serializeContext->Class<MeshFeatureProcessor, FeatureProcessor>()->Version(1);
  109. }
  110. }
  111. void MeshFeatureProcessor::Activate()
  112. {
  113. m_transformService = GetParentScene()->GetFeatureProcessor<TransformServiceFeatureProcessor>();
  114. AZ_Assert(m_transformService, "MeshFeatureProcessor requires a TransformServiceFeatureProcessor on its parent scene.");
  115. m_rayTracingFeatureProcessor = GetParentScene()->GetFeatureProcessor<RayTracingFeatureProcessor>();
  116. m_reflectionProbeFeatureProcessor = GetParentScene()->GetFeatureProcessor<ReflectionProbeFeatureProcessor>();
  117. m_handleGlobalShaderOptionUpdate = RPI::ShaderSystemInterface::GlobalShaderOptionUpdatedEvent::Handler
  118. {
  119. [this](const AZ::Name&, RPI::ShaderOptionValue) { m_forceRebuildDrawPackets = true; }
  120. };
  121. RPI::ShaderSystemInterface::Get()->Connect(m_handleGlobalShaderOptionUpdate);
  122. EnableSceneNotification();
  123. // Must read cvar from AZ::Console due to static variable in multiple libraries, see ghi-5537
  124. bool enablePerMeshShaderOptionFlagsCvar = false;
  125. if (auto* console = AZ::Interface<AZ::IConsole>::Get(); console != nullptr)
  126. {
  127. console->GetCvarValue("r_enablePerMeshShaderOptionFlags", enablePerMeshShaderOptionFlagsCvar);
  128. // push the cvars value so anything in this dll can access it directly.
  129. console->PerformCommand(AZStd::string::format("r_enablePerMeshShaderOptionFlags %s", enablePerMeshShaderOptionFlagsCvar ? "true" : "false").c_str());
  130. }
  131. m_meshMovedFlag = GetParentScene()->GetViewTagBitRegistry().AcquireTag(MeshCommon::MeshMovedName);
  132. m_meshMotionDrawListTag = AZ::RHI::RHISystemInterface::Get()->GetDrawListTagRegistry()->AcquireTag(MeshCommon::MotionDrawListTagName);
  133. m_transparentDrawListTag = AZ::RHI::RHISystemInterface::Get()->GetDrawListTagRegistry()->AcquireTag(s_transparent_Name);
  134. if (auto* console = AZ::Interface<AZ::IConsole>::Get(); console != nullptr)
  135. {
  136. console->GetCvarValue("r_meshInstancingEnabled", m_enableMeshInstancing);
  137. // push the cvars value so anything in this dll can access it directly.
  138. console->PerformCommand(
  139. AZStd::string::format("r_meshInstancingEnabled %s", m_enableMeshInstancing ? "true" : "false")
  140. .c_str());
  141. console->GetCvarValue("r_meshInstancingEnabledForTransparentObjects", m_enableMeshInstancingForTransparentObjects);
  142. // push the cvars value so anything in this dll can access it directly.
  143. console->PerformCommand(
  144. AZStd::string::format(
  145. "r_meshInstancingEnabledForTransparentObjects %s", m_enableMeshInstancingForTransparentObjects ? "true" : "false")
  146. .c_str());
  147. size_t meshInstancingBucketSortScatterBatchSize;
  148. console->GetCvarValue("r_meshInstancingBucketSortScatterBatchSize", meshInstancingBucketSortScatterBatchSize);
  149. // push the cvars value so anything in this dll can access it directly.
  150. console->PerformCommand(
  151. AZStd::string::format(
  152. "r_meshInstancingBucketSortScatterBatchSize %zu", meshInstancingBucketSortScatterBatchSize)
  153. .c_str());
  154. }
  155. }
  156. void MeshFeatureProcessor::Deactivate()
  157. {
  158. m_flagRegistry.reset();
  159. m_handleGlobalShaderOptionUpdate.Disconnect();
  160. DisableSceneNotification();
  161. AZ_Warning("MeshFeatureProcessor", m_modelData.size() == 0,
  162. "Deactivating the MeshFeatureProcessor, but there are still outstanding mesh handles.\n"
  163. );
  164. m_transformService = nullptr;
  165. m_rayTracingFeatureProcessor = nullptr;
  166. m_reflectionProbeFeatureProcessor = nullptr;
  167. m_forceRebuildDrawPackets = false;
  168. GetParentScene()->GetViewTagBitRegistry().ReleaseTag(m_meshMovedFlag);
  169. RHI::RHISystemInterface::Get()->GetDrawListTagRegistry()->ReleaseTag(m_meshMotionDrawListTag);
  170. RHI::RHISystemInterface::Get()->GetDrawListTagRegistry()->ReleaseTag(m_transparentDrawListTag);
  171. }
  172. TransformServiceFeatureProcessorInterface::ObjectId MeshFeatureProcessor::GetObjectId(const MeshHandle& meshHandle) const
  173. {
  174. if (meshHandle.IsValid())
  175. {
  176. return meshHandle->m_objectId;
  177. }
  178. return TransformServiceFeatureProcessorInterface::ObjectId::Null;
  179. }
  180. void MeshFeatureProcessor::Simulate(const FeatureProcessor::SimulatePacket& packet)
  181. {
  182. AZ_PROFILE_SCOPE(RPI, "MeshFeatureProcessor: Simulate");
  183. AZ::Job* parentJob = packet.m_parentJob;
  184. AZStd::concurrency_check_scope scopeCheck(m_meshDataChecker);
  185. // If the instancing cvar has changed, we need to re-initalize the ModelDataInstances
  186. CheckForInstancingCVarChange();
  187. AZStd::vector<Job*> initJobQueue = CreateInitJobQueue();
  188. AZStd::vector<Job*> updateCullingJobQueue = CreateUpdateCullingJobQueue();
  189. if (!r_meshInstancingEnabled)
  190. {
  191. // There's no need for all the init jobs to finish before any of the update culling jobs are run.
  192. // Any update culling job can run once it's corresponding init job is done. So instead of separating the jobs
  193. // entirely, use individual job dependencies to synchronize them. This performs better than having a big sync between them
  194. ExecuteCombinedJobQueue(initJobQueue, updateCullingJobQueue, parentJob);
  195. }
  196. else
  197. {
  198. ExecuteSimulateJobQueue(initJobQueue, parentJob);
  199. // Per-InstanceGroup work must be done after the Init jobs are complete, because the init jobs will determine which instance
  200. // group each mesh belongs to and populate those instance groups
  201. // Note: the Per-InstanceGroup jobs need to be created after init jobs because it's possible new instance groups are created in init jobs
  202. AZStd::vector<Job*> perInstanceGroupJobQueue = CreatePerInstanceGroupJobQueue();
  203. ExecuteSimulateJobQueue(perInstanceGroupJobQueue, parentJob);
  204. // Updating the culling scene must happen after the per-instance group work is done
  205. // because the per-instance group work will update the draw packets.
  206. ExecuteSimulateJobQueue(updateCullingJobQueue, parentJob);
  207. }
  208. m_forceRebuildDrawPackets = false;
  209. }
  210. void MeshFeatureProcessor::CheckForInstancingCVarChange()
  211. {
  212. if (m_enableMeshInstancing != r_meshInstancingEnabled || m_enableMeshInstancingForTransparentObjects != r_meshInstancingEnabledForTransparentObjects)
  213. {
  214. // DeInit and re-init every object
  215. for (auto& modelDataInstance : m_modelData)
  216. {
  217. modelDataInstance.ReInit(this);
  218. }
  219. m_enableMeshInstancing = r_meshInstancingEnabled;
  220. m_enableMeshInstancingForTransparentObjects = r_meshInstancingEnabledForTransparentObjects;
  221. }
  222. }
  223. AZStd::vector<Job*> MeshFeatureProcessor::CreatePerInstanceGroupJobQueue()
  224. {
  225. const auto instanceManagerRanges = m_meshInstanceManager.GetParallelRanges();
  226. AZStd::vector<Job*> perInstanceGroupJobQueue;
  227. perInstanceGroupJobQueue.reserve(instanceManagerRanges.size());
  228. RPI::Scene* scene = GetParentScene();
  229. for (const auto& iteratorRange : instanceManagerRanges)
  230. {
  231. const auto perInstanceGroupJobLambda = [this, scene, iteratorRange]() -> void
  232. {
  233. AZ_PROFILE_SCOPE(AzRender, "MeshFeatureProcessor: Simulate: PerInstanceGroupUpdate");
  234. for (auto instanceGroupDataIter = iteratorRange.m_begin; instanceGroupDataIter != iteratorRange.m_end;
  235. ++instanceGroupDataIter)
  236. {
  237. if (instanceGroupDataIter->UpdateDrawPacket(*scene, m_forceRebuildDrawPackets))
  238. {
  239. // We're going to need an interval for the root constant data that we update every frame for each draw item, so
  240. // cache that here
  241. CacheRootConstantInterval(*instanceGroupDataIter);
  242. }
  243. }
  244. };
  245. Job* executePerInstanceGroupJob =
  246. aznew JobFunction<decltype(perInstanceGroupJobLambda)>(perInstanceGroupJobLambda, true, nullptr); // Auto-deletes
  247. perInstanceGroupJobQueue.push_back(executePerInstanceGroupJob);
  248. }
  249. return perInstanceGroupJobQueue;
  250. }
  251. AZStd::vector<Job*> MeshFeatureProcessor::CreateInitJobQueue()
  252. {
  253. const auto iteratorRanges = m_modelData.GetParallelRanges();
  254. AZStd::vector<Job*> initJobQueue;
  255. initJobQueue.reserve(iteratorRanges.size());
  256. bool removePerMeshShaderOptionFlags = !r_enablePerMeshShaderOptionFlags && m_enablePerMeshShaderOptionFlags;
  257. for (const auto& iteratorRange : iteratorRanges)
  258. {
  259. const auto initJobLambda = [this, iteratorRange, removePerMeshShaderOptionFlags]() -> void
  260. {
  261. AZ_PROFILE_SCOPE(AzRender, "MeshFeatureProcessor: Simulate: Init");
  262. for (auto meshDataIter = iteratorRange.m_begin; meshDataIter != iteratorRange.m_end; ++meshDataIter)
  263. {
  264. if (!meshDataIter->m_model)
  265. {
  266. continue; // model not loaded yet
  267. }
  268. if (!meshDataIter->m_flags.m_visible)
  269. {
  270. continue;
  271. }
  272. if (meshDataIter->m_flags.m_needsInit)
  273. {
  274. meshDataIter->Init(this);
  275. }
  276. if (meshDataIter->m_flags.m_objectSrgNeedsUpdate)
  277. {
  278. meshDataIter->UpdateObjectSrg(this);
  279. }
  280. if (meshDataIter->m_flags.m_needsSetRayTracingData)
  281. {
  282. meshDataIter->SetRayTracingData(this);
  283. }
  284. // If instancing is enabled, the draw packets will be updated by the per-instance group jobs,
  285. // so they don't need to be updated here
  286. if (!r_meshInstancingEnabled)
  287. {
  288. // Unset per mesh shader options
  289. if (removePerMeshShaderOptionFlags)
  290. {
  291. for (RPI::MeshDrawPacketList& drawPacketList : meshDataIter->m_drawPacketListsByLod)
  292. {
  293. for (RPI::MeshDrawPacket& drawPacket : drawPacketList)
  294. {
  295. m_flagRegistry->VisitTags(
  296. [&](AZ::Name shaderOption, [[maybe_unused]] FlagRegistry::TagType tag)
  297. {
  298. drawPacket.UnsetShaderOption(shaderOption);
  299. });
  300. }
  301. }
  302. meshDataIter->m_cullable.m_shaderOptionFlags = 0;
  303. meshDataIter->m_cullable.m_prevShaderOptionFlags = 0;
  304. }
  305. // [GFX TODO] [ATOM-1357] Currently all of the draw packets have to be checked for material ID changes because
  306. // material properties can impact which actual shader is used, which impacts the SRG in the draw packet.
  307. // This is scheduled to be optimized so the work is only done on draw packets that need it instead of having
  308. // to check every one.
  309. meshDataIter->UpdateDrawPackets(m_forceRebuildDrawPackets);
  310. }
  311. }
  312. };
  313. Job* executeInitJob = aznew JobFunction<decltype(initJobLambda)>(initJobLambda, true, nullptr); // Auto-deletes
  314. initJobQueue.push_back(executeInitJob);
  315. }
  316. return initJobQueue;
  317. }
  318. AZStd::vector<Job*> MeshFeatureProcessor::CreateUpdateCullingJobQueue()
  319. {
  320. const auto iteratorRanges = m_modelData.GetParallelRanges();
  321. AZStd::vector<Job*> updateCullingJobQueue;
  322. updateCullingJobQueue.reserve(iteratorRanges.size());
  323. for (const auto& iteratorRange : iteratorRanges)
  324. {
  325. const auto updateCullingJobLambda = [this, iteratorRange]() -> void
  326. {
  327. AZ_PROFILE_SCOPE(AzRender, "MeshFeatureProcessor: Simulate: UpdateCulling");
  328. for (auto meshDataIter = iteratorRange.m_begin; meshDataIter != iteratorRange.m_end; ++meshDataIter)
  329. {
  330. if (!meshDataIter->m_model)
  331. {
  332. continue; // model not loaded yet
  333. }
  334. if (meshDataIter->m_flags.m_cullableNeedsRebuild)
  335. {
  336. meshDataIter->BuildCullable();
  337. }
  338. if (meshDataIter->m_flags.m_cullBoundsNeedsUpdate)
  339. {
  340. meshDataIter->UpdateCullBounds(this);
  341. }
  342. }
  343. };
  344. Job* executeUpdateGroupJob =
  345. aznew JobFunction<decltype(updateCullingJobLambda)>(updateCullingJobLambda, true, nullptr); // Auto-deletes
  346. updateCullingJobQueue.push_back(executeUpdateGroupJob);
  347. }
  348. return updateCullingJobQueue;
  349. }
  350. void MeshFeatureProcessor::ExecuteCombinedJobQueue(AZStd::span<Job*> initQueue, AZStd::span<Job*> updateCullingQueue, Job* parentJob)
  351. {
  352. AZ::JobCompletion jobCompletion;
  353. for (size_t i = 0; i < initQueue.size(); ++i)
  354. {
  355. // Update Culling work should happen after Init is done
  356. initQueue[i]->SetDependent(updateCullingQueue[i]);
  357. // FeatureProcessor::Simulate is optionally run with a parent job.
  358. if (parentJob)
  359. {
  360. // When a parent job is used, we set dependencies on it and use WaitForChildren to wait for them to finish executing
  361. parentJob->StartAsChild(updateCullingQueue[i]);
  362. initQueue[i]->Start();
  363. }
  364. else
  365. {
  366. // When a parent job is not used, we use a job completion to synchronize
  367. updateCullingQueue[i]->SetDependent(&jobCompletion);
  368. initQueue[i]->Start();
  369. updateCullingQueue[i]->Start();
  370. }
  371. }
  372. if (parentJob)
  373. {
  374. parentJob->WaitForChildren();
  375. }
  376. else
  377. {
  378. jobCompletion.StartAndWaitForCompletion();
  379. }
  380. }
  381. void MeshFeatureProcessor::ExecuteSimulateJobQueue(AZStd::span<Job*> jobQueue, Job* parentJob)
  382. {
  383. AZ::JobCompletion jobCompletion;
  384. for (Job* childJob : jobQueue)
  385. {
  386. // FeatureProcessor::Simulate is optionally run with a parent job.
  387. if (parentJob)
  388. {
  389. // When a parent job is used, we set dependencies on it and use WaitForChildren to wait for them to finish executing
  390. parentJob->StartAsChild(childJob);
  391. }
  392. else
  393. {
  394. // When a parent job is not used, we use a job completion to synchronize
  395. childJob->SetDependent(&jobCompletion);
  396. childJob->Start();
  397. }
  398. }
  399. if (parentJob)
  400. {
  401. parentJob->WaitForChildren();
  402. }
  403. else
  404. {
  405. jobCompletion.StartAndWaitForCompletion();
  406. }
  407. }
  408. void MeshFeatureProcessor::OnEndCulling(const MeshFeatureProcessor::RenderPacket& packet)
  409. {
  410. if (r_meshInstancingEnabled)
  411. {
  412. AZ_PROFILE_SCOPE(RPI, "MeshFeatureProcessor: OnEndCulling");
  413. // If necessary, allocate memory up front for the work that needs to be done this frame
  414. ResizePerViewInstanceVectors(packet.m_views.size());
  415. {
  416. // Iterate over all of the visible objects for each view, and perform the first stage of the bucket sort
  417. // where each visible object is sorted into its bucket
  418. AZ_PROFILE_SCOPE(RPI, "MeshFeatureProcessor: Add Visible Objects to Buckets");
  419. AZ::TaskGraphEvent addVisibleObjectsToBucketsTGEvent{ "AddVisibleObjectsToBuckets Wait" };
  420. AZ::TaskGraph addVisibleObjectsToBucketsTG{ "AddVisibleObjectsToBuckets" };
  421. for (size_t viewIndex = 0; viewIndex < packet.m_views.size(); ++viewIndex)
  422. {
  423. AddVisibleObjectsToBuckets(addVisibleObjectsToBucketsTG, viewIndex, packet.m_views[viewIndex]);
  424. }
  425. addVisibleObjectsToBucketsTG.Submit(&addVisibleObjectsToBucketsTGEvent);
  426. addVisibleObjectsToBucketsTGEvent.Wait();
  427. }
  428. {
  429. // Now that the buckets have been filled, create a task for each bucket to sort each individual bucket in parallel
  430. AZ_PROFILE_SCOPE(RPI, "MeshFeatureProcessor: Sort Buckets");
  431. AZ::TaskGraphEvent sortInstanceBufferBucketsTGEvent{ "SortInstanceBufferBuckets Wait" };
  432. AZ::TaskGraph sortInstanceBufferBucketsTG{ "SortInstanceBufferBuckets" };
  433. for (size_t viewIndex = 0; viewIndex < packet.m_views.size(); ++viewIndex)
  434. {
  435. SortInstanceBufferBuckets(sortInstanceBufferBucketsTG, viewIndex);
  436. }
  437. // submit the tasks
  438. sortInstanceBufferBucketsTG.Submit(&sortInstanceBufferBucketsTGEvent);
  439. sortInstanceBufferBucketsTGEvent.Wait();
  440. }
  441. {
  442. // For each bucket, create a task to iterate over the instance buffer to calculate the offset and count
  443. // to use with each instanced draw call, and add the draw calls to the view.
  444. AZ_PROFILE_SCOPE(RPI, "MeshFeatureProcessor: Build Instance Buffer and Draw Calls");
  445. AZ::TaskGraphEvent buildInstanceBufferTGEvent{ "BuildInstanceBuffer Wait" };
  446. AZ::TaskGraph buildInstanceBufferTG{ "BuildInstanceBuffer" };
  447. for (size_t viewIndex = 0; viewIndex < packet.m_views.size(); ++viewIndex)
  448. {
  449. BuildInstanceBufferAndDrawCalls(buildInstanceBufferTG, viewIndex, packet.m_views[viewIndex]);
  450. }
  451. // submit the tasks
  452. buildInstanceBufferTG.Submit(&buildInstanceBufferTGEvent);
  453. buildInstanceBufferTGEvent.Wait();
  454. }
  455. for (size_t viewIndex = 0; viewIndex < packet.m_views.size(); ++viewIndex)
  456. {
  457. // Now that the per-view instance buffers are up to date on the CPU, update them on the GPU
  458. UpdateGPUInstanceBufferForView(viewIndex, packet.m_views[viewIndex]);
  459. }
  460. }
  461. }
  462. void MeshFeatureProcessor::ResizePerViewInstanceVectors(size_t viewCount)
  463. {
  464. AZ_PROFILE_SCOPE(RPI, "MeshFeatureProcessor: ResizePerInstanceVectors");
  465. // Initialize the instance data if it hasn't been created yet
  466. if (m_perViewInstanceData.size() <= viewCount)
  467. {
  468. m_perViewInstanceData.resize(
  469. viewCount, AZStd::vector<TransformServiceFeatureProcessorInterface::ObjectId>());
  470. }
  471. if (m_perViewInstanceGroupBuckets.size() <= viewCount)
  472. {
  473. m_perViewInstanceGroupBuckets.resize(viewCount, AZStd::vector<InstanceGroupBucket>());
  474. }
  475. // Initialize the buffer handler if it hasn't been created yet
  476. if (m_perViewInstanceDataBufferHandlers.size() <= viewCount)
  477. {
  478. GpuBufferHandler::Descriptor desc;
  479. desc.m_bufferName = "MeshInstanceDataBuffer";
  480. desc.m_bufferSrgName = "m_instanceData";
  481. desc.m_elementSize = sizeof(uint32_t);
  482. desc.m_srgLayout = RPI::RPISystemInterface::Get()->GetViewSrgLayout().get();
  483. m_perViewInstanceDataBufferHandlers.reserve(viewCount);
  484. while (m_perViewInstanceDataBufferHandlers.size() < viewCount)
  485. {
  486. // We construct and add these one at a time instead of a single call to resize
  487. // because copying a GpuBufferHandler will result in a new one that refers to the same buffer,
  488. // and we want a unique GpuBufferHandler referring to a unique buffer for each view.
  489. m_perViewInstanceDataBufferHandlers.push_back(GpuBufferHandler(desc));
  490. }
  491. }
  492. AZStd::vector<uint32_t> perBucketInstanceCounts;
  493. const auto instanceManagerRanges = m_meshInstanceManager.GetParallelRanges();
  494. if (instanceManagerRanges.size() > 0)
  495. {
  496. // Resize the per-bucket data vectors for every view
  497. for (AZStd::vector<InstanceGroupBucket>& perViewInstanceGroupBuckets : m_perViewInstanceGroupBuckets)
  498. {
  499. // Get the max page index (bucket count) by looking at the index of the very last page
  500. // This is slightly conservative, as the StableDynamicArray in the MeshInstanceManager will always
  501. // increment the page count to get the index of a new page, but it will never decrement the page count
  502. // it or re-use the index of and existing page after it is freed, so that could result in some extra buckets
  503. // here that are ultimately unused. But the MeshInstanceManager is never releasing unused pages, so that won't
  504. // be an issue.
  505. uint32_t bucketCount = static_cast<uint32_t>(instanceManagerRanges.back().m_begin.GetPageIndex()) + 1;
  506. perViewInstanceGroupBuckets.resize(bucketCount);
  507. perBucketInstanceCounts.resize(bucketCount, 0);
  508. for (InstanceGroupBucket& instanceGroupBucket : perViewInstanceGroupBuckets)
  509. {
  510. instanceGroupBucket.m_currentElementIndex = 0;
  511. instanceGroupBucket.m_sortInstanceData.clear();
  512. }
  513. }
  514. }
  515. else
  516. {
  517. // If there are no buckets, clear them
  518. for (AZStd::vector<InstanceGroupBucket>& perViewInstanceGroupBuckets : m_perViewInstanceGroupBuckets)
  519. {
  520. perViewInstanceGroupBuckets.clear();
  521. }
  522. }
  523. for (const auto& iteratorRange : instanceManagerRanges)
  524. {
  525. uint32_t maxPossibleInstanceCountForGroup = 0;
  526. for (auto instanceGroupDataIter = iteratorRange.m_begin; instanceGroupDataIter != iteratorRange.m_end;
  527. ++instanceGroupDataIter)
  528. {
  529. // Resize the cloned draw packet vector so that there is a unique drawItem for each view
  530. instanceGroupDataIter->m_perViewDrawPackets.resize(viewCount);
  531. maxPossibleInstanceCountForGroup += instanceGroupDataIter->m_count;
  532. }
  533. perBucketInstanceCounts[iteratorRange.m_begin.GetPageIndex()] = maxPossibleInstanceCountForGroup;
  534. }
  535. // Resize the per-bucket data vectors for every view to allow for all possible objects to be visible
  536. for (size_t viewIndex = 0; viewIndex < viewCount; ++viewIndex)
  537. {
  538. AZStd::vector<InstanceGroupBucket>& currentViewInstanceGroupBuckets = m_perViewInstanceGroupBuckets[viewIndex];
  539. for (size_t bucketIndex = 0; bucketIndex < currentViewInstanceGroupBuckets.size(); ++bucketIndex)
  540. {
  541. // Reserve enough memory to handle the case where all of the objects are visible
  542. // We use resize_no_construct instead of reserve + push_back so that we can use an
  543. // atomic index to insert the data lock-free from multiple threads.
  544. uint32_t maxPossibleObjects = perBucketInstanceCounts[bucketIndex];
  545. currentViewInstanceGroupBuckets[bucketIndex].m_sortInstanceData.resize_no_construct(maxPossibleObjects);
  546. }
  547. }
  548. }
  549. void MeshFeatureProcessor::SetLightingChannelMask(const MeshHandle& meshHandle, uint32_t lightingChannelMask)
  550. {
  551. if (meshHandle.IsValid())
  552. {
  553. meshHandle->SetLightingChannelMask(lightingChannelMask);
  554. }
  555. }
  556. uint32_t MeshFeatureProcessor::GetLightingChannelMask(const MeshHandle& meshHandle) const
  557. {
  558. if (meshHandle.IsValid())
  559. {
  560. return meshHandle->GetLightingChannelMask();
  561. }
  562. else
  563. {
  564. AZ_Assert(false, "Invalid mesh handle");
  565. return 1;
  566. }
  567. }
  568. void MeshFeatureProcessor::AddVisibleObjectsToBuckets(
  569. TaskGraph& addVisibleObjectsToBucketsTG, size_t viewIndex, const RPI::ViewPtr& view)
  570. {
  571. AZ_PROFILE_SCOPE(RPI, "MeshFeatureProcessor: AddVisibleObjectsToBuckets");
  572. size_t visibleObjectCount = view->GetVisibleObjectList().size();
  573. AZStd::vector<TransformServiceFeatureProcessorInterface::ObjectId>& perViewInstanceData = m_perViewInstanceData[viewIndex];
  574. if (visibleObjectCount > 0)
  575. {
  576. perViewInstanceData.clear();
  577. static const AZ::TaskDescriptor addVisibleObjectsToBucketsTaskDescriptor{
  578. "AZ::Render::MeshFeatureProcessor::OnEndCulling - AddVisibleObjectsToBuckets", "Graphics"
  579. };
  580. size_t batchSize = r_meshInstancingBucketSortScatterBatchSize;
  581. size_t batchCount = AZ::DivideAndRoundUp(visibleObjectCount, batchSize);
  582. for (size_t batchIndex = 0; batchIndex < batchCount; ++batchIndex)
  583. {
  584. size_t batchStart = batchIndex * batchSize;
  585. // If we're in the last batch, we just get the remaining objects
  586. size_t currentBatchCount = batchIndex == batchCount - 1 ? visibleObjectCount - batchStart : batchSize;
  587. addVisibleObjectsToBucketsTG.AddTask(
  588. addVisibleObjectsToBucketsTaskDescriptor,
  589. [this, view, viewIndex, batchStart, currentBatchCount]()
  590. {
  591. RPI::VisibleObjectListView visibilityList = view->GetVisibleObjectList();
  592. AZStd::vector<InstanceGroupBucket>& currentViewInstanceGroupBuckets = m_perViewInstanceGroupBuckets[viewIndex];
  593. for (size_t i = batchStart; i < batchStart + currentBatchCount; ++i)
  594. {
  595. const RPI::VisibleObjectProperties& visibleObject = visibilityList[i];
  596. const ModelDataInstance::PostCullingInstanceDataList* postCullingInstanceDataList =
  597. static_cast<const ModelDataInstance::PostCullingInstanceDataList*>(visibleObject.m_userData);
  598. for (const ModelDataInstance::PostCullingInstanceData& postCullingData : *postCullingInstanceDataList)
  599. {
  600. SortInstanceData instanceData;
  601. instanceData.m_instanceGroupHandle = postCullingData.m_instanceGroupHandle;
  602. instanceData.m_objectId = postCullingData.m_objectId;
  603. instanceData.m_depth = visibleObject.m_depth;
  604. // Sort transparent objects in reverse by making their depths negative.
  605. if (instanceData.m_instanceGroupHandle->m_isTransparent)
  606. {
  607. instanceData.m_depth *= -1.0f;
  608. }
  609. // Add the sort data to the bucket
  610. InstanceGroupBucket& instanceGroupBucket =
  611. currentViewInstanceGroupBuckets[postCullingData.m_instanceGroupPageIndex];
  612. // Use an atomic operation to determine where to insert this sort data
  613. uint32_t currentIndex = instanceGroupBucket.m_currentElementIndex++;
  614. instanceGroupBucket.m_sortInstanceData[currentIndex] = instanceData;
  615. }
  616. }
  617. });
  618. }
  619. }
  620. }
  621. void MeshFeatureProcessor::SortInstanceBufferBuckets(TaskGraph& sortInstanceBufferBucketsTG, size_t viewIndex)
  622. {
  623. AZ_PROFILE_SCOPE(RPI, "MeshFeatureProcessor: SortInstanceBufferBuckets");
  624. AZStd::vector<InstanceGroupBucket>& currentViewInstanceGroupBuckets = m_perViewInstanceGroupBuckets[viewIndex];
  625. // Populate a task graph where each task is responsible for sorting a bucket.
  626. static const AZ::TaskDescriptor sortInstanceBufferBucketsTaskDescriptor{
  627. "AZ::Render::MeshFeatureProcessor::OnEndCulling - sort instance data buckets", "Graphics"
  628. };
  629. for (InstanceGroupBucket& instanceGroupBucket : currentViewInstanceGroupBuckets)
  630. {
  631. // We're creating one task per bucket here. That is ideal when the buckets are all close to the same size,
  632. // but it can lead to an imperfect distribution of work if one bucket has more objects than any of the others.
  633. // If this becomes a performance bottleneck, it could be alleviated by adding an heuristic to sort any overfull
  634. // buckets using a parallel std sort rather than using a single task, or by breaking it up into smaller buckets.
  635. sortInstanceBufferBucketsTG.AddTask(
  636. sortInstanceBufferBucketsTaskDescriptor,
  637. [&instanceGroupBucket]()
  638. {
  639. // Note: we've previously resized m_sortInstanceData to conservatively fit all possible visible meshes for the bucket,
  640. // which allowed us to use an atomic index for parallel lock free insertion.
  641. // As a result, m_sortInstanceData it has a greater size than the actual count.
  642. // We only care about the real visible objects, so cut off the last unused elements here
  643. instanceGroupBucket.m_sortInstanceData.resize(instanceGroupBucket.m_currentElementIndex);
  644. // Sort within the bucket
  645. std::sort(instanceGroupBucket.m_sortInstanceData.begin(), instanceGroupBucket.m_sortInstanceData.end());
  646. });
  647. }
  648. }
  649. static void AddInstancedDrawPacketToView(
  650. const RPI::ViewPtr& view,
  651. size_t viewIndex,
  652. ModelDataInstance::InstanceGroupHandle instanceGroupHandle,
  653. float accumulatedDepth,
  654. uint32_t instanceGroupBeginIndex,
  655. uint32_t instanceGroupEndNonInclusiveIndex)
  656. {
  657. MeshInstanceGroupData& instanceGroup = *instanceGroupHandle;
  658. // Each task is working on a page of instance groups, but
  659. // there is also one task per-view. So there may be multiple
  660. // threads accessing the intance group here, so we must use a lock to protect it.
  661. // We could potentially handle all views for a given bucket of instance groups
  662. // In a single task, which would negate the need to lock here
  663. if (instanceGroup.m_perViewDrawPackets.size() <= viewIndex)
  664. {
  665. AZStd::scoped_lock meshDataLock(instanceGroup.m_eventLock);
  666. instanceGroup.m_perViewDrawPackets.resize(viewIndex + 1);
  667. }
  668. // Cache a cloned drawpacket here
  669. if (!instanceGroup.m_perViewDrawPackets[viewIndex])
  670. {
  671. // Since there is only one task that will operate both on this view index and on the bucket with this instance group,
  672. // there is no need to lock here.
  673. RHI::DrawPacketBuilder drawPacketBuilder{RHI::MultiDevice::AllDevices};
  674. instanceGroup.m_perViewDrawPackets[viewIndex] = drawPacketBuilder.Clone(instanceGroup.m_drawPacket.GetRHIDrawPacket());
  675. }
  676. // Now that we have a valid cloned draw packet, update it with the latest offset + count
  677. RHI::Ptr<RHI::DrawPacket> clonedDrawPacket = instanceGroup.m_perViewDrawPackets[viewIndex];
  678. // Set the instance data offset
  679. AZStd::span<uint8_t> data{ reinterpret_cast<uint8_t*>(&instanceGroupBeginIndex), sizeof(uint32_t) };
  680. clonedDrawPacket->SetRootConstant(instanceGroup.m_drawRootConstantOffset, data);
  681. // instanceGroupEndNonInclusiveIndex is the first index after the current group ends.
  682. uint32_t instanceCount = instanceGroupEndNonInclusiveIndex - instanceGroupBeginIndex;
  683. // Set the cloned draw packet instance count
  684. clonedDrawPacket->SetInstanceCount(instanceCount);
  685. float averageDepth = accumulatedDepth / static_cast<float>(instanceCount);
  686. // Depth values from the camera are always positive.
  687. // However, we use negative values to sort by reverse depth for transparent objects
  688. // If the average depth is negative (this instance group is transparent), make it positive to get the real average depth for the group
  689. averageDepth = AZStd::abs(averageDepth);
  690. // Submit the draw packet
  691. view->AddDrawPacket(clonedDrawPacket.get(), averageDepth);
  692. }
  693. void MeshFeatureProcessor::BuildInstanceBufferAndDrawCalls(
  694. TaskGraph& buildInstanceBufferTG, size_t viewIndex, const RPI::ViewPtr& view)
  695. {
  696. AZStd::vector<TransformServiceFeatureProcessorInterface::ObjectId>& perViewInstanceData = m_perViewInstanceData[viewIndex];
  697. AZStd::vector<InstanceGroupBucket>& currentViewInstanceGroupBuckets = m_perViewInstanceGroupBuckets[viewIndex];
  698. uint32_t currentBatchStart = 0;
  699. for (InstanceGroupBucket& instanceGroupBucket : currentViewInstanceGroupBuckets)
  700. {
  701. if (instanceGroupBucket.m_currentElementIndex > 0)
  702. {
  703. static const AZ::TaskDescriptor buildInstanceBufferTaskDescriptor{
  704. "AZ::Render::MeshFeatureProcessor::OnEndCulling - process instance data", "Graphics"
  705. };
  706. // Process data up to but not including actualEndOffset
  707. buildInstanceBufferTG.AddTask(
  708. buildInstanceBufferTaskDescriptor,
  709. [currentBatchStart,
  710. viewIndex,
  711. &view,
  712. &perViewInstanceData, &instanceGroupBucket]()
  713. {
  714. ModelDataInstance::InstanceGroupHandle currentInstanceGroup =
  715. instanceGroupBucket.m_sortInstanceData.begin()->m_instanceGroupHandle;
  716. uint32_t instanceDataOffset = currentBatchStart;
  717. float accumulatedDepth = 0.0f;
  718. uint32_t instanceDataIndex = currentBatchStart;
  719. for (SortInstanceData& sortInstanceData : instanceGroupBucket.m_sortInstanceData)
  720. {
  721. // Anytime the instance group changes, submit a draw for the previous group
  722. if (sortInstanceData.m_instanceGroupHandle != currentInstanceGroup)
  723. {
  724. AddInstancedDrawPacketToView(
  725. view, viewIndex, currentInstanceGroup, accumulatedDepth, instanceDataOffset, instanceDataIndex);
  726. // Update the loop trackers
  727. accumulatedDepth = 0.0f;
  728. instanceDataOffset = instanceDataIndex;
  729. currentInstanceGroup = sortInstanceData.m_instanceGroupHandle;
  730. }
  731. perViewInstanceData[instanceDataIndex] = sortInstanceData.m_objectId;
  732. accumulatedDepth += sortInstanceData.m_depth;
  733. instanceDataIndex++;
  734. }
  735. // Submit the last instance group
  736. {
  737. AddInstancedDrawPacketToView(
  738. view, viewIndex, currentInstanceGroup, accumulatedDepth, instanceDataOffset, instanceDataIndex);
  739. }
  740. });
  741. // At this point, inserting into the bucket is already complete, so m_currentElementIndex represents the count of all visible meshes in this bucket.
  742. currentBatchStart += instanceGroupBucket.m_currentElementIndex;
  743. }
  744. }
  745. // currentBatchStart now represents the total count of visible instances in this view.
  746. // Re-size the instance data buffer so that we can fill it with the tasks created above
  747. perViewInstanceData.resize_no_construct(currentBatchStart);
  748. }
  749. void MeshFeatureProcessor::UpdateGPUInstanceBufferForView(size_t viewIndex, const RPI::ViewPtr& view)
  750. {
  751. AZ_PROFILE_SCOPE(RPI, "MeshFeatureProcessor: UpdateGPUInstanceBufferForView");
  752. // Use the correct srg for the view
  753. GpuBufferHandler& instanceDataBufferHandler = m_perViewInstanceDataBufferHandlers[viewIndex];
  754. instanceDataBufferHandler.UpdateSrg(view->GetShaderResourceGroup().get());
  755. // Now that we have all of our instance data, we need to create the buffer and bind it to the view srgs
  756. // Eventually, this could be a transient buffer
  757. // create output buffer descriptors
  758. AZStd::vector<TransformServiceFeatureProcessorInterface::ObjectId>& perViewInstanceData = m_perViewInstanceData[viewIndex];
  759. instanceDataBufferHandler.UpdateBuffer(perViewInstanceData.data(), static_cast<uint32_t>(perViewInstanceData.size()));
  760. }
  761. void MeshFeatureProcessor::OnBeginPrepareRender()
  762. {
  763. m_meshDataChecker.soft_lock();
  764. // The per-mesh shader option flags are set in feature processors' simulate function
  765. // So we want to process the flags here to update the draw packets if needed.
  766. // Update MeshDrawPacket's shader options if PerMeshShaderOption is enabled
  767. if (r_enablePerMeshShaderOptionFlags || m_enablePerMeshShaderOptionFlags)
  768. {
  769. // For mesh instance groups when r_meshInstancingEnabled is enabled
  770. AZStd::vector<ModelDataInstance::InstanceGroupHandle> instanceGroupsNeedUpdate;
  771. // Per mesh shader option flags was on, but now turned off, so reset all the shader options.
  772. for (auto& modelHandle : m_modelData)
  773. {
  774. if (modelHandle.m_cullable.m_prevShaderOptionFlags != modelHandle.m_cullable.m_shaderOptionFlags)
  775. {
  776. // skip if the model need to be initialized
  777. if (modelHandle.m_flags.m_needsInit)
  778. {
  779. continue;
  780. }
  781. if (!r_meshInstancingEnabled)
  782. {
  783. for (RPI::MeshDrawPacketList& drawPacketList : modelHandle.m_drawPacketListsByLod)
  784. {
  785. for (RPI::MeshDrawPacket& drawPacket : drawPacketList)
  786. {
  787. m_flagRegistry->VisitTags(
  788. [&](AZ::Name shaderOption, FlagRegistry::TagType tag)
  789. {
  790. bool shaderOptionValue = (modelHandle.m_cullable.m_shaderOptionFlags & tag.GetIndex()) > 0;
  791. drawPacket.SetShaderOption(shaderOption, AZ::RPI::ShaderOptionValue(shaderOptionValue));
  792. });
  793. drawPacket.Update(*GetParentScene(), true);
  794. }
  795. }
  796. modelHandle.m_flags.m_cullableNeedsRebuild = true;
  797. // [GHI-13619]
  798. // Update the draw packets on the cullable, since we just set a shader item.
  799. // BuildCullable is a bit overkill here, this could be reduced to just updating the drawPacket specific info
  800. // It's also going to cause m_cullableNeedsUpdate to be set, which will execute next frame, which we don't need
  801. modelHandle.BuildCullable();
  802. }
  803. else
  804. {
  805. // mark the instance groups which need to update their shader options
  806. for (size_t lodIndex = 0; lodIndex < modelHandle.m_postCullingInstanceDataByLod.size(); ++lodIndex)
  807. {
  808. ModelDataInstance::PostCullingInstanceDataList& postCullingInstanceDataList =
  809. modelHandle.m_postCullingInstanceDataByLod[lodIndex];
  810. for (const ModelDataInstance::PostCullingInstanceData& postCullingData : postCullingInstanceDataList)
  811. {
  812. instanceGroupsNeedUpdate.push_back(postCullingData.m_instanceGroupHandle);
  813. }
  814. }
  815. }
  816. }
  817. }
  818. if (r_meshInstancingEnabled)
  819. {
  820. for (auto& instanceGroupDataIter : instanceGroupsNeedUpdate)
  821. {
  822. // default values for when r_enablePerMeshShaderOptionFlags was set from true to false
  823. bool shaderOptionFlagsChanged = true;
  824. uint32_t shaderOptionFlagMask = 0; // 0 means disable all shader options
  825. if (r_enablePerMeshShaderOptionFlags)
  826. {
  827. shaderOptionFlagsChanged = instanceGroupDataIter->UpdateShaderOptionFlags();
  828. shaderOptionFlagMask = instanceGroupDataIter->m_shaderOptionFlagMask;
  829. }
  830. if (shaderOptionFlagsChanged)
  831. {
  832. // Set shader options here
  833. m_flagRegistry->VisitTags(
  834. [&](AZ::Name shaderOption, FlagRegistry::TagType tag)
  835. {
  836. if ((shaderOptionFlagMask & tag.GetIndex()) > 0)
  837. {
  838. bool shaderOptionValue = (instanceGroupDataIter->m_shaderOptionFlags & tag.GetIndex()) > 0;
  839. instanceGroupDataIter->m_drawPacket.SetShaderOption(
  840. shaderOption, AZ::RPI::ShaderOptionValue(shaderOptionValue));
  841. }
  842. else
  843. {
  844. instanceGroupDataIter->m_drawPacket.UnsetShaderOption(shaderOption);
  845. }
  846. });
  847. instanceGroupDataIter->UpdateDrawPacket(*GetParentScene(), true);
  848. // Note, we don't need to call CacheRootConstantInterval() here because the root constant layout won't change
  849. // when we switch shader variants.
  850. }
  851. }
  852. }
  853. }
  854. m_enablePerMeshShaderOptionFlags = r_enablePerMeshShaderOptionFlags;
  855. }
  856. void MeshFeatureProcessor::OnEndPrepareRender()
  857. {
  858. m_meshDataChecker.soft_unlock();
  859. if (m_reportShaderOptionFlags)
  860. {
  861. m_reportShaderOptionFlags = false;
  862. PrintShaderOptionFlags();
  863. }
  864. for (auto& model : m_modelData)
  865. {
  866. model.m_cullable.m_prevShaderOptionFlags = model.m_cullable.m_shaderOptionFlags.exchange(0);
  867. model.m_cullable.m_flags = model.m_flags.m_isAlwaysDynamic ? m_meshMovedFlag.GetIndex() : 0;
  868. }
  869. }
  870. MeshFeatureProcessor::MeshHandle MeshFeatureProcessor::AcquireMesh(const MeshHandleDescriptor& descriptor)
  871. {
  872. AZ_PROFILE_SCOPE(AzRender, "MeshFeatureProcessor: AcquireMesh");
  873. // don't need to check the concurrency during emplace() because the StableDynamicArray won't move the other elements during
  874. // insertion
  875. MeshHandle meshDataHandle = m_modelData.emplace();
  876. meshDataHandle->m_descriptor = descriptor;
  877. meshDataHandle->m_descriptor.m_modelChangedEventHandler.Connect(meshDataHandle->m_modelChangedEvent);
  878. meshDataHandle->m_descriptor.m_objectSrgCreatedHandler.Connect(meshDataHandle->m_objectSrgCreatedEvent);
  879. meshDataHandle->m_scene = GetParentScene();
  880. meshDataHandle->m_objectId = m_transformService->ReserveObjectId();
  881. meshDataHandle->m_rayTracingUuid = AZ::Uuid::CreateRandom();
  882. meshDataHandle->m_originalModelAsset = descriptor.m_modelAsset;
  883. meshDataHandle->m_flags.m_keepBufferAssetsInMemory = descriptor.m_supportRayIntersection; // Note: the MeshLoader may need to read this flag. so it needs to be assigned because meshloader is created
  884. meshDataHandle->m_meshLoader = AZStd::make_shared<ModelDataInstance::MeshLoader>(descriptor.m_modelAsset, &*meshDataHandle);
  885. meshDataHandle->m_flags.m_isAlwaysDynamic = descriptor.m_isAlwaysDynamic;
  886. meshDataHandle->m_flags.m_isDrawMotion = descriptor.m_isAlwaysDynamic;
  887. if (descriptor.m_excludeFromReflectionCubeMaps)
  888. {
  889. meshDataHandle->m_cullable.m_cullData.m_hideFlags |= RPI::View::UsageReflectiveCubeMap;
  890. }
  891. return meshDataHandle;
  892. }
  893. bool MeshFeatureProcessor::ReleaseMesh(MeshHandle& meshHandle)
  894. {
  895. if (meshHandle.IsValid())
  896. {
  897. meshHandle->m_meshLoader.reset();
  898. meshHandle->DeInit(this);
  899. m_transformService->ReleaseObjectId(meshHandle->m_objectId);
  900. AZStd::concurrency_check_scope scopeCheck(m_meshDataChecker);
  901. m_modelData.erase(meshHandle);
  902. return true;
  903. }
  904. return false;
  905. }
  906. void MeshFeatureProcessor::SetDrawItemEnabled(const MeshHandle& meshHandle, RHI::DrawListTag drawListTag, bool enabled)
  907. {
  908. AZ::RPI::MeshDrawPacketLods& drawPacketListByLod = meshHandle.IsValid() && !r_meshInstancingEnabled ? meshHandle->m_drawPacketListsByLod : m_emptyDrawPacketLods;
  909. for (AZ::RPI::MeshDrawPacketList& drawPacketList : drawPacketListByLod)
  910. {
  911. for (AZ::RPI::MeshDrawPacket& meshDrawPacket : drawPacketList)
  912. {
  913. RHI::DrawPacket* drawPacket = meshDrawPacket.GetRHIDrawPacket();
  914. if (drawPacket != nullptr)
  915. {
  916. size_t drawItemCount = drawPacket->GetDrawItemCount();
  917. for (size_t idx = 0; idx < drawItemCount; ++idx)
  918. {
  919. // Ensure that the draw item belongs to the specified tag
  920. if (drawPacket->GetDrawListTag(idx) == drawListTag)
  921. {
  922. drawPacket->GetDrawItem(idx)->SetEnabled(enabled);
  923. }
  924. }
  925. }
  926. }
  927. }
  928. }
  929. void MeshFeatureProcessor::PrintDrawPacketInfo(const MeshHandle& meshHandle)
  930. {
  931. AZStd::string stringOutput = "\n------- MESH INFO -------\n";
  932. AZ::RPI::MeshDrawPacketLods& drawPacketListByLod = meshHandle.IsValid() && !r_meshInstancingEnabled ? meshHandle->m_drawPacketListsByLod : m_emptyDrawPacketLods;
  933. u32 lodCounter = 0;
  934. for (AZ::RPI::MeshDrawPacketList& drawPacketList : drawPacketListByLod)
  935. {
  936. stringOutput += AZStd::string::format("--- Mesh Lod %u ---\n", lodCounter++);
  937. u32 drawPacketCounter = 0;
  938. for (AZ::RPI::MeshDrawPacket& meshDrawPacket : drawPacketList)
  939. {
  940. RHI::DrawPacket* drawPacket = meshDrawPacket.GetRHIDrawPacket();
  941. if (drawPacket)
  942. {
  943. size_t numDrawItems = drawPacket->GetDrawItemCount();
  944. stringOutput += AZStd::string::format("-- Draw Packet %u (%zu Draw Items) --\n", drawPacketCounter++, numDrawItems);
  945. for (size_t drawItemIdx = 0; drawItemIdx < numDrawItems; ++drawItemIdx)
  946. {
  947. RHI::DrawItem* drawItem = drawPacket->GetDrawItem(drawItemIdx);
  948. RHI::DrawListTag tag = drawPacket->GetDrawListTag(drawItemIdx);
  949. stringOutput += AZStd::string::format("Item %zu | ", drawItemIdx);
  950. stringOutput += drawItem->GetEnabled() ? "Enabled | " : "Disabled | ";
  951. stringOutput += AZStd::string::format("%s Tag\n", RHI::GetDrawListName(tag).GetCStr());
  952. }
  953. }
  954. }
  955. }
  956. stringOutput += "\n";
  957. AZ_Printf("MeshFeatureProcessor", stringOutput.c_str());
  958. }
  959. MeshFeatureProcessor::MeshHandle MeshFeatureProcessor::CloneMesh(const MeshHandle& meshHandle)
  960. {
  961. if (meshHandle.IsValid())
  962. {
  963. return AcquireMesh(meshHandle->m_descriptor);
  964. }
  965. return MeshFeatureProcessor::MeshHandle();
  966. }
  967. Data::Instance<RPI::Model> MeshFeatureProcessor::GetModel(const MeshHandle& meshHandle) const
  968. {
  969. return meshHandle.IsValid() ? meshHandle->m_model : nullptr;
  970. }
  971. Data::Asset<RPI::ModelAsset> MeshFeatureProcessor::GetModelAsset(const MeshHandle& meshHandle) const
  972. {
  973. if (meshHandle.IsValid())
  974. {
  975. return meshHandle->m_originalModelAsset;
  976. }
  977. return {};
  978. }
  979. const RPI::MeshDrawPacketLods& MeshFeatureProcessor::GetDrawPackets(const MeshHandle& meshHandle) const
  980. {
  981. // This function is being deprecated. It's currently used to get draw packets so that we can print some
  982. // debug information about the draw packets in an imgui menu. But the ownership model for draw packets is changing.
  983. // We can no longer assume a meshHandle directly keeps a copy of all of its draw packets.
  984. return meshHandle.IsValid() && !r_meshInstancingEnabled ? meshHandle->m_drawPacketListsByLod : m_emptyDrawPacketLods;
  985. }
  986. const AZStd::vector<Data::Instance<RPI::ShaderResourceGroup>>& MeshFeatureProcessor::GetObjectSrgs(const MeshHandle& meshHandle) const
  987. {
  988. static AZStd::vector<Data::Instance<RPI::ShaderResourceGroup>> staticEmptyList;
  989. return meshHandle.IsValid() ? meshHandle->m_objectSrgList : staticEmptyList;
  990. }
  991. void MeshFeatureProcessor::QueueObjectSrgForCompile(const MeshHandle& meshHandle) const
  992. {
  993. if (meshHandle.IsValid())
  994. {
  995. meshHandle->m_flags.m_objectSrgNeedsUpdate = true;
  996. }
  997. }
  998. void MeshFeatureProcessor::SetCustomMaterials(const MeshHandle& meshHandle, const Data::Instance<RPI::Material>& material)
  999. {
  1000. Render::CustomMaterialMap materials;
  1001. materials[AZ::Render::DefaultCustomMaterialId] = { material };
  1002. return SetCustomMaterials(meshHandle, materials);
  1003. }
  1004. void MeshFeatureProcessor::SetCustomMaterials(const MeshHandle& meshHandle, const CustomMaterialMap& materials)
  1005. {
  1006. if (meshHandle.IsValid())
  1007. {
  1008. meshHandle->m_descriptor.m_customMaterials = materials;
  1009. if (meshHandle->m_model)
  1010. {
  1011. meshHandle->ReInit(this);
  1012. }
  1013. meshHandle->m_flags.m_objectSrgNeedsUpdate = true;
  1014. }
  1015. }
  1016. const CustomMaterialMap& MeshFeatureProcessor::GetCustomMaterials(const MeshHandle& meshHandle) const
  1017. {
  1018. return meshHandle.IsValid() ? meshHandle->m_descriptor.m_customMaterials : DefaultCustomMaterialMap;
  1019. }
  1020. void MeshFeatureProcessor::SetTransform(const MeshHandle& meshHandle, const AZ::Transform& transform, const AZ::Vector3& nonUniformScale)
  1021. {
  1022. if (meshHandle.IsValid())
  1023. {
  1024. ModelDataInstance& modelData = *meshHandle;
  1025. modelData.m_flags.m_cullBoundsNeedsUpdate = true;
  1026. modelData.m_flags.m_objectSrgNeedsUpdate = true;
  1027. modelData.m_cullable.m_flags = modelData.m_cullable.m_flags | m_meshMovedFlag.GetIndex();
  1028. // Only set m_dynamic flag if the model instance is initialized.
  1029. if (!modelData.m_flags.m_dynamic)
  1030. {
  1031. modelData.m_flags.m_dynamic = (modelData.m_model && !modelData.m_flags.m_needsInit) ? true : false;
  1032. // Enable draw motion for all the DrawPacket referenced by this model
  1033. if (r_meshInstancingEnabled && modelData.m_flags.m_dynamic)
  1034. {
  1035. for (size_t lodIndex = 0; lodIndex < modelData.m_postCullingInstanceDataByLod.size(); ++lodIndex)
  1036. {
  1037. ModelDataInstance::PostCullingInstanceDataList& postCullingInstanceDataList =
  1038. modelData.m_postCullingInstanceDataByLod[lodIndex];
  1039. for (const ModelDataInstance::PostCullingInstanceData& postCullingData : postCullingInstanceDataList)
  1040. {
  1041. AZStd::scoped_lock<AZStd::mutex> scopedLock(postCullingData.m_instanceGroupHandle->m_eventLock);
  1042. if (!postCullingData.m_instanceGroupHandle->m_isDrawMotion)
  1043. {
  1044. postCullingData.m_instanceGroupHandle->m_isDrawMotion = true;
  1045. postCullingData.m_instanceGroupHandle->m_drawPacket.SetEnableDraw(m_meshMotionDrawListTag, true);
  1046. }
  1047. }
  1048. }
  1049. }
  1050. }
  1051. m_transformService->SetTransformForId(meshHandle->m_objectId, transform, nonUniformScale);
  1052. // ray tracing data needs to be updated with the new transform
  1053. if (m_rayTracingFeatureProcessor)
  1054. {
  1055. m_rayTracingFeatureProcessor->SetMeshTransform(meshHandle->m_rayTracingUuid, transform, nonUniformScale);
  1056. }
  1057. }
  1058. }
  1059. void MeshFeatureProcessor::SetLocalAabb(const MeshHandle& meshHandle, const AZ::Aabb& localAabb)
  1060. {
  1061. if (meshHandle.IsValid())
  1062. {
  1063. ModelDataInstance& modelData = *meshHandle;
  1064. modelData.m_aabb = localAabb;
  1065. modelData.m_flags.m_cullBoundsNeedsUpdate = true;
  1066. modelData.m_flags.m_objectSrgNeedsUpdate = true;
  1067. }
  1068. };
  1069. AZ::Aabb MeshFeatureProcessor::GetLocalAabb(const MeshHandle& meshHandle) const
  1070. {
  1071. if (meshHandle.IsValid())
  1072. {
  1073. return meshHandle->m_aabb;
  1074. }
  1075. else
  1076. {
  1077. AZ_Assert(false, "Invalid mesh handle");
  1078. return Aabb::CreateNull();
  1079. }
  1080. }
  1081. Transform MeshFeatureProcessor::GetTransform(const MeshHandle& meshHandle)
  1082. {
  1083. if (meshHandle.IsValid())
  1084. {
  1085. return m_transformService->GetTransformForId(meshHandle->m_objectId);
  1086. }
  1087. else
  1088. {
  1089. AZ_Assert(false, "Invalid mesh handle");
  1090. return Transform::CreateIdentity();
  1091. }
  1092. }
  1093. Vector3 MeshFeatureProcessor::GetNonUniformScale(const MeshHandle& meshHandle)
  1094. {
  1095. if (meshHandle.IsValid())
  1096. {
  1097. return m_transformService->GetNonUniformScaleForId(meshHandle->m_objectId);
  1098. }
  1099. else
  1100. {
  1101. AZ_Assert(false, "Invalid mesh handle");
  1102. return Vector3::CreateOne();
  1103. }
  1104. }
  1105. void MeshFeatureProcessor::SetSortKey(const MeshHandle& meshHandle, RHI::DrawItemSortKey sortKey)
  1106. {
  1107. if (meshHandle.IsValid())
  1108. {
  1109. meshHandle->SetSortKey(this, sortKey);
  1110. }
  1111. }
  1112. RHI::DrawItemSortKey MeshFeatureProcessor::GetSortKey(const MeshHandle& meshHandle) const
  1113. {
  1114. if (meshHandle.IsValid())
  1115. {
  1116. return meshHandle->GetSortKey();
  1117. }
  1118. else
  1119. {
  1120. AZ_Assert(false, "Invalid mesh handle");
  1121. return 0;
  1122. }
  1123. }
  1124. void ModelDataInstance::SetLightingChannelMask(uint32_t lightingChannelMask)
  1125. {
  1126. m_lightingChannelMask = lightingChannelMask;
  1127. }
  1128. void MeshFeatureProcessor::SetMeshLodConfiguration(const MeshHandle& meshHandle, const RPI::Cullable::LodConfiguration& meshLodConfig)
  1129. {
  1130. if (meshHandle.IsValid())
  1131. {
  1132. meshHandle->SetMeshLodConfiguration(meshLodConfig);
  1133. }
  1134. }
  1135. RPI::Cullable::LodConfiguration MeshFeatureProcessor::GetMeshLodConfiguration(const MeshHandle& meshHandle) const
  1136. {
  1137. if (meshHandle.IsValid())
  1138. {
  1139. return meshHandle->GetMeshLodConfiguration();
  1140. }
  1141. else
  1142. {
  1143. AZ_Assert(false, "Invalid mesh handle");
  1144. return { RPI::Cullable::LodType::Default, 0, 0.0f, 0.0f };
  1145. }
  1146. }
  1147. void MeshFeatureProcessor::SetIsAlwaysDynamic(const MeshHandle & meshHandle, bool isAlwaysDynamic)
  1148. {
  1149. if (meshHandle.IsValid())
  1150. {
  1151. meshHandle->m_flags.m_isAlwaysDynamic = isAlwaysDynamic;
  1152. }
  1153. }
  1154. bool MeshFeatureProcessor::GetIsAlwaysDynamic(const MeshHandle& meshHandle) const
  1155. {
  1156. if (!meshHandle.IsValid())
  1157. {
  1158. AZ_Assert(false, "Invalid mesh handle");
  1159. return false;
  1160. }
  1161. return meshHandle->m_flags.m_isAlwaysDynamic;
  1162. }
  1163. void MeshFeatureProcessor::SetExcludeFromReflectionCubeMaps(const MeshHandle& meshHandle, bool excludeFromReflectionCubeMaps)
  1164. {
  1165. if (meshHandle.IsValid())
  1166. {
  1167. meshHandle->m_descriptor.m_excludeFromReflectionCubeMaps = excludeFromReflectionCubeMaps;
  1168. if (excludeFromReflectionCubeMaps)
  1169. {
  1170. meshHandle->m_cullable.m_cullData.m_hideFlags |= RPI::View::UsageReflectiveCubeMap;
  1171. }
  1172. else
  1173. {
  1174. meshHandle->m_cullable.m_cullData.m_hideFlags &= ~RPI::View::UsageReflectiveCubeMap;
  1175. }
  1176. }
  1177. }
  1178. bool MeshFeatureProcessor::GetExcludeFromReflectionCubeMaps(const MeshHandle& meshHandle) const
  1179. {
  1180. if (meshHandle.IsValid())
  1181. {
  1182. return meshHandle->m_descriptor.m_excludeFromReflectionCubeMaps;
  1183. }
  1184. return false;
  1185. }
  1186. void MeshFeatureProcessor::SetRayTracingEnabled(const MeshHandle& meshHandle, bool enabled)
  1187. {
  1188. if (meshHandle.IsValid())
  1189. {
  1190. // update the ray tracing data based on the current state and the new state
  1191. if (enabled && !meshHandle->m_descriptor.m_isRayTracingEnabled)
  1192. {
  1193. // add to ray tracing
  1194. meshHandle->m_flags.m_needsSetRayTracingData = true;
  1195. }
  1196. else if (!enabled && meshHandle->m_descriptor.m_isRayTracingEnabled)
  1197. {
  1198. // remove from ray tracing
  1199. if (m_rayTracingFeatureProcessor)
  1200. {
  1201. m_rayTracingFeatureProcessor->RemoveMesh(meshHandle->m_rayTracingUuid);
  1202. }
  1203. }
  1204. // set new state
  1205. meshHandle->m_descriptor.m_isRayTracingEnabled = enabled;
  1206. }
  1207. }
  1208. bool MeshFeatureProcessor::GetRayTracingEnabled(const MeshHandle& meshHandle) const
  1209. {
  1210. if (meshHandle.IsValid())
  1211. {
  1212. return meshHandle->m_descriptor.m_isRayTracingEnabled;
  1213. }
  1214. else
  1215. {
  1216. AZ_Assert(false, "Invalid mesh handle");
  1217. return false;
  1218. }
  1219. }
  1220. bool MeshFeatureProcessor::GetVisible(const MeshHandle& meshHandle) const
  1221. {
  1222. if (meshHandle.IsValid())
  1223. {
  1224. return meshHandle->m_flags.m_visible;
  1225. }
  1226. return false;
  1227. }
  1228. void MeshFeatureProcessor::SetVisible(const MeshHandle& meshHandle, bool visible)
  1229. {
  1230. if (meshHandle.IsValid())
  1231. {
  1232. meshHandle->SetVisible(visible);
  1233. if (m_rayTracingFeatureProcessor && meshHandle->m_descriptor.m_isRayTracingEnabled)
  1234. {
  1235. // always remove from ray tracing first
  1236. m_rayTracingFeatureProcessor->RemoveMesh(meshHandle->m_rayTracingUuid);
  1237. // now add if it's visible
  1238. if (visible)
  1239. {
  1240. meshHandle->m_flags.m_needsSetRayTracingData = true;
  1241. }
  1242. }
  1243. }
  1244. }
  1245. void MeshFeatureProcessor::SetUseForwardPassIblSpecular(const MeshHandle& meshHandle, bool useForwardPassIblSpecular)
  1246. {
  1247. if (meshHandle.IsValid())
  1248. {
  1249. meshHandle->m_descriptor.m_useForwardPassIblSpecular = useForwardPassIblSpecular;
  1250. meshHandle->m_flags.m_objectSrgNeedsUpdate = true;
  1251. if (meshHandle->m_model)
  1252. {
  1253. const size_t modelLodCount = meshHandle->m_model->GetLodCount();
  1254. for (size_t modelLodIndex = 0; modelLodIndex < modelLodCount; ++modelLodIndex)
  1255. {
  1256. meshHandle->BuildDrawPacketList(this, modelLodIndex);
  1257. }
  1258. }
  1259. }
  1260. }
  1261. void MeshFeatureProcessor::SetRayTracingDirty(const MeshHandle& meshHandle)
  1262. {
  1263. if (meshHandle.IsValid())
  1264. {
  1265. meshHandle->m_flags.m_needsSetRayTracingData = true;
  1266. }
  1267. }
  1268. RHI::Ptr<MeshFeatureProcessor::FlagRegistry> MeshFeatureProcessor::GetShaderOptionFlagRegistry()
  1269. {
  1270. if (m_flagRegistry == nullptr)
  1271. {
  1272. m_flagRegistry = FlagRegistry::Create();
  1273. }
  1274. return m_flagRegistry;
  1275. };
  1276. void MeshFeatureProcessor::ForceRebuildDrawPackets([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
  1277. {
  1278. m_forceRebuildDrawPackets = true;
  1279. }
  1280. void MeshFeatureProcessor::OnRenderPipelineChanged([[maybe_unused]] RPI::RenderPipeline* pipeline,
  1281. [[maybe_unused]] RPI::SceneNotification::RenderPipelineChangeType changeType)
  1282. {
  1283. m_forceRebuildDrawPackets = true;
  1284. }
  1285. void MeshFeatureProcessor::UpdateMeshReflectionProbes()
  1286. {
  1287. for (auto& meshInstance : m_modelData)
  1288. {
  1289. // we need to rebuild the Srg for any meshes that are using the forward pass IBL specular option
  1290. if (meshInstance.m_descriptor.m_useForwardPassIblSpecular)
  1291. {
  1292. meshInstance.m_flags.m_objectSrgNeedsUpdate = true;
  1293. }
  1294. // update the raytracing reflection probe data if necessary
  1295. RayTracingFeatureProcessor::Mesh::ReflectionProbe reflectionProbe;
  1296. bool currentHasRayTracingReflectionProbe = meshInstance.m_flags.m_hasRayTracingReflectionProbe;
  1297. meshInstance.SetRayTracingReflectionProbeData(this, reflectionProbe);
  1298. if (meshInstance.m_flags.m_hasRayTracingReflectionProbe ||
  1299. (currentHasRayTracingReflectionProbe != meshInstance.m_flags.m_hasRayTracingReflectionProbe))
  1300. {
  1301. m_rayTracingFeatureProcessor->SetMeshReflectionProbe(meshInstance.m_rayTracingUuid, reflectionProbe);
  1302. }
  1303. }
  1304. }
  1305. void MeshFeatureProcessor::ReportShaderOptionFlags([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
  1306. {
  1307. m_reportShaderOptionFlags = true;
  1308. }
  1309. RayTracingFeatureProcessor* MeshFeatureProcessor::GetRayTracingFeatureProcessor() const
  1310. {
  1311. return m_rayTracingFeatureProcessor;
  1312. }
  1313. ReflectionProbeFeatureProcessor* MeshFeatureProcessor::GetReflectionProbeFeatureProcessor() const
  1314. {
  1315. return m_reflectionProbeFeatureProcessor;
  1316. }
  1317. TransformServiceFeatureProcessor* MeshFeatureProcessor::GetTransformServiceFeatureProcessor() const
  1318. {
  1319. return m_transformService;
  1320. }
  1321. RHI::DrawListTag MeshFeatureProcessor::GetTransparentDrawListTag() const
  1322. {
  1323. return m_transparentDrawListTag;
  1324. }
  1325. MeshInstanceManager& MeshFeatureProcessor::GetMeshInstanceManager()
  1326. {
  1327. return m_meshInstanceManager;
  1328. }
  1329. bool MeshFeatureProcessor::IsMeshInstancingEnabled() const
  1330. {
  1331. return m_enableMeshInstancing;
  1332. }
  1333. void MeshFeatureProcessor::PrintShaderOptionFlags()
  1334. {
  1335. AZStd::map<FlagRegistry::TagType, AZ::Name> tags;
  1336. AZStd::string registeredFoundMessage = "Registered flags: ";
  1337. auto gatherTags = [&](const Name& name, FlagRegistry::TagType tag)
  1338. {
  1339. tags[tag] = name;
  1340. registeredFoundMessage.append(name.GetCStr() + AZStd::string(", "));
  1341. };
  1342. m_flagRegistry->VisitTags(gatherTags);
  1343. registeredFoundMessage.erase(registeredFoundMessage.end() - 2);
  1344. AZ_Printf("MeshFeatureProcessor", registeredFoundMessage.c_str());
  1345. AZStd::map<uint32_t, uint32_t> flagStats;
  1346. for (auto& model : m_modelData)
  1347. {
  1348. ++flagStats[model.m_cullable.m_shaderOptionFlags.load()];
  1349. }
  1350. for (auto [flag, references] : flagStats)
  1351. {
  1352. AZStd::string flagList;
  1353. if (flag == 0)
  1354. {
  1355. flagList = "(None)";
  1356. }
  1357. else
  1358. {
  1359. for (auto [tag, name] : tags)
  1360. {
  1361. if ((tag.GetIndex() & flag) > 0)
  1362. {
  1363. flagList.append(name.GetCStr());
  1364. flagList.append(", ");
  1365. }
  1366. }
  1367. flagList.erase(flagList.end() - 2);
  1368. }
  1369. AZ_Printf("MeshFeatureProcessor", "Found %u references to [%s]", references, flagList.c_str());
  1370. }
  1371. }
  1372. // ModelDataInstance::MeshLoader...
  1373. ModelDataInstance::MeshLoader::MeshLoader(const Data::Asset<RPI::ModelAsset>& modelAsset, ModelDataInstance* parent)
  1374. : m_modelAsset(modelAsset)
  1375. , m_parent(parent)
  1376. {
  1377. if (!m_modelAsset.GetId().IsValid())
  1378. {
  1379. AZ_Error("ModelDataInstance::MeshLoader", false, "Invalid model asset Id.");
  1380. return;
  1381. }
  1382. m_modelAsset.QueueLoad();
  1383. Data::AssetBus::Handler::BusConnect(m_modelAsset.GetId());
  1384. AzFramework::AssetCatalogEventBus::Handler::BusConnect();
  1385. }
  1386. ModelDataInstance::MeshLoader::~MeshLoader()
  1387. {
  1388. AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
  1389. Data::AssetBus::Handler::BusDisconnect();
  1390. SystemTickBus::Handler::BusDisconnect();
  1391. }
  1392. void ModelDataInstance::MeshLoader::OnSystemTick()
  1393. {
  1394. SystemTickBus::Handler::BusDisconnect();
  1395. // Assign the fully loaded asset back to the mesh handle to not only hold asset id, but the actual data as well.
  1396. m_parent->m_originalModelAsset = m_modelAsset;
  1397. if (const auto& modelTags = m_modelAsset->GetTags(); !modelTags.empty())
  1398. {
  1399. RPI::AssetQuality highestLodBias = RPI::AssetQualityLowest;
  1400. for (const AZ::Name& tag : modelTags)
  1401. {
  1402. RPI::AssetQuality tagQuality = RPI::AssetQualityHighest;
  1403. RPI::ModelTagBus::BroadcastResult(tagQuality, &RPI::ModelTagBus::Events::GetQuality, tag);
  1404. highestLodBias = AZStd::min(highestLodBias, tagQuality);
  1405. }
  1406. if (highestLodBias >= m_modelAsset->GetLodCount())
  1407. {
  1408. highestLodBias = aznumeric_caster(m_modelAsset->GetLodCount() - 1);
  1409. }
  1410. m_parent->m_lodBias = highestLodBias;
  1411. for (const AZ::Name& tag : modelTags)
  1412. {
  1413. RPI::ModelTagBus::Broadcast(&RPI::ModelTagBus::Events::RegisterAsset, tag, m_modelAsset->GetId());
  1414. }
  1415. }
  1416. else
  1417. {
  1418. m_parent->m_lodBias = 0;
  1419. }
  1420. Data::Instance<RPI::Model> model;
  1421. // Check if a requires cloning callback got set and if so check if cloning the model asset is requested.
  1422. if (m_parent->m_descriptor.m_requiresCloneCallback && m_parent->m_descriptor.m_requiresCloneCallback(m_modelAsset))
  1423. {
  1424. // Clone the model asset to force create another model instance.
  1425. AZ::Data::AssetId newId(AZ::Uuid::CreateRandom(), /*subId=*/0);
  1426. Data::Asset<RPI::ModelAsset> clonedAsset;
  1427. // Assume cloned models will involve some kind of geometry deformation
  1428. m_parent->m_flags.m_isAlwaysDynamic = true;
  1429. if (AZ::RPI::ModelAssetCreator::Clone(m_modelAsset, clonedAsset, newId))
  1430. {
  1431. model = RPI::Model::FindOrCreate(clonedAsset);
  1432. }
  1433. else
  1434. {
  1435. AZ_Error("ModelDataInstance", false, "Cannot clone model for '%s'. Cloth simulation results won't be individual per entity.", m_modelAsset->GetName().GetCStr());
  1436. model = RPI::Model::FindOrCreate(m_modelAsset);
  1437. }
  1438. }
  1439. else
  1440. {
  1441. // Static mesh, no cloth buffer present.
  1442. model = RPI::Model::FindOrCreate(m_modelAsset);
  1443. }
  1444. if (model)
  1445. {
  1446. RayTracingFeatureProcessor* rayTracingFeatureProcessor =
  1447. m_parent->m_scene->GetFeatureProcessor<RayTracingFeatureProcessor>();
  1448. m_parent->RemoveRayTracingData(rayTracingFeatureProcessor);
  1449. m_parent->QueueInit(model);
  1450. m_parent->m_modelChangedEvent.Signal(AZStd::move(model));
  1451. if (m_parent->m_flags.m_keepBufferAssetsInMemory)
  1452. {
  1453. model->GetModelAsset()->AddRefBufferAssets();
  1454. }
  1455. else
  1456. {
  1457. model->GetModelAsset()->ReleaseRefBufferAssets();
  1458. }
  1459. }
  1460. else
  1461. {
  1462. // when running with null renderer, the RPI::Model::FindOrCreate(...) is expected to return nullptr, so suppress this error.
  1463. AZ_Error("ModelDataInstance::OnAssetReady", RHI::IsNullRHI(), "Failed to create model instance for '%s'", m_modelAsset.GetHint().c_str());
  1464. }
  1465. }
  1466. //! AssetBus::Handler overrides...
  1467. void ModelDataInstance::MeshLoader::OnAssetReady(Data::Asset<Data::AssetData> asset)
  1468. {
  1469. // Update our model asset reference to contain the latest loaded version.
  1470. m_modelAsset = asset;
  1471. // The mesh loader queues the model asset to be loaded then connects to the asset bus. If the asset is already loaded
  1472. // OnAssetReady will be called before returning from the acquire function. Many callers connect handlers for model change
  1473. // events. Some of the handlers attempt to access their stored mesh handle member, which will not be up to date if the acquire
  1474. // function hasn't returned. This postpones sending the event until the next tick, allowing the acquire function to return and
  1475. // update and he stored mesh handles.
  1476. SystemTickBus::Handler::BusConnect();
  1477. }
  1478. void ModelDataInstance::MeshLoader::OnModelReloaded(Data::Asset<Data::AssetData> asset)
  1479. {
  1480. OnAssetReady(asset);
  1481. }
  1482. void ModelDataInstance::MeshLoader::OnAssetError(Data::Asset<Data::AssetData> asset)
  1483. {
  1484. // Note: m_modelAsset and asset represents same asset, but only m_modelAsset contains the file path in its hint from serialization
  1485. AZ_Error(
  1486. "ModelDataInstance::MeshLoader", false, "Failed to load asset %s. It may be missing, or not be finished processing",
  1487. m_modelAsset.GetHint().c_str());
  1488. AzFramework::AssetSystemRequestBus::Broadcast(
  1489. &AzFramework::AssetSystem::AssetSystemRequests::EscalateAssetByUuid, m_modelAsset.GetId().m_guid);
  1490. }
  1491. void ModelDataInstance::MeshLoader::OnCatalogAssetRemoved(
  1492. const AZ::Data::AssetId& assetId, [[maybe_unused]] const AZ::Data::AssetInfo& assetInfo)
  1493. {
  1494. OnCatalogAssetChanged(assetId);
  1495. }
  1496. void ModelDataInstance::MeshLoader::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId)
  1497. {
  1498. // If the asset didn't exist in the catalog when it first attempted to load, we need to try loading it again
  1499. OnCatalogAssetChanged(assetId);
  1500. }
  1501. void ModelDataInstance::MeshLoader::OnCatalogAssetChanged(const AZ::Data::AssetId& assetId)
  1502. {
  1503. if (assetId == m_modelAsset.GetId())
  1504. {
  1505. Data::Asset<RPI::ModelAsset> modelAssetReference = m_modelAsset;
  1506. // If the asset was modified, reload it. This will also cause a model to change back to the default missing
  1507. // asset if it was removed, and it will replace the default missing asset with the real asset if it was added.
  1508. AZ::SystemTickBus::QueueFunction(
  1509. [=, meshLoader = m_parent->m_meshLoader]() mutable
  1510. {
  1511. // Only trigger the reload if the meshLoader is still being used by something other than the lambda.
  1512. // If the lambda is the only owner, it will get destroyed after this queued call, so there's no point
  1513. // in reloading the model.
  1514. if (meshLoader.use_count() > 1)
  1515. {
  1516. ModelReloaderSystemInterface::Get()->ReloadModel(modelAssetReference, m_modelReloadedEventHandler);
  1517. }
  1518. });
  1519. }
  1520. }
  1521. ModelDataInstance::ModelDataInstance()
  1522. {
  1523. m_flags.m_cullBoundsNeedsUpdate = false;
  1524. m_flags.m_cullableNeedsRebuild = false;
  1525. m_flags.m_needsInit = false;
  1526. m_flags.m_objectSrgNeedsUpdate = true;
  1527. m_flags.m_isAlwaysDynamic = false;
  1528. m_flags.m_dynamic = false;
  1529. m_flags.m_isDrawMotion = false;
  1530. m_flags.m_visible = true;
  1531. m_flags.m_useForwardPassIblSpecular = false;
  1532. m_flags.m_hasForwardPassIblSpecularMaterial = false;
  1533. m_flags.m_needsSetRayTracingData = false;
  1534. m_flags.m_hasRayTracingReflectionProbe = false;
  1535. }
  1536. void ModelDataInstance::DeInit(MeshFeatureProcessor* meshFeatureProcessor)
  1537. {
  1538. RayTracingFeatureProcessor* rayTracingFeatureProcessor = meshFeatureProcessor->GetRayTracingFeatureProcessor();
  1539. m_scene->GetCullingScene()->UnregisterCullable(m_cullable);
  1540. RemoveRayTracingData(rayTracingFeatureProcessor);
  1541. // We're intentionally using the MeshFeatureProcessor's value instead of using the cvar directly here,
  1542. // because DeInit might be called after the cvar changes, but we want to do the de-initialization based
  1543. // on what the setting was before (when the resources were initialized). The MeshFeatureProcessor will still have the cached
  1544. // value in that case
  1545. if (!meshFeatureProcessor->IsMeshInstancingEnabled())
  1546. {
  1547. m_drawPacketListsByLod.clear();
  1548. }
  1549. else
  1550. {
  1551. // Remove all the meshes from the MeshInstanceManager
  1552. MeshInstanceManager& meshInstanceManager = meshFeatureProcessor->GetMeshInstanceManager();
  1553. for (size_t lodIndex = 0; lodIndex < m_postCullingInstanceDataByLod.size(); ++lodIndex)
  1554. {
  1555. PostCullingInstanceDataList& postCullingInstanceDataList = m_postCullingInstanceDataByLod[lodIndex];
  1556. for (PostCullingInstanceData& postCullingData : postCullingInstanceDataList)
  1557. {
  1558. postCullingData.m_instanceGroupHandle->RemoveAssociatedInstance(this);
  1559. // Remove instance will decrement the use-count of the instance group, and only release the instance group
  1560. // if nothing else is referring to it.
  1561. meshInstanceManager.RemoveInstance(postCullingData.m_instanceGroupHandle);
  1562. }
  1563. postCullingInstanceDataList.clear();
  1564. }
  1565. m_postCullingInstanceDataByLod.clear();
  1566. }
  1567. m_descriptor.m_customMaterials.clear();
  1568. m_objectSrgList = {};
  1569. m_model = {};
  1570. }
  1571. void ModelDataInstance::ReInit(MeshFeatureProcessor* meshFeatureProcessor)
  1572. {
  1573. CustomMaterialMap customMaterials = m_descriptor.m_customMaterials;
  1574. const Data::Instance<RPI::Model> model = m_model;
  1575. DeInit(meshFeatureProcessor);
  1576. m_descriptor.m_customMaterials = customMaterials;
  1577. m_model = model;
  1578. QueueInit(m_model);
  1579. }
  1580. void ModelDataInstance::QueueInit(const Data::Instance<RPI::Model>& model)
  1581. {
  1582. m_model = model;
  1583. m_flags.m_needsInit = true;
  1584. m_aabb = m_model->GetModelAsset()->GetAabb();
  1585. }
  1586. void ModelDataInstance::Init(MeshFeatureProcessor* meshFeatureProcessor)
  1587. {
  1588. const size_t modelLodCount = m_model->GetLodCount();
  1589. if (!r_meshInstancingEnabled)
  1590. {
  1591. m_drawPacketListsByLod.resize(modelLodCount);
  1592. }
  1593. else
  1594. {
  1595. m_postCullingInstanceDataByLod.resize(modelLodCount);
  1596. }
  1597. for (size_t modelLodIndex = 0; modelLodIndex < modelLodCount; ++modelLodIndex)
  1598. {
  1599. BuildDrawPacketList(meshFeatureProcessor, modelLodIndex);
  1600. }
  1601. for (auto& objectSrg : m_objectSrgList)
  1602. {
  1603. // Set object Id once since it never changes
  1604. RHI::ShaderInputNameIndex objectIdIndex = "m_objectId";
  1605. objectSrg->SetConstant(objectIdIndex, m_objectId.GetIndex());
  1606. objectIdIndex.AssertValid();
  1607. }
  1608. if (m_flags.m_visible && m_descriptor.m_isRayTracingEnabled)
  1609. {
  1610. m_flags.m_needsSetRayTracingData = true;
  1611. }
  1612. m_flags.m_cullableNeedsRebuild = true;
  1613. m_flags.m_cullBoundsNeedsUpdate = true;
  1614. m_flags.m_objectSrgNeedsUpdate = true;
  1615. m_flags.m_needsInit = false;
  1616. }
  1617. struct MeshInstancingSupport
  1618. {
  1619. bool m_canSupportInstancing = false;
  1620. bool m_isTransparent = false;
  1621. };
  1622. static MeshInstancingSupport CanSupportInstancing(
  1623. Data::Instance<RPI::Material> material, bool useForwardPassIbleSpecular, const RHI::DrawListTag& transparentDrawListTag)
  1624. {
  1625. MeshInstancingSupport result;
  1626. if (useForwardPassIbleSpecular)
  1627. {
  1628. // Forward pass ibl specular uses the ObjectSrg to set the closest reflection probe data
  1629. // Since all instances from a single instanced draw call share a single ObjectSrg, this
  1630. // will not work with instancing unless they happen to all share the same closes probe.
  1631. // In the future, we could make that part of the MeshInstanceGroupKey, but that impacts
  1632. // the initalization logic since at Init time we don't yet know the closest reflection probe.
  1633. // So initially we treat that case as not supporting instancing, and eventually we can re-order
  1634. // the logic in MeshFeatureProcessor::Simulate such that we know the up-to-date ObjectSrg data
  1635. // before this point
  1636. result.m_canSupportInstancing = false;
  1637. return result;
  1638. }
  1639. bool shadersSupportInstancing = true;
  1640. bool isTransparent = false;
  1641. material->ForAllShaderItems(
  1642. [&](const Name&, const RPI::ShaderCollection::Item& shaderItem)
  1643. {
  1644. if (shaderItem.IsEnabled())
  1645. {
  1646. // Check to see if the shaderItem has the o_meshInstancingEnabled option. All shader items in the draw packet must
  1647. // support this option
  1648. RPI::ShaderOptionIndex index = shaderItem.GetShaderOptionGroup().GetShaderOptionLayout()->FindShaderOptionIndex(
  1649. s_o_meshInstancingIsEnabled_Name);
  1650. if (!index.IsValid())
  1651. {
  1652. shadersSupportInstancing = false;
  1653. return false; // break
  1654. }
  1655. // Get the DrawListTag. Use the explicit draw list override if exists.
  1656. AZ::RHI::DrawListTag drawListTag = shaderItem.GetDrawListTagOverride();
  1657. if (drawListTag.IsNull())
  1658. {
  1659. drawListTag = RHI::RHISystemInterface::Get()->GetDrawListTagRegistry()->FindTag(
  1660. shaderItem.GetShaderAsset()->GetDrawListName());
  1661. }
  1662. // Check to see if the shaderItem is for a transparent pass. If any of the active shader items
  1663. // are for a transparent pass, we still support instancing, but we mark it as transparent so that
  1664. // we can sort by reverse-depth
  1665. if (drawListTag == transparentDrawListTag)
  1666. {
  1667. isTransparent = true;
  1668. if (!r_meshInstancingEnabledForTransparentObjects)
  1669. {
  1670. shadersSupportInstancing = false;
  1671. return false; // break
  1672. }
  1673. }
  1674. }
  1675. return true; // continue
  1676. });
  1677. result.m_canSupportInstancing = shadersSupportInstancing;
  1678. result.m_isTransparent = isTransparent;
  1679. return result;
  1680. }
  1681. void ModelDataInstance::BuildDrawPacketList(MeshFeatureProcessor* meshFeatureProcessor, size_t modelLodIndex)
  1682. {
  1683. RPI::ModelLod& modelLod = *m_model->GetLods()[modelLodIndex];
  1684. const size_t meshCount = modelLod.GetMeshes().size();
  1685. MeshInstanceManager& meshInstanceManager = meshFeatureProcessor->GetMeshInstanceManager();
  1686. if (!r_meshInstancingEnabled)
  1687. {
  1688. RPI::MeshDrawPacketList& drawPacketListOut = m_drawPacketListsByLod[modelLodIndex];
  1689. drawPacketListOut.clear();
  1690. drawPacketListOut.reserve(meshCount);
  1691. }
  1692. auto meshMotionDrawListTag = AZ::RHI::RHISystemInterface::Get()->GetDrawListTagRegistry()->FindTag(MeshCommon::MotionDrawListTagName);
  1693. for (size_t meshIndex = 0; meshIndex < meshCount; ++meshIndex)
  1694. {
  1695. const auto meshes = modelLod.GetMeshes();
  1696. const RPI::ModelLod::Mesh& mesh = meshes[meshIndex];
  1697. // Determine if there is a custom material specified for this submission
  1698. const CustomMaterialId customMaterialId(aznumeric_cast<AZ::u64>(modelLodIndex), mesh.m_materialSlotStableId);
  1699. const auto& customMaterialInfo = GetCustomMaterialWithFallback(customMaterialId);
  1700. const auto& material = customMaterialInfo.m_material ? customMaterialInfo.m_material : mesh.m_material;
  1701. if (!material)
  1702. {
  1703. AZ_Warning("MeshFeatureProcessor", false, "No material provided for mesh. Skipping.");
  1704. continue;
  1705. }
  1706. auto& objectSrgLayout = material->GetAsset()->GetObjectSrgLayout();
  1707. if (!objectSrgLayout)
  1708. {
  1709. AZ_Warning("MeshFeatureProcessor", false, "No per-object ShaderResourceGroup found.");
  1710. continue;
  1711. }
  1712. Data::Instance<RPI::ShaderResourceGroup> meshObjectSrg;
  1713. // See if the object SRG for this mesh is already in our list of object SRGs
  1714. for (auto& objectSrgIter : m_objectSrgList)
  1715. {
  1716. if (objectSrgIter->GetLayout()->GetHash() == objectSrgLayout->GetHash())
  1717. {
  1718. meshObjectSrg = objectSrgIter;
  1719. }
  1720. }
  1721. // If the object SRG for this mesh was not already in the list, create it and add it to the list
  1722. if (!meshObjectSrg)
  1723. {
  1724. auto& shaderAsset = material->GetAsset()->GetMaterialTypeAsset()->GetShaderAssetForObjectSrg();
  1725. meshObjectSrg = RPI::ShaderResourceGroup::Create(shaderAsset, objectSrgLayout->GetName());
  1726. if (!meshObjectSrg)
  1727. {
  1728. AZ_Warning("MeshFeatureProcessor", false, "Failed to create a new shader resource group, skipping.");
  1729. continue;
  1730. }
  1731. m_objectSrgCreatedEvent.Signal(meshObjectSrg);
  1732. m_objectSrgList.push_back(meshObjectSrg);
  1733. }
  1734. bool materialRequiresForwardPassIblSpecular = MaterialRequiresForwardPassIblSpecular(material);
  1735. // Track whether any materials in this mesh require ForwardPassIblSpecular, we need this information when the ObjectSrg is
  1736. // updated
  1737. m_flags.m_hasForwardPassIblSpecularMaterial |= materialRequiresForwardPassIblSpecular;
  1738. MeshInstanceManager::InsertResult instanceGroupInsertResult{ MeshInstanceManager::Handle{}, 0 };
  1739. MeshInstancingSupport instancingSupport;
  1740. if (r_meshInstancingEnabled)
  1741. {
  1742. // Get the instance index for referencing the draw packet
  1743. MeshInstanceGroupKey key{};
  1744. // Only meshes from the same model and lod with a matching material instance can be instanced
  1745. key.m_modelId = m_model->GetId();
  1746. key.m_lodIndex = static_cast<uint32_t>(modelLodIndex);
  1747. key.m_meshIndex = static_cast<uint32_t>(meshIndex);
  1748. key.m_materialId = material->GetId();
  1749. // Two meshes that could otherwise be instanced but have manually specified sort keys will not be instanced together
  1750. key.m_sortKey = m_sortKey;
  1751. instancingSupport = CanSupportInstancing(
  1752. material, m_flags.m_hasForwardPassIblSpecularMaterial, meshFeatureProcessor->GetTransparentDrawListTag());
  1753. if (instancingSupport.m_canSupportInstancing && !r_meshInstancingDebugForceUniqueObjectsForProfiling)
  1754. {
  1755. // If this object can be instanced, it gets a null uuid that will match other objects that can be instanced with it
  1756. key.m_forceInstancingOff = Uuid::CreateNull();
  1757. }
  1758. else
  1759. {
  1760. // When instancing is enabled, everything goes down the instancing path, including this object
  1761. // However, using a random uuid here will give it its own unique instance group, with it's own unique ObjectSrg,
  1762. // so it will end up as an instanced draw call with a count of 1
  1763. // We also use this path when r_meshInstancingDebugForceUniqueObjectsForProfiling is true, which makes meshes that
  1764. // would otherwise be instanced end up in a unique group. This is helpful for performance profiling to test the
  1765. // worst case scenario of lots of objects that don't actually end up getting instanced but still go down the
  1766. // instancing path
  1767. key.m_forceInstancingOff = Uuid::CreateRandom();
  1768. }
  1769. instanceGroupInsertResult = meshInstanceManager.AddInstance(key);
  1770. PostCullingInstanceData postCullingData;
  1771. postCullingData.m_instanceGroupHandle = instanceGroupInsertResult.m_handle;
  1772. postCullingData.m_instanceGroupPageIndex = instanceGroupInsertResult.m_pageIndex;
  1773. postCullingData.m_objectId = m_objectId;
  1774. // Mark the group as transparent so that the depth can be sorted in reverse
  1775. postCullingData.m_instanceGroupHandle->m_isTransparent = instancingSupport.m_isTransparent;
  1776. m_postCullingInstanceDataByLod[modelLodIndex].push_back(postCullingData);
  1777. // The instaceGroup needs to keep a reference of this ModelDataInstance so it can
  1778. // notify the ModelDataInstance when the MeshDrawPacket is changed or get the cullable's flags
  1779. instanceGroupInsertResult.m_handle->AddAssociatedInstance(this);
  1780. }
  1781. // If this condition is true, we're dealing with a new, uninitialized draw packet, either because instancing is disabled
  1782. // or because this was the first object in the instance group. So we need to initialize it
  1783. if (!r_meshInstancingEnabled || instanceGroupInsertResult.m_instanceCount == 1)
  1784. {
  1785. // setup the mesh draw packet
  1786. RPI::MeshDrawPacket drawPacket(modelLod, meshIndex, material, meshObjectSrg, customMaterialInfo.m_uvMapping);
  1787. // set the shader option to select forward pass IBL specular if necessary
  1788. if (!drawPacket.SetShaderOption(s_o_meshUseForwardPassIBLSpecular_Name, AZ::RPI::ShaderOptionValue{ m_descriptor.m_useForwardPassIblSpecular }))
  1789. {
  1790. AZ_Warning("MeshDrawPacket", false, "Failed to set o_meshUseForwardPassIBLSpecular on mesh draw packet");
  1791. }
  1792. if (instancingSupport.m_canSupportInstancing)
  1793. {
  1794. drawPacket.SetShaderOption(s_o_meshInstancingIsEnabled_Name, AZ::RPI::ShaderOptionValue{ true });
  1795. }
  1796. bool blockSilhouettes = false;
  1797. if (auto index = material->FindPropertyIndex(s_block_silhouette_Name); index.IsValid())
  1798. {
  1799. blockSilhouettes = material->GetPropertyValue<bool>(index);
  1800. }
  1801. // stencil bits
  1802. uint8_t stencilRef = m_descriptor.m_useForwardPassIblSpecular || materialRequiresForwardPassIblSpecular
  1803. ? Render::StencilRefs::None
  1804. : Render::StencilRefs::UseIBLSpecularPass;
  1805. stencilRef |= Render::StencilRefs::UseDiffuseGIPass;
  1806. stencilRef |= blockSilhouettes ? Render::StencilRefs::BlockSilhouettes : 0;
  1807. drawPacket.SetStencilRef(stencilRef);
  1808. drawPacket.SetSortKey(m_sortKey);
  1809. drawPacket.SetEnableDraw(meshMotionDrawListTag, m_flags.m_isDrawMotion);
  1810. // Note: do not add drawPacket.Update() here. It's not needed.It may cause issue with m_shaderVariantHandler which captures 'this' pointer.
  1811. if (!r_meshInstancingEnabled)
  1812. {
  1813. m_drawPacketListsByLod[modelLodIndex].emplace_back(AZStd::move(drawPacket));
  1814. }
  1815. else
  1816. {
  1817. MeshInstanceGroupData& instanceGroupData = meshInstanceManager[instanceGroupInsertResult.m_handle];
  1818. instanceGroupData.m_drawPacket = AZStd::move(drawPacket);
  1819. instanceGroupData.m_isDrawMotion = m_flags.m_isDrawMotion;
  1820. // We're going to need an interval for the root constant data that we update every frame for each draw item, so cache that here
  1821. CacheRootConstantInterval(instanceGroupData);
  1822. }
  1823. }
  1824. // For mesh instancing only
  1825. // If this model needs to draw motion, enable draw motion vector for the DrawPacket.
  1826. // This means any mesh instances which are using this draw packet would draw motion vector too. This is fine, just not optimized.
  1827. if (r_meshInstancingEnabled && m_flags.m_isDrawMotion)
  1828. {
  1829. MeshInstanceGroupData& instanceGroupData = meshInstanceManager[instanceGroupInsertResult.m_handle];
  1830. if (!instanceGroupData.m_isDrawMotion)
  1831. {
  1832. instanceGroupData.m_isDrawMotion = true;
  1833. instanceGroupData.m_drawPacket.SetEnableDraw(meshMotionDrawListTag, true);
  1834. }
  1835. }
  1836. }
  1837. }
  1838. void ModelDataInstance::SetRayTracingData(MeshFeatureProcessor* meshFeatureProcessor)
  1839. {
  1840. RayTracingFeatureProcessor* rayTracingFeatureProcessor = meshFeatureProcessor->GetRayTracingFeatureProcessor();
  1841. TransformServiceFeatureProcessor* transformServiceFeatureProcessor =
  1842. meshFeatureProcessor->GetTransformServiceFeatureProcessor();
  1843. RemoveRayTracingData(rayTracingFeatureProcessor);
  1844. if (!m_model)
  1845. {
  1846. return;
  1847. }
  1848. if (!rayTracingFeatureProcessor)
  1849. {
  1850. return;
  1851. }
  1852. const AZStd::span<const Data::Instance<RPI::ModelLod>>& modelLods = m_model->GetLods();
  1853. if (modelLods.empty())
  1854. {
  1855. return;
  1856. }
  1857. // use the lowest LOD for raytracing
  1858. uint32_t rayTracingLod = aznumeric_cast<uint32_t>(modelLods.size() - 1);
  1859. const Data::Instance<RPI::ModelLod>& modelLod = modelLods[rayTracingLod];
  1860. // setup a stream layout and shader input contract for the vertex streams
  1861. static const char* PositionSemantic = "POSITION";
  1862. static const char* NormalSemantic = "NORMAL";
  1863. static const char* TangentSemantic = "TANGENT";
  1864. static const char* BitangentSemantic = "BITANGENT";
  1865. static const char* UVSemantic = "UV";
  1866. static const RHI::Format PositionStreamFormat = RHI::Format::R32G32B32_FLOAT;
  1867. static const RHI::Format NormalStreamFormat = RHI::Format::R32G32B32_FLOAT;
  1868. static const RHI::Format TangentStreamFormat = RHI::Format::R32G32B32A32_FLOAT;
  1869. static const RHI::Format BitangentStreamFormat = RHI::Format::R32G32B32_FLOAT;
  1870. static const RHI::Format UVStreamFormat = RHI::Format::R32G32_FLOAT;
  1871. RHI::InputStreamLayoutBuilder layoutBuilder;
  1872. layoutBuilder.AddBuffer()->Channel(PositionSemantic, PositionStreamFormat);
  1873. layoutBuilder.AddBuffer()->Channel(NormalSemantic, NormalStreamFormat);
  1874. layoutBuilder.AddBuffer()->Channel(UVSemantic, UVStreamFormat);
  1875. layoutBuilder.AddBuffer()->Channel(TangentSemantic, TangentStreamFormat);
  1876. layoutBuilder.AddBuffer()->Channel(BitangentSemantic, BitangentStreamFormat);
  1877. RHI::InputStreamLayout inputStreamLayout = layoutBuilder.End();
  1878. RPI::ShaderInputContract::StreamChannelInfo positionStreamChannelInfo;
  1879. positionStreamChannelInfo.m_semantic = RHI::ShaderSemantic(AZ::Name(PositionSemantic));
  1880. positionStreamChannelInfo.m_componentCount = RHI::GetFormatComponentCount(PositionStreamFormat);
  1881. RPI::ShaderInputContract::StreamChannelInfo normalStreamChannelInfo;
  1882. normalStreamChannelInfo.m_semantic = RHI::ShaderSemantic(AZ::Name(NormalSemantic));
  1883. normalStreamChannelInfo.m_componentCount = RHI::GetFormatComponentCount(NormalStreamFormat);
  1884. RPI::ShaderInputContract::StreamChannelInfo tangentStreamChannelInfo;
  1885. tangentStreamChannelInfo.m_semantic = RHI::ShaderSemantic(AZ::Name(TangentSemantic));
  1886. tangentStreamChannelInfo.m_componentCount = RHI::GetFormatComponentCount(TangentStreamFormat);
  1887. tangentStreamChannelInfo.m_isOptional = true;
  1888. RPI::ShaderInputContract::StreamChannelInfo bitangentStreamChannelInfo;
  1889. bitangentStreamChannelInfo.m_semantic = RHI::ShaderSemantic(AZ::Name(BitangentSemantic));
  1890. bitangentStreamChannelInfo.m_componentCount = RHI::GetFormatComponentCount(BitangentStreamFormat);
  1891. bitangentStreamChannelInfo.m_isOptional = true;
  1892. RPI::ShaderInputContract::StreamChannelInfo uvStreamChannelInfo;
  1893. uvStreamChannelInfo.m_semantic = RHI::ShaderSemantic(AZ::Name(UVSemantic));
  1894. uvStreamChannelInfo.m_componentCount = RHI::GetFormatComponentCount(UVStreamFormat);
  1895. uvStreamChannelInfo.m_isOptional = true;
  1896. RPI::ShaderInputContract shaderInputContract;
  1897. shaderInputContract.m_streamChannels.emplace_back(positionStreamChannelInfo);
  1898. shaderInputContract.m_streamChannels.emplace_back(normalStreamChannelInfo);
  1899. shaderInputContract.m_streamChannels.emplace_back(tangentStreamChannelInfo);
  1900. shaderInputContract.m_streamChannels.emplace_back(bitangentStreamChannelInfo);
  1901. shaderInputContract.m_streamChannels.emplace_back(uvStreamChannelInfo);
  1902. // setup the raytracing data for each sub-mesh
  1903. const size_t meshCount = modelLod->GetMeshes().size();
  1904. RayTracingFeatureProcessor::SubMeshVector subMeshes;
  1905. for (uint32_t meshIndex = 0; meshIndex < meshCount; ++meshIndex)
  1906. {
  1907. const auto meshes = modelLod->GetMeshes();
  1908. const RPI::ModelLod::Mesh& mesh = meshes[meshIndex];
  1909. // retrieve the material
  1910. const CustomMaterialId customMaterialId(rayTracingLod, mesh.m_materialSlotStableId);
  1911. const auto& customMaterialInfo = GetCustomMaterialWithFallback(customMaterialId);
  1912. const auto& material = customMaterialInfo.m_material ? customMaterialInfo.m_material : mesh.m_material;
  1913. if (!material)
  1914. {
  1915. AZ_Warning("MeshFeatureProcessor", false, "No material provided for mesh. Skipping.");
  1916. continue;
  1917. }
  1918. // retrieve vertex/index buffers
  1919. RPI::ModelLod::StreamBufferViewList streamBufferViews;
  1920. [[maybe_unused]] bool result = modelLod->GetStreamsForMesh(
  1921. inputStreamLayout,
  1922. streamBufferViews,
  1923. nullptr,
  1924. shaderInputContract,
  1925. meshIndex,
  1926. customMaterialInfo.m_uvMapping,
  1927. material->GetAsset()->GetMaterialTypeAsset()->GetUvNameMap());
  1928. AZ_Assert(result, "Failed to retrieve mesh stream buffer views");
  1929. // The code below expects streams for positions, normals, tangents, bitangents, and uvs.
  1930. constexpr size_t NumExpectedStreams = 5;
  1931. if (streamBufferViews.size() < NumExpectedStreams)
  1932. {
  1933. AZ_Warning("MeshFeatureProcessor", false, "Model is missing one or more expected streams "
  1934. "(positions, normals, tangents, bitangents, uvs), skipping the raytracing data generation.");
  1935. continue;
  1936. }
  1937. // note that the element count is the size of the entire buffer, even though this mesh may only
  1938. // occupy a portion of the vertex buffer. This is necessary since we are accessing it using
  1939. // a ByteAddressBuffer in the raytracing shaders and passing the byte offset to the shader in a constant buffer.
  1940. uint32_t positionBufferByteCount = static_cast<uint32_t>(
  1941. const_cast<RHI::Buffer*>(streamBufferViews[0].GetBuffer())->GetDescriptor().m_byteCount);
  1942. RHI::BufferViewDescriptor positionBufferDescriptor = RHI::BufferViewDescriptor::CreateRaw(0, positionBufferByteCount);
  1943. uint32_t normalBufferByteCount = static_cast<uint32_t>(
  1944. const_cast<RHI::Buffer*>(streamBufferViews[1].GetBuffer())->GetDescriptor().m_byteCount);
  1945. RHI::BufferViewDescriptor normalBufferDescriptor = RHI::BufferViewDescriptor::CreateRaw(0, normalBufferByteCount);
  1946. uint32_t tangentBufferByteCount = static_cast<uint32_t>(
  1947. const_cast<RHI::Buffer*>(streamBufferViews[2].GetBuffer())->GetDescriptor().m_byteCount);
  1948. RHI::BufferViewDescriptor tangentBufferDescriptor = RHI::BufferViewDescriptor::CreateRaw(0, tangentBufferByteCount);
  1949. uint32_t bitangentBufferByteCount = static_cast<uint32_t>(
  1950. const_cast<RHI::Buffer*>(streamBufferViews[3].GetBuffer())->GetDescriptor().m_byteCount);
  1951. RHI::BufferViewDescriptor bitangentBufferDescriptor = RHI::BufferViewDescriptor::CreateRaw(0, bitangentBufferByteCount);
  1952. uint32_t uvBufferByteCount = static_cast<uint32_t>(
  1953. const_cast<RHI::Buffer*>(streamBufferViews[4].GetBuffer())->GetDescriptor().m_byteCount);
  1954. RHI::BufferViewDescriptor uvBufferDescriptor = RHI::BufferViewDescriptor::CreateRaw(0, uvBufferByteCount);
  1955. const RHI::IndexBufferView& indexBufferView = mesh.m_indexBufferView;
  1956. uint32_t indexElementSize = indexBufferView.GetIndexFormat() == RHI::IndexFormat::Uint16 ? 2 : 4;
  1957. uint32_t indexElementCount = (uint32_t)indexBufferView.GetBuffer()->GetDescriptor().m_byteCount / indexElementSize;
  1958. RHI::BufferViewDescriptor indexBufferDescriptor;
  1959. indexBufferDescriptor.m_elementOffset = 0;
  1960. indexBufferDescriptor.m_elementCount = indexElementCount;
  1961. indexBufferDescriptor.m_elementSize = indexElementSize;
  1962. indexBufferDescriptor.m_elementFormat = indexBufferView.GetIndexFormat() == RHI::IndexFormat::Uint16 ? RHI::Format::R16_UINT : RHI::Format::R32_UINT;
  1963. // set the SubMesh data to pass to the RayTracingFeatureProcessor, starting with vertex/index data
  1964. RayTracingFeatureProcessor::SubMesh subMesh;
  1965. RayTracingFeatureProcessor::SubMeshMaterial& subMeshMaterial = subMesh.m_material;
  1966. subMesh.m_positionFormat = PositionStreamFormat;
  1967. subMesh.m_positionVertexBufferView = streamBufferViews[0];
  1968. subMesh.m_positionShaderBufferView =
  1969. const_cast<RHI::Buffer*>(streamBufferViews[0].GetBuffer())->BuildBufferView(positionBufferDescriptor);
  1970. subMesh.m_normalFormat = NormalStreamFormat;
  1971. subMesh.m_normalVertexBufferView = streamBufferViews[1];
  1972. subMesh.m_normalShaderBufferView =
  1973. const_cast<RHI::Buffer*>(streamBufferViews[1].GetBuffer())->BuildBufferView(normalBufferDescriptor);
  1974. if (tangentBufferByteCount > 0)
  1975. {
  1976. subMesh.m_bufferFlags |= RayTracingSubMeshBufferFlags::Tangent;
  1977. subMesh.m_tangentFormat = TangentStreamFormat;
  1978. subMesh.m_tangentVertexBufferView = streamBufferViews[2];
  1979. subMesh.m_tangentShaderBufferView =
  1980. const_cast<RHI::Buffer*>(streamBufferViews[2].GetBuffer())->BuildBufferView(tangentBufferDescriptor);
  1981. }
  1982. if (bitangentBufferByteCount > 0)
  1983. {
  1984. subMesh.m_bufferFlags |= RayTracingSubMeshBufferFlags::Bitangent;
  1985. subMesh.m_bitangentFormat = BitangentStreamFormat;
  1986. subMesh.m_bitangentVertexBufferView = streamBufferViews[3];
  1987. subMesh.m_bitangentShaderBufferView =
  1988. const_cast<RHI::Buffer*>(streamBufferViews[3].GetBuffer())->BuildBufferView(bitangentBufferDescriptor);
  1989. }
  1990. if (uvBufferByteCount > 0)
  1991. {
  1992. subMesh.m_bufferFlags |= RayTracingSubMeshBufferFlags::UV;
  1993. subMesh.m_uvFormat = UVStreamFormat;
  1994. subMesh.m_uvVertexBufferView = streamBufferViews[4];
  1995. subMesh.m_uvShaderBufferView =
  1996. const_cast<RHI::Buffer*>(streamBufferViews[4].GetBuffer())->BuildBufferView(uvBufferDescriptor);
  1997. }
  1998. subMesh.m_indexBufferView = mesh.m_indexBufferView;
  1999. subMesh.m_indexShaderBufferView =
  2000. const_cast<RHI::Buffer*>(mesh.m_indexBufferView.GetBuffer())->BuildBufferView(indexBufferDescriptor);
  2001. // add material data
  2002. if (material)
  2003. {
  2004. RPI::MaterialPropertyIndex propertyIndex;
  2005. // base color
  2006. propertyIndex = material->FindPropertyIndex(s_baseColor_color_Name);
  2007. if (propertyIndex.IsValid())
  2008. {
  2009. subMeshMaterial.m_baseColor = material->GetPropertyValue<AZ::Color>(propertyIndex);
  2010. }
  2011. propertyIndex = material->FindPropertyIndex(s_baseColor_factor_Name);
  2012. if (propertyIndex.IsValid())
  2013. {
  2014. subMeshMaterial.m_baseColor *= material->GetPropertyValue<float>(propertyIndex);
  2015. }
  2016. // metallic
  2017. propertyIndex = material->FindPropertyIndex(s_metallic_factor_Name);
  2018. if (propertyIndex.IsValid())
  2019. {
  2020. subMeshMaterial.m_metallicFactor = material->GetPropertyValue<float>(propertyIndex);
  2021. }
  2022. // roughness
  2023. propertyIndex = material->FindPropertyIndex(s_roughness_factor_Name);
  2024. if (propertyIndex.IsValid())
  2025. {
  2026. subMeshMaterial.m_roughnessFactor = material->GetPropertyValue<float>(propertyIndex);
  2027. }
  2028. // emissive color
  2029. propertyIndex = material->FindPropertyIndex(s_emissive_enable_Name);
  2030. if (propertyIndex.IsValid())
  2031. {
  2032. if (material->GetPropertyValue<bool>(propertyIndex))
  2033. {
  2034. propertyIndex = material->FindPropertyIndex(s_emissive_color_Name);
  2035. if (propertyIndex.IsValid())
  2036. {
  2037. subMeshMaterial.m_emissiveColor = material->GetPropertyValue<AZ::Color>(propertyIndex);
  2038. }
  2039. // When we have an emissive intensity, the unit of the intensity is defined in the material settings.
  2040. // For non-raytracing materials, the intensity is converted, and set in the shader, by a Functor.
  2041. // This (and the other) Functors are normally called in the Compile function of the Material
  2042. // We can't use the Compile function here, because the raytracing material behaves bit differently
  2043. // Therefor we need to look for the right Functor to convert the intensity here
  2044. propertyIndex = material->FindPropertyIndex(s_emissive_intensity_Name);
  2045. if (propertyIndex.IsValid())
  2046. {
  2047. auto unitPropertyIndex = material->FindPropertyIndex(s_emissive_unit_Name);
  2048. AZ_WarningOnce(
  2049. "MeshFeatureProcessor",
  2050. propertyIndex.IsValid(),
  2051. "Emissive intensity property missing in material %s. Materials with an emissive intensity need a unit for the intensity.",
  2052. material->GetAsset()->GetId().ToFixedString().c_str());
  2053. if (unitPropertyIndex.IsValid())
  2054. {
  2055. auto intensity = material->GetPropertyValue<float>(propertyIndex);
  2056. auto unit = material->GetPropertyValue<uint32_t>(unitPropertyIndex);
  2057. bool foundEmissiveUnitFunctor = false;
  2058. for (const auto& functor : material->GetAsset()->GetMaterialFunctors())
  2059. {
  2060. auto emissiveFunctor = azdynamic_cast<ConvertEmissiveUnitFunctor*>(functor);
  2061. if (emissiveFunctor != nullptr)
  2062. {
  2063. intensity = emissiveFunctor->GetProcessedValue(intensity, unit);
  2064. foundEmissiveUnitFunctor = true;
  2065. break;
  2066. }
  2067. }
  2068. AZ_WarningOnce(
  2069. "MeshFeatureProcessor",
  2070. foundEmissiveUnitFunctor,
  2071. "Could not find ConvertEmissiveUnitFunctor for material %s",
  2072. material->GetAsset()->GetId().ToFixedString().c_str());
  2073. if (foundEmissiveUnitFunctor)
  2074. {
  2075. subMeshMaterial.m_emissiveColor *= intensity;
  2076. }
  2077. }
  2078. }
  2079. }
  2080. }
  2081. // textures
  2082. Data::Instance<RPI::Image> baseColorImage; // can be used for irradiance color below
  2083. propertyIndex = material->FindPropertyIndex(s_baseColor_textureMap_Name);
  2084. if (propertyIndex.IsValid())
  2085. {
  2086. Data::Instance<RPI::Image> image = material->GetPropertyValue<Data::Instance<RPI::Image>>(propertyIndex);
  2087. if (image.get())
  2088. {
  2089. subMeshMaterial.m_textureFlags |= RayTracingSubMeshTextureFlags::BaseColor;
  2090. subMeshMaterial.m_baseColorImageView = image->GetImageView();
  2091. baseColorImage = image;
  2092. }
  2093. }
  2094. propertyIndex = material->FindPropertyIndex(s_normal_textureMap_Name);
  2095. if (propertyIndex.IsValid())
  2096. {
  2097. Data::Instance<RPI::Image> image = material->GetPropertyValue<Data::Instance<RPI::Image>>(propertyIndex);
  2098. if (image.get())
  2099. {
  2100. subMeshMaterial.m_textureFlags |= RayTracingSubMeshTextureFlags::Normal;
  2101. subMeshMaterial.m_normalImageView = image->GetImageView();
  2102. }
  2103. }
  2104. propertyIndex = material->FindPropertyIndex(s_metallic_textureMap_Name);
  2105. if (propertyIndex.IsValid())
  2106. {
  2107. Data::Instance<RPI::Image> image = material->GetPropertyValue<Data::Instance<RPI::Image>>(propertyIndex);
  2108. if (image.get())
  2109. {
  2110. subMeshMaterial.m_textureFlags |= RayTracingSubMeshTextureFlags::Metallic;
  2111. subMeshMaterial.m_metallicImageView = image->GetImageView();
  2112. }
  2113. }
  2114. propertyIndex = material->FindPropertyIndex(s_roughness_textureMap_Name);
  2115. if (propertyIndex.IsValid())
  2116. {
  2117. Data::Instance<RPI::Image> image = material->GetPropertyValue<Data::Instance<RPI::Image>>(propertyIndex);
  2118. if (image.get())
  2119. {
  2120. subMeshMaterial.m_textureFlags |= RayTracingSubMeshTextureFlags::Roughness;
  2121. subMeshMaterial.m_roughnessImageView = image->GetImageView();
  2122. }
  2123. }
  2124. propertyIndex = material->FindPropertyIndex(s_emissive_textureMap_Name);
  2125. if (propertyIndex.IsValid())
  2126. {
  2127. Data::Instance<RPI::Image> image = material->GetPropertyValue<Data::Instance<RPI::Image>>(propertyIndex);
  2128. if (image.get())
  2129. {
  2130. subMeshMaterial.m_textureFlags |= RayTracingSubMeshTextureFlags::Emissive;
  2131. subMeshMaterial.m_emissiveImageView = image->GetImageView();
  2132. }
  2133. }
  2134. // irradiance color
  2135. SetIrradianceData(subMesh, material, baseColorImage);
  2136. }
  2137. subMeshes.push_back(subMesh);
  2138. }
  2139. // setup the RayTracing Mesh
  2140. RayTracingFeatureProcessor::Mesh rayTracingMesh;
  2141. rayTracingMesh.m_assetId = m_model->GetModelAsset()->GetId();
  2142. rayTracingMesh.m_transform = transformServiceFeatureProcessor->GetTransformForId(m_objectId);
  2143. rayTracingMesh.m_nonUniformScale = transformServiceFeatureProcessor->GetNonUniformScaleForId(m_objectId);
  2144. rayTracingMesh.m_isSkinnedMesh = m_descriptor.m_isSkinnedMesh;
  2145. rayTracingMesh.m_instanceMask |= (rayTracingMesh.m_isSkinnedMesh)
  2146. ? static_cast<uint32_t>(AZ::RHI::RayTracingAccelerationStructureInstanceInclusionMask::SKINNED_MESH)
  2147. : static_cast<uint32_t>(AZ::RHI::RayTracingAccelerationStructureInstanceInclusionMask::STATIC_MESH);
  2148. // setup the reflection probe data, and track if this mesh is currently affected by a reflection probe
  2149. SetRayTracingReflectionProbeData(meshFeatureProcessor, rayTracingMesh.m_reflectionProbe);
  2150. // add the mesh
  2151. rayTracingFeatureProcessor->AddMesh(m_rayTracingUuid, rayTracingMesh, subMeshes);
  2152. m_flags.m_needsSetRayTracingData = false;
  2153. }
  2154. void ModelDataInstance::SetIrradianceData(
  2155. RayTracingFeatureProcessor::SubMesh& subMesh,
  2156. const Data::Instance<RPI::Material> material,
  2157. const Data::Instance<RPI::Image> baseColorImage)
  2158. {
  2159. RPI::MaterialPropertyIndex propertyIndex = material->FindPropertyIndex(s_irradiance_irradianceColorSource_Name);
  2160. if (!propertyIndex.IsValid())
  2161. {
  2162. return;
  2163. }
  2164. uint32_t enumVal = material->GetPropertyValue<uint32_t>(propertyIndex);
  2165. AZ::Name irradianceColorSource = material->GetMaterialPropertiesLayout()->GetPropertyDescriptor(propertyIndex)->GetEnumName(enumVal);
  2166. RayTracingFeatureProcessor::SubMeshMaterial& subMeshMaterial = subMesh.m_material;
  2167. if (irradianceColorSource.IsEmpty() || irradianceColorSource == s_Manual_Name)
  2168. {
  2169. propertyIndex = material->FindPropertyIndex(s_irradiance_manualColor_Name);
  2170. if (propertyIndex.IsValid())
  2171. {
  2172. subMeshMaterial.m_irradianceColor = material->GetPropertyValue<AZ::Color>(propertyIndex);
  2173. }
  2174. else
  2175. {
  2176. // Couldn't find irradiance.manualColor -> check for an irradiance.color in case the material type
  2177. // doesn't have the concept of manual vs. automatic irradiance color, allow a simpler property name
  2178. propertyIndex = material->FindPropertyIndex(s_irradiance_color_Name);
  2179. if (propertyIndex.IsValid())
  2180. {
  2181. subMeshMaterial.m_irradianceColor = material->GetPropertyValue<AZ::Color>(propertyIndex);
  2182. }
  2183. else
  2184. {
  2185. AZ_Warning(
  2186. "MeshFeatureProcessor", false,
  2187. "No irradiance.manualColor or irradiance.color field found. Defaulting to 1.0f.");
  2188. subMeshMaterial.m_irradianceColor = AZ::Colors::White;
  2189. }
  2190. }
  2191. }
  2192. else if (irradianceColorSource == s_BaseColorTint_Name)
  2193. {
  2194. // Use only the baseColor, no texture on top of it
  2195. subMeshMaterial.m_irradianceColor = subMeshMaterial.m_baseColor;
  2196. }
  2197. else if (irradianceColorSource == s_BaseColor_Name)
  2198. {
  2199. // Check if texturing is enabled
  2200. bool useTexture;
  2201. propertyIndex = material->FindPropertyIndex(s_baseColor_useTexture_Name);
  2202. if (propertyIndex.IsValid())
  2203. {
  2204. useTexture = material->GetPropertyValue<bool>(propertyIndex);
  2205. }
  2206. else
  2207. {
  2208. // No explicit baseColor.useTexture switch found, assuming the user wants to use
  2209. // a texture if a texture was found.
  2210. useTexture = true;
  2211. }
  2212. // If texturing was requested: check if we found a texture and use it
  2213. if (useTexture && baseColorImage.get())
  2214. {
  2215. // Currently GetAverageColor() is only implemented for a StreamingImage
  2216. auto baseColorStreamingImg = azdynamic_cast<RPI::StreamingImage*>(baseColorImage.get());
  2217. if (baseColorStreamingImg)
  2218. {
  2219. // Note: there are quite a few hidden assumptions in using the average
  2220. // texture color. For instance, (1) it assumes that every texel in the
  2221. // texture actually gets mapped to the surface (or non-mapped regions are
  2222. // colored with a meaningful 'average' color, or have zero opacity); (2) it
  2223. // assumes that the mapping from uv space to the mesh surface is
  2224. // (approximately) area-preserving to get a properly weighted average; and
  2225. // mostly, (3) it assumes that a single 'average color' is a meaningful
  2226. // characterisation of the full material.
  2227. Color avgColor = baseColorStreamingImg->GetAverageColor();
  2228. // We do a simple 'multiply' blend with the base color
  2229. // Note: other blend modes are currently not supported
  2230. subMeshMaterial.m_irradianceColor = avgColor * subMeshMaterial.m_baseColor;
  2231. }
  2232. else
  2233. {
  2234. AZ_Warning("MeshFeatureProcessor", false, "Using BaseColor as irradianceColorSource "
  2235. "is currently only supported for textures of type StreamingImage");
  2236. // Default to the flat base color
  2237. subMeshMaterial.m_irradianceColor = subMeshMaterial.m_baseColor;
  2238. }
  2239. }
  2240. else
  2241. {
  2242. // No texture, simply copy the baseColor
  2243. subMeshMaterial.m_irradianceColor = subMeshMaterial.m_baseColor;
  2244. }
  2245. }
  2246. else
  2247. {
  2248. AZ_Warning("MeshFeatureProcessor", false, "Unknown irradianceColorSource value: %s, "
  2249. "defaulting to 1.0f.", irradianceColorSource.GetCStr());
  2250. subMeshMaterial.m_irradianceColor = AZ::Colors::White;
  2251. }
  2252. // Overall scale factor
  2253. propertyIndex = material->FindPropertyIndex(s_irradiance_factor_Name);
  2254. if (propertyIndex.IsValid())
  2255. {
  2256. subMeshMaterial.m_irradianceColor *= material->GetPropertyValue<float>(propertyIndex);
  2257. }
  2258. // set the raytracing transparency from the material opacity factor
  2259. float opacity = 1.0f;
  2260. propertyIndex = material->FindPropertyIndex(s_opacity_mode_Name);
  2261. if (propertyIndex.IsValid())
  2262. {
  2263. // only query the opacity factor if it's a non-Opaque mode
  2264. uint32_t mode = material->GetPropertyValue<uint32_t>(propertyIndex);
  2265. if (mode > 0)
  2266. {
  2267. propertyIndex = material->FindPropertyIndex(s_opacity_factor_Name);
  2268. if (propertyIndex.IsValid())
  2269. {
  2270. opacity = material->GetPropertyValue<float>(propertyIndex);
  2271. }
  2272. }
  2273. }
  2274. subMeshMaterial.m_irradianceColor.SetA(opacity);
  2275. }
  2276. void ModelDataInstance::SetRayTracingReflectionProbeData(
  2277. MeshFeatureProcessor* meshFeatureProcessor,
  2278. RayTracingFeatureProcessor::Mesh::ReflectionProbe& reflectionProbe)
  2279. {
  2280. TransformServiceFeatureProcessor* transformServiceFeatureProcessor = meshFeatureProcessor->GetTransformServiceFeatureProcessor();
  2281. ReflectionProbeFeatureProcessor* reflectionProbeFeatureProcessor = meshFeatureProcessor->GetReflectionProbeFeatureProcessor();
  2282. AZ::Transform transform = transformServiceFeatureProcessor->GetTransformForId(m_objectId);
  2283. // retrieve reflection probes
  2284. Aabb aabbWS = m_aabb;
  2285. aabbWS.ApplyTransform(transform);
  2286. ReflectionProbeHandleVector reflectionProbeHandles;
  2287. reflectionProbeFeatureProcessor->FindReflectionProbes(aabbWS, reflectionProbeHandles);
  2288. m_flags.m_hasRayTracingReflectionProbe = !reflectionProbeHandles.empty();
  2289. if (m_flags.m_hasRayTracingReflectionProbe)
  2290. {
  2291. // take the last handle from the list, which will be the smallest (most influential) probe
  2292. ReflectionProbeHandle handle = reflectionProbeHandles.back();
  2293. reflectionProbe.m_modelToWorld = reflectionProbeFeatureProcessor->GetTransform(handle);
  2294. reflectionProbe.m_outerObbHalfLengths = reflectionProbeFeatureProcessor->GetOuterObbWs(handle).GetHalfLengths();
  2295. reflectionProbe.m_innerObbHalfLengths = reflectionProbeFeatureProcessor->GetInnerObbWs(handle).GetHalfLengths();
  2296. reflectionProbe.m_useParallaxCorrection = reflectionProbeFeatureProcessor->GetUseParallaxCorrection(handle);
  2297. reflectionProbe.m_exposure = reflectionProbeFeatureProcessor->GetRenderExposure(handle);
  2298. reflectionProbe.m_reflectionProbeCubeMap = reflectionProbeFeatureProcessor->GetCubeMap(handle);
  2299. }
  2300. }
  2301. void ModelDataInstance::RemoveRayTracingData(RayTracingFeatureProcessor* rayTracingFeatureProcessor)
  2302. {
  2303. // remove from ray tracing
  2304. if (rayTracingFeatureProcessor)
  2305. {
  2306. rayTracingFeatureProcessor->RemoveMesh(m_rayTracingUuid);
  2307. }
  2308. }
  2309. void ModelDataInstance::SetSortKey(MeshFeatureProcessor* meshFeatureProcessor, RHI::DrawItemSortKey sortKey)
  2310. {
  2311. RHI::DrawItemSortKey previousSortKey = m_sortKey;
  2312. m_sortKey = sortKey;
  2313. if (previousSortKey != m_sortKey)
  2314. {
  2315. if (!r_meshInstancingEnabled)
  2316. {
  2317. for (auto& drawPacketList : m_drawPacketListsByLod)
  2318. {
  2319. for (auto& drawPacket : drawPacketList)
  2320. {
  2321. drawPacket.SetSortKey(sortKey);
  2322. }
  2323. }
  2324. }
  2325. else
  2326. {
  2327. // If the ModelDataInstance has already been initialized
  2328. if (m_model && !m_flags.m_needsInit)
  2329. {
  2330. // DeInit/ReInit is overkill (destroys and re-creates ray-tracing data)
  2331. // but it works for now since SetSortKey is infrequent
  2332. // Init needs to be called because that is where we determine what can be part of the same instance group,
  2333. // and the sort key is part of that.
  2334. ReInit(meshFeatureProcessor);
  2335. }
  2336. }
  2337. }
  2338. }
  2339. RHI::DrawItemSortKey ModelDataInstance::GetSortKey() const
  2340. {
  2341. return m_sortKey;
  2342. }
  2343. void ModelDataInstance::SetMeshLodConfiguration(RPI::Cullable::LodConfiguration meshLodConfig)
  2344. {
  2345. m_cullable.m_lodData.m_lodConfiguration = meshLodConfig;
  2346. }
  2347. RPI::Cullable::LodConfiguration ModelDataInstance::GetMeshLodConfiguration() const
  2348. {
  2349. return m_cullable.m_lodData.m_lodConfiguration;
  2350. }
  2351. void ModelDataInstance::UpdateDrawPackets(bool forceUpdate /*= false*/)
  2352. {
  2353. AZ_Assert(!r_meshInstancingEnabled, "If mesh instancing is enabled, the draw packet update should be going through the MeshInstanceManager.");
  2354. // Only enable draw motion if model is dynamic and draw motion was disabled
  2355. bool enableDrawMotion = !m_flags.m_isDrawMotion && m_flags.m_dynamic;
  2356. RHI::DrawListTag meshMotionDrawListTag;
  2357. if (enableDrawMotion)
  2358. {
  2359. meshMotionDrawListTag = AZ::RHI::RHISystemInterface::Get()->GetDrawListTagRegistry()->FindTag(MeshCommon::MotionDrawListTagName);
  2360. }
  2361. for (auto& drawPacketList : m_drawPacketListsByLod)
  2362. {
  2363. for (auto& drawPacket : drawPacketList)
  2364. {
  2365. if (enableDrawMotion)
  2366. {
  2367. drawPacket.SetEnableDraw(meshMotionDrawListTag, true);
  2368. }
  2369. if (drawPacket.Update(*m_scene, forceUpdate))
  2370. {
  2371. m_flags.m_cullableNeedsRebuild = true;
  2372. }
  2373. }
  2374. }
  2375. }
  2376. void ModelDataInstance::BuildCullable()
  2377. {
  2378. AZ_Assert(m_flags.m_cullableNeedsRebuild, "This function only needs to be called if the cullable to be rebuilt");
  2379. AZ_Assert(m_model, "The model has not finished loading yet");
  2380. RPI::Cullable::CullData& cullData = m_cullable.m_cullData;
  2381. RPI::Cullable::LodData& lodData = m_cullable.m_lodData;
  2382. const Aabb& localAabb = m_aabb;
  2383. lodData.m_lodSelectionRadius = 0.5f * localAabb.GetExtents().GetMaxElement();
  2384. const size_t modelLodCount = m_model->GetLodCount();
  2385. const auto& lodAssets = m_model->GetModelAsset()->GetLodAssets();
  2386. AZ_Assert(lodAssets.size() == modelLodCount, "Number of asset lods must match number of model lods");
  2387. AZ_Assert(m_lodBias <= modelLodCount - 1, "Incorrect lod bias");
  2388. lodData.m_lods.resize(modelLodCount);
  2389. cullData.m_drawListMask.reset();
  2390. const size_t lodCount = lodAssets.size();
  2391. for (size_t lodIndex = 0; lodIndex < lodCount; ++lodIndex)
  2392. {
  2393. //initialize the lod
  2394. RPI::Cullable::LodData::Lod& lod = lodData.m_lods[lodIndex];
  2395. // non-used lod (except if forced)
  2396. if (lodIndex < m_lodBias)
  2397. {
  2398. // set impossible screen coverage to disable it
  2399. lod.m_screenCoverageMax = 0.0f;
  2400. lod.m_screenCoverageMin = 1.0f;
  2401. }
  2402. else
  2403. {
  2404. if (lodIndex == m_lodBias)
  2405. {
  2406. //first lod
  2407. lod.m_screenCoverageMax = 1.0f;
  2408. }
  2409. else
  2410. {
  2411. //every other lod: use the previous lod's min
  2412. lod.m_screenCoverageMax = AZStd::GetMax(lodData.m_lods[lodIndex - 1].m_screenCoverageMin, lodData.m_lodConfiguration.m_minimumScreenCoverage);
  2413. }
  2414. if (lodIndex < lodAssets.size() - 1)
  2415. {
  2416. //first and middle lods: compute a stepdown value for the min
  2417. lod.m_screenCoverageMin = AZStd::GetMax(lodData.m_lodConfiguration.m_qualityDecayRate * lod.m_screenCoverageMax, lodData.m_lodConfiguration.m_minimumScreenCoverage);
  2418. }
  2419. else
  2420. {
  2421. //last lod: use MinimumScreenCoverage for the min
  2422. lod.m_screenCoverageMin = lodData.m_lodConfiguration.m_minimumScreenCoverage;
  2423. }
  2424. }
  2425. lod.m_drawPackets.clear();
  2426. if (!r_meshInstancingEnabled)
  2427. {
  2428. const RPI::MeshDrawPacketList& drawPacketList = m_drawPacketListsByLod[lodIndex + m_lodBias];
  2429. for (const RPI::MeshDrawPacket& drawPacket : drawPacketList)
  2430. {
  2431. // If mesh instancing is disabled, get the draw packets directly from this ModelDataInstance
  2432. const RHI::DrawPacket* rhiDrawPacket = drawPacket.GetRHIDrawPacket();
  2433. if (rhiDrawPacket)
  2434. {
  2435. // OR-together all the drawListMasks (so we know which views to cull against)
  2436. cullData.m_drawListMask |= rhiDrawPacket->GetDrawListMask();
  2437. lod.m_drawPackets.push_back(rhiDrawPacket);
  2438. }
  2439. }
  2440. }
  2441. else
  2442. {
  2443. const PostCullingInstanceDataList& postCullingInstanceDataList = m_postCullingInstanceDataByLod[lodIndex + m_lodBias];
  2444. for (const ModelDataInstance::PostCullingInstanceData& postCullingData : postCullingInstanceDataList)
  2445. {
  2446. // If mesh instancing is enabled, get the draw packet from the MeshInstanceManager
  2447. const RHI::DrawPacket* rhiDrawPacket = postCullingData.m_instanceGroupHandle->m_drawPacket.GetRHIDrawPacket();
  2448. if (rhiDrawPacket)
  2449. {
  2450. // OR-together all the drawListMasks (so we know which views to cull against)
  2451. cullData.m_drawListMask |= rhiDrawPacket->GetDrawListMask();
  2452. }
  2453. // Set the user data for the cullable lod to reference the intance group handles for the lod
  2454. lod.m_visibleObjectUserData = static_cast<void*>(&m_postCullingInstanceDataByLod[lodIndex + m_lodBias]);
  2455. }
  2456. }
  2457. }
  2458. cullData.m_hideFlags = RPI::View::UsageNone;
  2459. if (m_descriptor.m_excludeFromReflectionCubeMaps)
  2460. {
  2461. cullData.m_hideFlags |= RPI::View::UsageReflectiveCubeMap;
  2462. }
  2463. #ifdef AZ_CULL_DEBUG_ENABLED
  2464. m_cullable.SetDebugName(AZ::Name(AZStd::string::format("%s - objectId: %u", m_model->GetModelAsset()->GetName().GetCStr(), m_objectId.GetIndex())));
  2465. #endif
  2466. m_flags.m_cullableNeedsRebuild = false;
  2467. m_flags.m_cullBoundsNeedsUpdate = true;
  2468. }
  2469. void ModelDataInstance::UpdateCullBounds(const MeshFeatureProcessor* meshFeatureProcessor)
  2470. {
  2471. AZ_Assert(m_flags.m_cullBoundsNeedsUpdate, "This function only needs to be called if the culling bounds need to be rebuilt");
  2472. AZ_Assert(m_model, "The model has not finished loading yet");
  2473. const TransformServiceFeatureProcessor* transformService = meshFeatureProcessor->GetTransformServiceFeatureProcessor();
  2474. Transform localToWorld = transformService->GetTransformForId(m_objectId);
  2475. Vector3 nonUniformScale = transformService->GetNonUniformScaleForId(m_objectId);
  2476. Vector3 center;
  2477. float radius;
  2478. Aabb localAabb = m_aabb;
  2479. localAabb.MultiplyByScale(nonUniformScale);
  2480. localAabb.GetTransformedAabb(localToWorld).GetAsSphere(center, radius);
  2481. m_cullable.m_lodData.m_lodSelectionRadius = 0.5f*localAabb.GetExtents().GetMaxElement();
  2482. m_cullable.m_cullData.m_boundingSphere = Sphere(center, radius);
  2483. m_cullable.m_cullData.m_boundingObb = localAabb.GetTransformedObb(localToWorld);
  2484. m_cullable.m_cullData.m_visibilityEntry.m_boundingVolume = localAabb.GetTransformedAabb(localToWorld);
  2485. m_cullable.m_cullData.m_visibilityEntry.m_userData = &m_cullable;
  2486. if (!r_meshInstancingEnabled)
  2487. {
  2488. m_cullable.m_cullData.m_visibilityEntry.m_typeFlags = AzFramework::VisibilityEntry::TYPE_RPI_Cullable;
  2489. }
  2490. else
  2491. {
  2492. m_cullable.m_cullData.m_visibilityEntry.m_typeFlags = AzFramework::VisibilityEntry::TYPE_RPI_VisibleObjectList;
  2493. }
  2494. m_scene->GetCullingScene()->RegisterOrUpdateCullable(m_cullable);
  2495. m_flags.m_cullBoundsNeedsUpdate = false;
  2496. }
  2497. void ModelDataInstance::UpdateObjectSrg(MeshFeatureProcessor* meshFeatureProcessor)
  2498. {
  2499. ReflectionProbeFeatureProcessor* reflectionProbeFeatureProcessor = meshFeatureProcessor->GetReflectionProbeFeatureProcessor();
  2500. TransformServiceFeatureProcessor* transformServiceFeatureProcessor = meshFeatureProcessor->GetTransformServiceFeatureProcessor();
  2501. for (auto& objectSrg : m_objectSrgList)
  2502. {
  2503. if (reflectionProbeFeatureProcessor && (m_descriptor.m_useForwardPassIblSpecular || m_flags.m_hasForwardPassIblSpecularMaterial))
  2504. {
  2505. // retrieve probe constant indices
  2506. AZ::RHI::ShaderInputConstantIndex modelToWorldConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_modelToWorld"));
  2507. AZ_Error("ModelDataInstance", modelToWorldConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
  2508. AZ::RHI::ShaderInputConstantIndex modelToWorldInverseConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_modelToWorldInverse"));
  2509. AZ_Error("ModelDataInstance", modelToWorldInverseConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
  2510. AZ::RHI::ShaderInputConstantIndex outerObbHalfLengthsConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_outerObbHalfLengths"));
  2511. AZ_Error("ModelDataInstance", outerObbHalfLengthsConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
  2512. AZ::RHI::ShaderInputConstantIndex innerObbHalfLengthsConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_innerObbHalfLengths"));
  2513. AZ_Error("ModelDataInstance", innerObbHalfLengthsConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
  2514. AZ::RHI::ShaderInputConstantIndex useReflectionProbeConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_useReflectionProbe"));
  2515. AZ_Error("ModelDataInstance", useReflectionProbeConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
  2516. AZ::RHI::ShaderInputConstantIndex useParallaxCorrectionConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_useParallaxCorrection"));
  2517. AZ_Error("ModelDataInstance", useParallaxCorrectionConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
  2518. AZ::RHI::ShaderInputConstantIndex exposureConstantIndex = objectSrg->FindShaderInputConstantIndex(Name("m_reflectionProbeData.m_exposure"));
  2519. AZ_Error("ModelDataInstance", exposureConstantIndex.IsValid(), "Failed to find ReflectionProbe constant index");
  2520. // retrieve probe cubemap index
  2521. Name reflectionCubeMapImageName = Name("m_reflectionProbeCubeMap");
  2522. RHI::ShaderInputImageIndex reflectionCubeMapImageIndex = objectSrg->FindShaderInputImageIndex(reflectionCubeMapImageName);
  2523. AZ_Error("ModelDataInstance", reflectionCubeMapImageIndex.IsValid(), "Failed to find shader image index [%s]", reflectionCubeMapImageName.GetCStr());
  2524. // retrieve the list of probes that overlap the mesh bounds
  2525. Transform transform = transformServiceFeatureProcessor->GetTransformForId(m_objectId);
  2526. Aabb aabbWS = m_aabb;
  2527. aabbWS.ApplyTransform(transform);
  2528. ReflectionProbeHandleVector reflectionProbeHandles;
  2529. reflectionProbeFeatureProcessor->FindReflectionProbes(aabbWS, reflectionProbeHandles);
  2530. if (!reflectionProbeHandles.empty())
  2531. {
  2532. // take the last handle from the list, which will be the smallest (most influential) probe
  2533. ReflectionProbeHandle handle = reflectionProbeHandles.back();
  2534. objectSrg->SetConstant(modelToWorldConstantIndex, Matrix3x4::CreateFromTransform(reflectionProbeFeatureProcessor->GetTransform(handle)));
  2535. objectSrg->SetConstant(modelToWorldInverseConstantIndex, Matrix3x4::CreateFromTransform(reflectionProbeFeatureProcessor->GetTransform(handle)).GetInverseFull());
  2536. objectSrg->SetConstant(outerObbHalfLengthsConstantIndex, reflectionProbeFeatureProcessor->GetOuterObbWs(handle).GetHalfLengths());
  2537. objectSrg->SetConstant(innerObbHalfLengthsConstantIndex, reflectionProbeFeatureProcessor->GetInnerObbWs(handle).GetHalfLengths());
  2538. objectSrg->SetConstant(useReflectionProbeConstantIndex, true);
  2539. objectSrg->SetConstant(useParallaxCorrectionConstantIndex, reflectionProbeFeatureProcessor->GetUseParallaxCorrection(handle));
  2540. objectSrg->SetConstant(exposureConstantIndex, reflectionProbeFeatureProcessor->GetRenderExposure(handle));
  2541. objectSrg->SetImage(reflectionCubeMapImageIndex, reflectionProbeFeatureProcessor->GetCubeMap(handle));
  2542. }
  2543. else
  2544. {
  2545. objectSrg->SetConstant(useReflectionProbeConstantIndex, false);
  2546. }
  2547. }
  2548. RHI::ShaderInputConstantIndex lightingChannelMaskIndex = objectSrg->FindShaderInputConstantIndex(AZ::Name("m_lightingChannelMask"));
  2549. if (lightingChannelMaskIndex.IsValid())
  2550. {
  2551. objectSrg->SetConstant(lightingChannelMaskIndex, m_lightingChannelMask);
  2552. }
  2553. objectSrg->Compile();
  2554. }
  2555. // Set m_objectSrgNeedsUpdate to false if there are object SRGs in the list
  2556. m_flags.m_objectSrgNeedsUpdate = m_flags.m_objectSrgNeedsUpdate && (m_objectSrgList.size() == 0);
  2557. }
  2558. bool ModelDataInstance::MaterialRequiresForwardPassIblSpecular(Data::Instance<RPI::Material> material) const
  2559. {
  2560. bool requiresForwardPassIbl = false;
  2561. // look for a shader that has the o_materialUseForwardPassIBLSpecular option set
  2562. // Note: this should be changed to have the material automatically set the forwardPassIBLSpecular
  2563. // property and look for that instead of the shader option.
  2564. // [GFX TODO][ATOM-5040] Address Property Metadata Feedback Loop
  2565. material->ForAllShaderItems(
  2566. [&](const Name&, const RPI::ShaderCollection::Item& shaderItem)
  2567. {
  2568. if (shaderItem.IsEnabled())
  2569. {
  2570. RPI::ShaderOptionIndex index = shaderItem.GetShaderOptionGroup().GetShaderOptionLayout()->FindShaderOptionIndex(Name{"o_materialUseForwardPassIBLSpecular"});
  2571. if (index.IsValid())
  2572. {
  2573. RPI::ShaderOptionValue value = shaderItem.GetShaderOptionGroup().GetValue(Name{"o_materialUseForwardPassIBLSpecular"});
  2574. if (value.GetIndex() == 1)
  2575. {
  2576. requiresForwardPassIbl = true;
  2577. return false; // break
  2578. }
  2579. }
  2580. }
  2581. return true; // continue
  2582. });
  2583. return requiresForwardPassIbl;
  2584. }
  2585. void ModelDataInstance::SetVisible(bool isVisible)
  2586. {
  2587. m_flags.m_visible = isVisible;
  2588. m_cullable.m_isHidden = !isVisible;
  2589. }
  2590. CustomMaterialInfo ModelDataInstance::GetCustomMaterialWithFallback(const CustomMaterialId& id) const
  2591. {
  2592. const CustomMaterialId ignoreLodId(DefaultCustomMaterialLodIndex, id.second);
  2593. for (const auto& currentId : { id, ignoreLodId, DefaultCustomMaterialId })
  2594. {
  2595. if (auto itr = m_descriptor.m_customMaterials.find(currentId); itr != m_descriptor.m_customMaterials.end() && itr->second.m_material)
  2596. {
  2597. return itr->second;
  2598. }
  2599. }
  2600. return CustomMaterialInfo{};
  2601. }
  2602. void ModelDataInstance::HandleDrawPacketUpdate()
  2603. {
  2604. // When the drawpacket is updated, the cullable must be rebuilt to use the latest draw packet
  2605. m_flags.m_cullableNeedsRebuild = true;
  2606. }
  2607. } // namespace Render
  2608. } // namespace AZ