ClothComponentMesh.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  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 <AzCore/Interface/Interface.h>
  9. #include <AzCore/Console/IConsole.h>
  10. #include <AzCore/Math/PackedVector3.h>
  11. #include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
  12. #include <AtomLyIntegration/CommonFeatures/SkinnedMesh/SkinnedMeshOverrideBus.h>
  13. #include <Atom/RHI/RHIUtils.h>
  14. #include <NvCloth/IClothSystem.h>
  15. #include <NvCloth/IFabricCooker.h>
  16. #include <NvCloth/IClothConfigurator.h>
  17. #include <NvCloth/ITangentSpaceHelper.h>
  18. #include <Components/ClothComponentMesh/ActorClothColliders.h>
  19. #include <Components/ClothComponentMesh/ActorClothSkinning.h>
  20. #include <Components/ClothComponentMesh/ClothConstraints.h>
  21. #include <Components/ClothComponentMesh/ClothDebugDisplay.h>
  22. #include <Components/ClothComponentMesh/ClothComponentMesh.h>
  23. #include <AzFramework/Physics/PhysicsScene.h>
  24. #include <AzFramework/Physics/WindBus.h>
  25. #include <AzFramework/Physics/Common/PhysicsTypes.h>
  26. #include <Atom/RPI.Reflect/Buffer/BufferAssetView.h>
  27. #include <Atom/RPI.Reflect/Model/ModelAsset.h>
  28. #include <Atom/RPI.Reflect/Model/ModelLodAsset.h>
  29. namespace NvCloth
  30. {
  31. AZ_CVAR(float, cloth_DistanceToTeleport, 0.5f, nullptr, AZ::ConsoleFunctorFlags::Null,
  32. "The amount of meters the entity has to move in a frame to consider it a teleport for cloth.");
  33. AZ_CVAR(float, cloth_SecondsToDelaySimulationOnActorSpawned, 0.25f, nullptr, AZ::ConsoleFunctorFlags::Null,
  34. "The amount of time in seconds the cloth simulation will be delayed to avoid sudden impulses when actors are spawned.");
  35. // Helper class to map an RPI buffer from a buffer asset view.
  36. template<typename T>
  37. class MappedBuffer
  38. {
  39. public:
  40. MappedBuffer(
  41. const AZ::RPI::BufferAssetView* bufferAssetView,
  42. const size_t expectedElementCount,
  43. const AZ::RHI::Format expectedElementFormat);
  44. ~MappedBuffer();
  45. T* GetBuffer()
  46. {
  47. return m_buffer;
  48. }
  49. private:
  50. AZ::Data::Instance<AZ::RPI::Buffer> m_rpiBuffer;
  51. T* m_buffer = nullptr;
  52. };
  53. template<typename T>
  54. MappedBuffer<T>::MappedBuffer(
  55. const AZ::RPI::BufferAssetView* bufferAssetView,
  56. [[maybe_unused]] const size_t expectedElementCount,
  57. [[maybe_unused]] const AZ::RHI::Format expectedElementFormat)
  58. {
  59. if (!bufferAssetView)
  60. {
  61. return;
  62. }
  63. const AZ::RHI::BufferViewDescriptor& bufferViewDescriptor = bufferAssetView->GetBufferViewDescriptor();
  64. AZ_Assert(bufferViewDescriptor.m_elementCount == expectedElementCount,
  65. "Unexpected buffer size: expected is %d but descriptor's is %d", expectedElementCount, bufferViewDescriptor.m_elementCount);
  66. AZ_Assert(bufferViewDescriptor.m_elementSize == sizeof(T),
  67. "Unexpected buffer element size: expected is %d but descriptor's is %d", sizeof(T), bufferViewDescriptor.m_elementSize);
  68. AZ_Assert(bufferViewDescriptor.m_elementFormat == expectedElementFormat,
  69. "Unexpected buffer format: expected is %d but descriptor's is %d", expectedElementFormat, bufferViewDescriptor.m_elementFormat);
  70. const AZ::Data::Asset<AZ::RPI::BufferAsset>& bufferAsset = bufferAssetView->GetBufferAsset();
  71. m_rpiBuffer = AZ::RPI::Buffer::FindOrCreate(bufferAsset);
  72. if (m_rpiBuffer == nullptr)
  73. {
  74. AZ_Error("ClothComponentMesh", false,
  75. "Failed to find or create RPI buffer from buffer asset '%s'", bufferAsset.GetHint().c_str());
  76. return;
  77. }
  78. const uint64_t byteCount = aznumeric_cast<uint64_t>(bufferViewDescriptor.m_elementCount) * aznumeric_cast<uint64_t>(bufferViewDescriptor.m_elementSize);
  79. const uint64_t byteOffset = aznumeric_cast<uint64_t>(bufferViewDescriptor.m_elementOffset) * aznumeric_cast<uint64_t>(bufferViewDescriptor.m_elementSize);
  80. m_buffer = static_cast<T*>(m_rpiBuffer->Map(byteCount, byteOffset));
  81. }
  82. template<typename T>
  83. MappedBuffer<T>::~MappedBuffer()
  84. {
  85. if (m_buffer)
  86. {
  87. m_rpiBuffer->Unmap();
  88. }
  89. }
  90. ClothComponentMesh::ClothComponentMesh(AZ::EntityId entityId, const ClothConfiguration& config)
  91. : m_preSimulationEventHandler(
  92. [this](ClothId clothId, float deltaTime)
  93. {
  94. this->OnPreSimulation(clothId, deltaTime);
  95. })
  96. , m_postSimulationEventHandler(
  97. [this](ClothId clothId, float deltaTime, const AZStd::vector<SimParticleFormat>& updatedParticles)
  98. {
  99. this->OnPostSimulation(clothId, deltaTime, updatedParticles);
  100. })
  101. {
  102. Setup(entityId, config);
  103. }
  104. ClothComponentMesh::~ClothComponentMesh()
  105. {
  106. TearDown();
  107. }
  108. void ClothComponentMesh::UpdateConfiguration(AZ::EntityId entityId, const ClothConfiguration& config)
  109. {
  110. if (m_entityId != entityId ||
  111. m_config.m_meshNode != config.m_meshNode ||
  112. m_config.m_removeStaticTriangles != config.m_removeStaticTriangles)
  113. {
  114. Setup(entityId, config);
  115. }
  116. else if (m_cloth)
  117. {
  118. m_config = config;
  119. ApplyConfigurationToCloth();
  120. // Update the cloth constraints parameters
  121. m_clothConstraints->SetMotionConstraintMaxDistance(m_config.m_motionConstraintsMaxDistance);
  122. m_clothConstraints->SetBackstopMaxRadius(m_config.m_backstopRadius);
  123. m_clothConstraints->SetBackstopMaxOffsets(m_config.m_backstopBackOffset, m_config.m_backstopFrontOffset);
  124. UpdateSimulationConstraints();
  125. // Subscribe to WindNotificationsBus only if custom wind velocity flag is not set
  126. if (m_config.IsUsingWindBus())
  127. {
  128. Physics::WindNotificationsBus::Handler::BusConnect();
  129. }
  130. else
  131. {
  132. Physics::WindNotificationsBus::Handler::BusDisconnect();
  133. }
  134. }
  135. }
  136. void ClothComponentMesh::Setup(AZ::EntityId entityId, const ClothConfiguration& config)
  137. {
  138. TearDown();
  139. m_entityId = entityId;
  140. m_config = config;
  141. if (!CreateCloth())
  142. {
  143. TearDown();
  144. return;
  145. }
  146. // Initialize render data
  147. m_renderDataBufferIndex = 0;
  148. {
  149. auto& renderData = GetRenderData();
  150. renderData.m_particles = m_meshClothInfo.m_particles;
  151. renderData.m_tangents = m_meshClothInfo.m_tangents;
  152. renderData.m_bitangents = m_meshClothInfo.m_bitangents;
  153. renderData.m_normals = m_meshClothInfo.m_normals;
  154. }
  155. UpdateRenderData(m_cloth->GetParticles());
  156. // Copy the first initialized element to the rest of the buffer
  157. for (AZ::u32 i = 1; i < RenderDataBufferSize; ++i)
  158. {
  159. m_renderDataBuffer[i] = m_renderDataBuffer[0];
  160. }
  161. // It will return a valid instance if it's an actor with cloth colliders in it.
  162. m_actorClothColliders = ActorClothColliders::Create(m_entityId);
  163. // It will return a valid instance if it's an actor with skinning data.
  164. m_actorClothSkinning = ActorClothSkinning::Create(
  165. m_entityId,
  166. m_meshNodeInfo,
  167. m_meshClothInfo.m_particles,
  168. m_cloth->GetParticles().size(),
  169. m_meshRemappedVertices);
  170. m_timeClothSkinningUpdates = 0.0f;
  171. // Turn off GPU skinning for any sub-meshes simulated by the cloth component
  172. DisableSkinning();
  173. m_clothConstraints = ClothConstraints::Create(
  174. m_meshClothInfo.m_motionConstraints,
  175. m_config.m_motionConstraintsMaxDistance,
  176. m_meshClothInfo.m_backstopData,
  177. m_config.m_backstopRadius,
  178. m_config.m_backstopBackOffset,
  179. m_config.m_backstopFrontOffset,
  180. m_cloth->GetParticles(),
  181. m_cloth->GetInitialIndices(),
  182. m_meshRemappedVertices);
  183. AZ_Assert(m_clothConstraints, "Failed to create cloth constraints");
  184. UpdateSimulationConstraints();
  185. #ifndef RELEASE
  186. m_clothDebugDisplay = AZStd::make_unique<ClothDebugDisplay>(this);
  187. #endif
  188. AZ::TransformNotificationBus::Handler::BusConnect(m_entityId);
  189. AZ::TickBus::Handler::BusConnect();
  190. m_cloth->ConnectPreSimulationEventHandler(m_preSimulationEventHandler);
  191. m_cloth->ConnectPostSimulationEventHandler(m_postSimulationEventHandler);
  192. if (m_config.IsUsingWindBus())
  193. {
  194. Physics::WindNotificationsBus::Handler::BusConnect();
  195. }
  196. }
  197. void ClothComponentMesh::TearDown()
  198. {
  199. if (m_cloth)
  200. {
  201. Physics::WindNotificationsBus::Handler::BusDisconnect();
  202. AZ::TickBus::Handler::BusDisconnect();
  203. AZ::TransformNotificationBus::Handler::BusDisconnect();
  204. m_preSimulationEventHandler.Disconnect();
  205. m_postSimulationEventHandler.Disconnect();
  206. AZ::Interface<IClothSystem>::Get()->RemoveCloth(m_cloth);
  207. AZ::Interface<IClothSystem>::Get()->DestroyCloth(m_cloth);
  208. // Re-enable skinning for any sub-meshes that were previously skinned by the cloth component
  209. EnableSkinning();
  210. }
  211. m_entityId.SetInvalid();
  212. m_renderDataBuffer = {};
  213. m_meshRemappedVertices.clear();
  214. m_meshNodeInfo = {};
  215. m_meshClothInfo = {};
  216. m_actorClothColliders.reset();
  217. m_actorClothSkinning.reset();
  218. m_clothConstraints.reset();
  219. m_motionConstraints.clear();
  220. m_separationConstraints.clear();
  221. m_clothDebugDisplay.reset();
  222. }
  223. void ClothComponentMesh::OnPreSimulation(
  224. [[maybe_unused]] ClothId clothId,
  225. float deltaTime)
  226. {
  227. AZ_PROFILE_FUNCTION(Cloth);
  228. UpdateSimulationCollisions();
  229. if (m_actorClothSkinning)
  230. {
  231. UpdateSimulationSkinning(deltaTime);
  232. UpdateSimulationConstraints();
  233. }
  234. }
  235. void ClothComponentMesh::OnPostSimulation(
  236. [[maybe_unused]] ClothId clothId,
  237. [[maybe_unused]] float deltaTime,
  238. const AZStd::vector<SimParticleFormat>& updatedParticles)
  239. {
  240. AZ_PROFILE_FUNCTION(Cloth);
  241. // Next buffer index of the render data
  242. m_renderDataBufferIndex = (m_renderDataBufferIndex + 1) % RenderDataBufferSize;
  243. UpdateRenderData(updatedParticles);
  244. }
  245. void ClothComponentMesh::OnTransformChanged([[maybe_unused]] const AZ::Transform& local, const AZ::Transform& world)
  246. {
  247. // At the moment there is no way to distinguish "move" from "teleport".
  248. // As a workaround we will consider a teleport if the position has changed considerably.
  249. bool teleport = (m_worldPosition.GetDistance(world.GetTranslation()) >= cloth_DistanceToTeleport);
  250. if (teleport)
  251. {
  252. TeleportCloth(world);
  253. }
  254. else
  255. {
  256. MoveCloth(world);
  257. }
  258. }
  259. void ClothComponentMesh::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
  260. {
  261. CopyRenderDataToModel();
  262. }
  263. int ClothComponentMesh::GetTickOrder()
  264. {
  265. return AZ::TICK_PRE_RENDER;
  266. }
  267. void ClothComponentMesh::OnGlobalWindChanged()
  268. {
  269. m_cloth->GetClothConfigurator()->SetWindVelocity(GetWindBusVelocity());
  270. }
  271. void ClothComponentMesh::OnWindChanged([[maybe_unused]] const AZ::Aabb& aabb)
  272. {
  273. OnGlobalWindChanged();
  274. }
  275. ClothComponentMesh::RenderData& ClothComponentMesh::GetRenderData()
  276. {
  277. return const_cast<RenderData&>(
  278. static_cast<const ClothComponentMesh&>(*this).GetRenderData());
  279. }
  280. const ClothComponentMesh::RenderData& ClothComponentMesh::GetRenderData() const
  281. {
  282. return m_renderDataBuffer[m_renderDataBufferIndex];
  283. }
  284. void ClothComponentMesh::UpdateSimulationCollisions()
  285. {
  286. if (m_actorClothColliders)
  287. {
  288. AZ_PROFILE_FUNCTION(Cloth);
  289. m_actorClothColliders->Update();
  290. const auto& spheres = m_actorClothColliders->GetSpheres();
  291. m_cloth->GetClothConfigurator()->SetSphereColliders(spheres);
  292. const auto& capsuleIndices = m_actorClothColliders->GetCapsuleIndices();
  293. m_cloth->GetClothConfigurator()->SetCapsuleColliders(capsuleIndices);
  294. }
  295. }
  296. void ClothComponentMesh::UpdateSimulationSkinning(float deltaTime)
  297. {
  298. if (m_actorClothSkinning)
  299. {
  300. AZ_PROFILE_FUNCTION(Cloth);
  301. m_actorClothSkinning->UpdateSkinning();
  302. // Since component activation order is not trivial, the actor's pose might not be updated
  303. // immediately. Because of this cloth will receive a sudden impulse when changing from
  304. // T pose to animated pose. To avoid this undesired effect we will override cloth simulation during
  305. // a short amount of time.
  306. m_timeClothSkinningUpdates += deltaTime;
  307. // While the actor is not visible the skinned joints are not updated. Then when
  308. // it becomes visible the jump to the new skinned positions causes a sudden
  309. // impulse to cloth simulation. To avoid this undesired effect we will override cloth simulation during
  310. // a short amount of time.
  311. m_actorClothSkinning->UpdateActorVisibility();
  312. if (!m_actorClothSkinning->WasActorVisible() &&
  313. m_actorClothSkinning->IsActorVisible())
  314. {
  315. m_timeClothSkinningUpdates = 0.0f;
  316. }
  317. if (m_timeClothSkinningUpdates <= cloth_SecondsToDelaySimulationOnActorSpawned)
  318. {
  319. // Update skinning for all particles and apply it to cloth
  320. AZStd::vector<SimParticleFormat> particles = m_cloth->GetParticles();
  321. m_actorClothSkinning->ApplySkinning(m_cloth->GetInitialParticles(), particles);
  322. m_cloth->SetParticles(AZStd::move(particles));
  323. m_cloth->DiscardParticleDelta();
  324. }
  325. }
  326. }
  327. void ClothComponentMesh::UpdateSimulationConstraints()
  328. {
  329. AZ_PROFILE_FUNCTION(Cloth);
  330. m_motionConstraints = m_clothConstraints->GetMotionConstraints();
  331. m_separationConstraints = m_clothConstraints->GetSeparationConstraints();
  332. if (m_actorClothSkinning)
  333. {
  334. m_actorClothSkinning->ApplySkinning(m_clothConstraints->GetMotionConstraints(), m_motionConstraints);
  335. m_actorClothSkinning->ApplySkinning(m_clothConstraints->GetSeparationConstraints(), m_separationConstraints);
  336. }
  337. m_cloth->GetClothConfigurator()->SetMotionConstraints(m_motionConstraints);
  338. if (!m_separationConstraints.empty())
  339. {
  340. m_cloth->GetClothConfigurator()->SetSeparationConstraints(m_separationConstraints);
  341. }
  342. }
  343. void ClothComponentMesh::UpdateRenderData(const AZStd::vector<SimParticleFormat>& particles)
  344. {
  345. AZ_PROFILE_FUNCTION(Cloth);
  346. if (!m_cloth)
  347. {
  348. return;
  349. }
  350. auto& renderData = GetRenderData();
  351. if (m_actorClothSkinning)
  352. {
  353. // Apply skinning to the non-simulated part of the mesh.
  354. m_actorClothSkinning->ApplySkinningOnNonSimulatedVertices(m_meshClothInfo, renderData);
  355. }
  356. // Calculate normals of the cloth particles (simplified mesh).
  357. AZStd::vector<AZ::Vector3> normals;
  358. [[maybe_unused]] bool normalsCalculated =
  359. AZ::Interface<ITangentSpaceHelper>::Get()->CalculateNormals(particles, m_cloth->GetInitialIndices(), normals);
  360. AZ_Assert(normalsCalculated, "Cloth component mesh failed to calculate normals.");
  361. // Copy particles and normals to render data.
  362. // Since cloth's vertices were welded together,
  363. // the full mesh will result in smooth normals.
  364. for (size_t index = 0; index < m_meshRemappedVertices.size(); ++index)
  365. {
  366. const int remappedIndex = m_meshRemappedVertices[index];
  367. if (remappedIndex >= 0)
  368. {
  369. renderData.m_particles[index] = particles[remappedIndex];
  370. // For static particles only use the updated normal when indicated in the configuration.
  371. const bool useSimulatedClothParticleNormal =
  372. m_meshClothInfo.m_particles[index].GetW() != 0.0f ||
  373. m_config.m_updateNormalsOfStaticParticles;
  374. if (useSimulatedClothParticleNormal)
  375. {
  376. renderData.m_normals[index] = normals[remappedIndex];
  377. }
  378. }
  379. }
  380. // Calculate tangents and bitangents for the full mesh.
  381. [[maybe_unused]] bool tangentsAndBitangentsCalculated =
  382. AZ::Interface<ITangentSpaceHelper>::Get()->CalculateTangentsAndBitagents(
  383. renderData.m_particles, m_meshClothInfo.m_indices,
  384. m_meshClothInfo.m_uvs, renderData.m_normals,
  385. renderData.m_tangents, renderData.m_bitangents);
  386. AZ_Assert(tangentsAndBitangentsCalculated, "Cloth component mesh failed to calculate tangents and bitangents.");
  387. }
  388. void ClothComponentMesh::CopyRenderDataToModel()
  389. {
  390. AZ_PROFILE_FUNCTION(Cloth);
  391. // Previous buffer index of the render data
  392. const AZ::u32 previousBufferIndex = (m_renderDataBufferIndex + RenderDataBufferSize - 1) % RenderDataBufferSize;
  393. // Workaround to sync debug drawing with cloth rendering as
  394. // the Entity Debug Display Bus renders on the next frame.
  395. const bool isDebugDrawEnabled = m_clothDebugDisplay && m_clothDebugDisplay->IsDebugDrawEnabled();
  396. const RenderData& renderData = (isDebugDrawEnabled)
  397. ? m_renderDataBuffer[previousBufferIndex]
  398. : m_renderDataBuffer[m_renderDataBufferIndex];
  399. const auto& renderParticles = renderData.m_particles;
  400. const auto& renderNormals = renderData.m_normals;
  401. const auto& renderTangents = renderData.m_tangents;
  402. const auto& renderBitangents = renderData.m_bitangents;
  403. // Since Atom has a 1:1 relation with between ModelAsset buffers and Model buffers,
  404. // internally it created a new asset for the model instance. So it's important to
  405. // get the asset from the model when we want to write to them, instead of getting the
  406. // ModelAsset directly from the bus (which returns the original asset shared by all entities).
  407. AZ::Data::Instance<AZ::RPI::Model> model;
  408. AZ::Render::MeshComponentRequestBus::EventResult(model, m_entityId, &AZ::Render::MeshComponentRequestBus::Events::GetModel);
  409. if (!model)
  410. {
  411. return;
  412. }
  413. AZ::Data::Asset<AZ::RPI::ModelAsset> modelAsset = model->GetModelAsset();
  414. if (!modelAsset.IsReady())
  415. {
  416. return;
  417. }
  418. if (modelAsset->GetLodCount() < m_meshNodeInfo.m_lodLevel)
  419. {
  420. AZ_Error("ClothComponentMesh", false,
  421. "Unable to access lod %d from model asset '%s' as it only has %d lod levels.",
  422. m_meshNodeInfo.m_lodLevel,
  423. modelAsset.GetHint().c_str(),
  424. modelAsset->GetLodCount());
  425. return;
  426. }
  427. const auto modelLodAssets = modelAsset->GetLodAssets();
  428. const AZ::Data::Asset<AZ::RPI::ModelLodAsset> modelLodAsset = modelLodAssets[m_meshNodeInfo.m_lodLevel];
  429. if (!modelLodAsset.GetId().IsValid())
  430. {
  431. AZ_Error("ClothComponentMesh", false,
  432. "Model asset '%s' returns an invalid lod asset '%s' (lod level %d).",
  433. modelAsset.GetHint().c_str(),
  434. modelLodAsset.GetHint().c_str(),
  435. m_meshNodeInfo.m_lodLevel);
  436. return;
  437. }
  438. const AZ::Name positionSemantic("POSITION");
  439. const AZ::Name normalSemantic("NORMAL");
  440. const AZ::Name tangentSemantic("TANGENT");
  441. const AZ::Name bitangentSemantic("BITANGENT");
  442. // For each submesh...
  443. for (const auto& subMeshInfo : m_meshNodeInfo.m_subMeshes)
  444. {
  445. if (modelLodAsset->GetMeshes().size() < subMeshInfo.m_primitiveIndex)
  446. {
  447. AZ_Error("ClothComponentMesh", false,
  448. "Unable to access submesh %d from lod asset '%s' as it only has %d submeshes.",
  449. subMeshInfo.m_primitiveIndex,
  450. modelAsset.GetHint().c_str(),
  451. modelLodAsset->GetMeshes().size());
  452. continue;
  453. }
  454. const auto subMeshes = modelLodAsset->GetMeshes();
  455. const AZ::RPI::ModelLodAsset::Mesh& subMesh = subMeshes[subMeshInfo.m_primitiveIndex];
  456. const int numVertices = subMeshInfo.m_numVertices;
  457. const int firstVertex = subMeshInfo.m_verticesFirstIndex;
  458. if (subMesh.GetVertexCount() != static_cast<uint32_t>(numVertices))
  459. {
  460. AZ_Error("ClothComponentMesh", false,
  461. "Render mesh to be modified doesn't have the same number of vertices (%d) as the cloth's submesh (%d).",
  462. subMesh.GetVertexCount(),
  463. numVertices);
  464. continue;
  465. }
  466. AZ_Assert(firstVertex >= 0, "Invalid first vertex index %d", firstVertex);
  467. AZ_Assert((firstVertex + numVertices) <= static_cast<int>(renderParticles.size()),
  468. "Submesh number of vertices (%d) reaches outside the particles (%zu)", (firstVertex + numVertices), renderParticles.size());
  469. MappedBuffer<AZ::PackedVector3f> destVertices(subMesh.GetSemanticBufferAssetView(positionSemantic), numVertices, AZ::RHI::Format::R32G32B32_FLOAT);
  470. MappedBuffer<AZ::PackedVector3f> destNormals(subMesh.GetSemanticBufferAssetView(normalSemantic), numVertices, AZ::RHI::Format::R32G32B32_FLOAT);
  471. MappedBuffer<AZ::Vector4> destTangents(subMesh.GetSemanticBufferAssetView(tangentSemantic), numVertices, AZ::RHI::Format::R32G32B32A32_FLOAT);
  472. MappedBuffer<AZ::PackedVector3f> destBitangents(subMesh.GetSemanticBufferAssetView(bitangentSemantic), numVertices, AZ::RHI::Format::R32G32B32_FLOAT);
  473. auto* destVerticesBuffer = destVertices.GetBuffer();
  474. auto* destNormalsBuffer = destNormals.GetBuffer();
  475. auto* destTangentsBuffer = destTangents.GetBuffer();
  476. auto* destBitangentsBuffer = destBitangents.GetBuffer();
  477. if (!destVerticesBuffer)
  478. {
  479. AZ_Error("ClothComponentMesh", AZ::RHI::IsNullRHI(),
  480. "Invalid vertex position buffer obtained from the render mesh to be modified.");
  481. continue;
  482. }
  483. for (size_t index = 0; index < numVertices; ++index)
  484. {
  485. const int renderVertexIndex = static_cast<int>(firstVertex + index);
  486. const SimParticleFormat& renderParticle = renderParticles[renderVertexIndex];
  487. destVerticesBuffer[index].Set(
  488. renderParticle.GetX(),
  489. renderParticle.GetY(),
  490. renderParticle.GetZ());
  491. if (destNormalsBuffer)
  492. {
  493. const AZ::Vector3& renderNormal = renderNormals[renderVertexIndex];
  494. destNormalsBuffer[index].Set(
  495. renderNormal.GetX(),
  496. renderNormal.GetY(),
  497. renderNormal.GetZ());
  498. }
  499. if (destTangentsBuffer)
  500. {
  501. const AZ::Vector3& renderTangent = renderTangents[renderVertexIndex];
  502. destTangentsBuffer[index].Set(
  503. renderTangent,
  504. -1.0f); // Shader function ConstructTBN inverts w to change bitangent sign, but the bitangents passed are already corrected, so passing -1.0 to counteract.
  505. }
  506. if (destBitangentsBuffer)
  507. {
  508. const AZ::Vector3& renderBitangent = renderBitangents[renderVertexIndex];
  509. destBitangentsBuffer[index].Set(
  510. renderBitangent.GetX(),
  511. renderBitangent.GetY(),
  512. renderBitangent.GetZ());
  513. }
  514. }
  515. }
  516. }
  517. bool ClothComponentMesh::CreateCloth()
  518. {
  519. AZStd::unique_ptr<AssetHelper> assetHelper = AssetHelper::CreateAssetHelper(m_entityId);
  520. if (!assetHelper)
  521. {
  522. return false;
  523. }
  524. // Obtain cloth mesh info
  525. bool clothInfoObtained = assetHelper->ObtainClothMeshNodeInfo(m_config.m_meshNode,
  526. m_meshNodeInfo, m_meshClothInfo);
  527. if (!clothInfoObtained)
  528. {
  529. return false;
  530. }
  531. // Generate a simplified mesh for simulation
  532. AZStd::vector<SimParticleFormat> meshSimplifiedParticles;
  533. AZStd::vector<SimIndexType> meshSimplifiedIndices;
  534. AZ::Interface<IFabricCooker>::Get()->SimplifyMesh(
  535. m_meshClothInfo.m_particles, m_meshClothInfo.m_indices,
  536. meshSimplifiedParticles, meshSimplifiedIndices,
  537. m_meshRemappedVertices,
  538. m_config.m_removeStaticTriangles);
  539. if (meshSimplifiedParticles.empty() ||
  540. meshSimplifiedIndices.empty())
  541. {
  542. return false;
  543. }
  544. // Cook Fabric
  545. AZStd::optional<FabricCookedData> cookedData =
  546. AZ::Interface<IFabricCooker>::Get()->CookFabric(meshSimplifiedParticles, meshSimplifiedIndices);
  547. if (!cookedData)
  548. {
  549. return false;
  550. }
  551. // Create cloth instance
  552. m_cloth = AZ::Interface<IClothSystem>::Get()->CreateCloth(meshSimplifiedParticles, *cookedData);
  553. if (!m_cloth)
  554. {
  555. return false;
  556. }
  557. // Set initial Position and Rotation
  558. AZ::Transform transform = AZ::Transform::CreateIdentity();
  559. AZ::TransformBus::EventResult(transform, m_entityId, &AZ::TransformInterface::GetWorldTM);
  560. TeleportCloth(transform);
  561. ApplyConfigurationToCloth();
  562. // Add cloth to default solver to be simulated
  563. AZ::Interface<IClothSystem>::Get()->AddCloth(m_cloth);
  564. return true;
  565. }
  566. void ClothComponentMesh::ApplyConfigurationToCloth()
  567. {
  568. IClothConfigurator* clothConfig = m_cloth->GetClothConfigurator();
  569. // Mass
  570. clothConfig->SetMass(m_config.m_mass);
  571. // Gravity and scale
  572. if (m_config.IsUsingWorldBusGravity())
  573. {
  574. AZ::Vector3 gravity = AzPhysics::DefaultGravity;
  575. if (auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get())
  576. {
  577. AzPhysics::SceneHandle defaultScene = sceneInterface->GetSceneHandle(AzPhysics::DefaultPhysicsSceneName);
  578. if (defaultScene != AzPhysics::InvalidSceneHandle)
  579. {
  580. gravity = sceneInterface->GetGravity(defaultScene);
  581. }
  582. }
  583. clothConfig->SetGravity(gravity * m_config.m_gravityScale);
  584. }
  585. else
  586. {
  587. clothConfig->SetGravity(m_config.m_customGravity * m_config.m_gravityScale);
  588. }
  589. // Stiffness Frequency
  590. clothConfig->SetStiffnessFrequency(m_config.m_stiffnessFrequency);
  591. // Motion constraints parameters
  592. clothConfig->SetMotionConstraintsScale(m_config.m_motionConstraintsScale);
  593. clothConfig->SetMotionConstraintsBias(m_config.m_motionConstraintsBias);
  594. clothConfig->SetMotionConstraintsStiffness(m_config.m_motionConstraintsStiffness);
  595. // Damping parameters
  596. clothConfig->SetDamping(m_config.m_damping);
  597. clothConfig->SetDampingLinearDrag(m_config.m_linearDrag);
  598. clothConfig->SetDampingAngularDrag(m_config.m_angularDrag);
  599. // Inertia parameters
  600. clothConfig->SetLinearInertia(m_config.m_linearInteria);
  601. clothConfig->SetAngularInertia(m_config.m_angularInteria);
  602. clothConfig->SetCentrifugalInertia(m_config.m_centrifugalInertia);
  603. // Wind parameters
  604. if (m_config.IsUsingWindBus())
  605. {
  606. clothConfig->SetWindVelocity(GetWindBusVelocity());
  607. }
  608. else
  609. {
  610. clothConfig->SetWindVelocity(m_config.m_windVelocity);
  611. }
  612. clothConfig->SetWindDragCoefficient(m_config.m_airDragCoefficient);
  613. clothConfig->SetWindLiftCoefficient(m_config.m_airLiftCoefficient);
  614. clothConfig->SetWindFluidDensity(m_config.m_fluidDensity);
  615. // Collision parameters
  616. clothConfig->SetCollisionFriction(m_config.m_collisionFriction);
  617. clothConfig->SetCollisionMassScale(m_config.m_collisionMassScale);
  618. clothConfig->EnableContinuousCollision(m_config.m_continuousCollisionDetection);
  619. clothConfig->SetCollisionAffectsStaticParticles(m_config.m_collisionAffectsStaticParticles);
  620. // Self Collision parameters
  621. clothConfig->SetSelfCollisionDistance(m_config.m_selfCollisionDistance);
  622. clothConfig->SetSelfCollisionStiffness(m_config.m_selfCollisionStiffness);
  623. // Tether Constraints parameters
  624. clothConfig->SetTetherConstraintStiffness(m_config.m_tetherConstraintStiffness);
  625. clothConfig->SetTetherConstraintScale(m_config.m_tetherConstraintScale);
  626. // Quality parameters
  627. clothConfig->SetSolverFrequency(m_config.m_solverFrequency);
  628. clothConfig->SetAcceleationFilterWidth(m_config.m_accelerationFilterIterations);
  629. // Fabric Phases
  630. clothConfig->SetVerticalPhaseConfig(
  631. m_config.m_verticalStiffness,
  632. m_config.m_verticalStiffnessMultiplier,
  633. m_config.m_verticalCompressionLimit,
  634. m_config.m_verticalStretchLimit);
  635. clothConfig->SetHorizontalPhaseConfig(
  636. m_config.m_horizontalStiffness,
  637. m_config.m_horizontalStiffnessMultiplier,
  638. m_config.m_horizontalCompressionLimit,
  639. m_config.m_horizontalStretchLimit);
  640. clothConfig->SetBendingPhaseConfig(
  641. m_config.m_bendingStiffness,
  642. m_config.m_bendingStiffnessMultiplier,
  643. m_config.m_bendingCompressionLimit,
  644. m_config.m_bendingStretchLimit);
  645. clothConfig->SetShearingPhaseConfig(
  646. m_config.m_shearingStiffness,
  647. m_config.m_shearingStiffnessMultiplier,
  648. m_config.m_shearingCompressionLimit,
  649. m_config.m_shearingStretchLimit);
  650. }
  651. void ClothComponentMesh::MoveCloth(const AZ::Transform& worldTransform)
  652. {
  653. m_worldPosition = worldTransform.GetTranslation();
  654. m_cloth->GetClothConfigurator()->SetTransform(worldTransform);
  655. if (m_config.IsUsingWindBus())
  656. {
  657. // Wind velocity is affected by world position
  658. m_cloth->GetClothConfigurator()->SetWindVelocity(GetWindBusVelocity());
  659. }
  660. }
  661. void ClothComponentMesh::TeleportCloth(const AZ::Transform& worldTransform)
  662. {
  663. MoveCloth(worldTransform);
  664. // By clearing inertia the cloth won't be affected by the sudden translation caused when teleporting the entity.
  665. m_cloth->GetClothConfigurator()->ClearInertia();
  666. }
  667. AZ::Vector3 ClothComponentMesh::GetWindBusVelocity()
  668. {
  669. const Physics::WindRequests* windRequests = AZ::Interface<Physics::WindRequests>::Get();
  670. if (windRequests)
  671. {
  672. const AZ::Vector3 globalWind = windRequests->GetGlobalWind();
  673. const AZ::Vector3 localWind = windRequests->GetWind(m_worldPosition);
  674. return globalWind + localWind;
  675. }
  676. return AZ::Vector3::CreateZero();
  677. }
  678. void ClothComponentMesh::EnableSkinning() const
  679. {
  680. if (m_actorClothSkinning)
  681. {
  682. for (const auto& subMeshInfo : m_meshNodeInfo.m_subMeshes)
  683. {
  684. AZ::Render::SkinnedMeshOverrideRequestBus::Event(
  685. m_entityId,
  686. &AZ::Render::SkinnedMeshOverrideRequestBus::Events::EnableSkinning,
  687. aznumeric_cast<uint32_t>(m_meshNodeInfo.m_lodLevel), aznumeric_cast<uint32_t>(subMeshInfo.m_primitiveIndex));
  688. }
  689. }
  690. }
  691. void ClothComponentMesh::DisableSkinning() const
  692. {
  693. if (m_actorClothSkinning)
  694. {
  695. for (const auto& subMeshInfo : m_meshNodeInfo.m_subMeshes)
  696. {
  697. AZ::Render::SkinnedMeshOverrideRequestBus::Event(
  698. m_entityId,
  699. &AZ::Render::SkinnedMeshOverrideRequestBus::Events::DisableSkinning,
  700. aznumeric_cast<uint32_t>(m_meshNodeInfo.m_lodLevel), aznumeric_cast<uint32_t>(subMeshInfo.m_primitiveIndex));
  701. }
  702. }
  703. }
  704. } // namespace NvCloth