3
0

MeshFeatureProcessor.cpp 145 KB

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