Cloth.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  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/Math/Transform.h>
  9. #include <AzCore/Math/Quaternion.h>
  10. #include <System/Cloth.h>
  11. #include <System/Fabric.h>
  12. #include <System/Solver.h>
  13. // NvCloth library includes
  14. #include <NvCloth/Cloth.h>
  15. #include <NvClothExt/ClothFabricCooker.h>
  16. #include <foundation/PxVec3.h>
  17. #include <foundation/PxVec4.h>
  18. #include <foundation/PxQuat.h>
  19. AZ_DEFINE_BUDGET(Cloth);
  20. namespace NvCloth
  21. {
  22. namespace Internal
  23. {
  24. // Returns AZ::Vector3 as physx::PxVec3 using the same memory.
  25. // It's safe to reinterpret AZ::Vector3 as physx::PxVec3 because they have the same memory layout
  26. // and AZ::Vector3 has more memory alignment restrictions than physx::PxVec3.
  27. // The opposite operation would NOT be safe.
  28. physx::PxVec3& AsPxVec3(AZ::Vector3& azVec)
  29. {
  30. return *reinterpret_cast<physx::PxVec3*>(&azVec);
  31. }
  32. const physx::PxVec3& AsPxVec3(const AZ::Vector3& azVec)
  33. {
  34. return *reinterpret_cast<const physx::PxVec3*>(&azVec);
  35. }
  36. // Returns AZ::Quaternion as physx::PxQuat using the same memory.
  37. // It's safe to reinterpret AZ::Quaternion as physx::PxQuat because they have the same memory layout
  38. // and AZ::Quaternion has more memory alignment restrictions than physx::PxQuat.
  39. // The opposite operation would NOT be safe.
  40. physx::PxQuat& AsPxQuat(AZ::Quaternion& azQuat)
  41. {
  42. return *reinterpret_cast<physx::PxQuat*>(&azQuat);
  43. }
  44. const physx::PxQuat& AsPxQuat(const AZ::Quaternion& azQuat)
  45. {
  46. return *reinterpret_cast<const physx::PxQuat*>(&azQuat);
  47. }
  48. // Copies an AZ vector of AZ::Vector4 elements as a NvCloth Range of physx::PxVec4 elements.
  49. //
  50. // It's safe to reinterpret AZ::Vector4 as physx::PxVec4 because they have the same memory layout.
  51. // Each one has its own memory with their appropriate alignments.
  52. void FastCopy(const AZStd::vector<AZ::Vector4>& azVector, nv::cloth::Range<physx::PxVec4>& nvRange)
  53. {
  54. AZ_Assert(azVector.size() == nvRange.size(),
  55. "Mismatch in number of elements. AZ vector: %zu Nv Range: %u", azVector.size(), nvRange.size());
  56. static_assert(sizeof(physx::PxVec4) == sizeof(AZ::Vector4), "physx::PxVec4 and AZ::Vector4 types have different sizes");
  57. // Reinterpret cast to floats so it does a fast copy.
  58. AZStd::copy(
  59. reinterpret_cast<const float*>(azVector.data()),
  60. reinterpret_cast<const float*>(azVector.data() + azVector.size()),
  61. reinterpret_cast<float*>(nvRange.begin()));
  62. }
  63. // Copies a NvCloth Range of physx::PxVec4 elements as an AZ vector of AZ::Vector4 elements.
  64. //
  65. // It's safe to reinterpret AZ::Vector4 as physx::PxVec4 because they have the same memory layout.
  66. // Each one has its own memory with their appropriate alignments.
  67. void FastCopy(const nv::cloth::Range<physx::PxVec4>& nvRange, AZStd::vector<AZ::Vector4>& azVector)
  68. {
  69. AZ_Assert(azVector.size() == nvRange.size(),
  70. "Mismatch in number of elements. AZ vector: %zu Nv Range: %u", azVector.size(), nvRange.size());
  71. static_assert(sizeof(physx::PxVec4) == sizeof(AZ::Vector4), "physx::PxVec4 and AZ::Vector4 types have different sizes");
  72. // Reinterpret cast to floats so it does a fast copy.
  73. AZStd::copy(
  74. reinterpret_cast<const float*>(nvRange.begin()),
  75. reinterpret_cast<const float*>(nvRange.end()),
  76. reinterpret_cast<float*>(azVector.begin()));
  77. }
  78. // Moves an AZ vector of AZ::Vector4 elements as a NvCloth Range of physx::PxVec4 elements.
  79. //
  80. // It's safe to reinterpret AZ::Vector4 as physx::PxVec4 because they have the same memory layout.
  81. // Each one has its own memory with their appropriate alignments.
  82. void FastMove(AZStd::vector<AZ::Vector4>&& azVector, nv::cloth::Range<physx::PxVec4>& nvRange)
  83. {
  84. AZ_Assert(azVector.size() == nvRange.size(),
  85. "Mismatch in number of elements. AZ vector: %zu Nv Range: %u", azVector.size(), nvRange.size());
  86. static_assert(sizeof(physx::PxVec4) == sizeof(AZ::Vector4), "physx::PxVec4 and AZ::Vector4 types have different sizes");
  87. // Reinterpret cast to floats so it does a fast move.
  88. AZStd::move(
  89. reinterpret_cast<float*>(azVector.data()),
  90. reinterpret_cast<float*>(azVector.data() + azVector.size()),
  91. reinterpret_cast<float*>(nvRange.begin()));
  92. }
  93. // Moves a NvCloth Range of physx::PxVec4 elements as an AZ vector of AZ::Vector4 elements.
  94. //
  95. // It's safe to reinterpret AZ::Vector4 as physx::PxVec4 because they have the same memory layout.
  96. // Each one has its own memory with their appropriate alignments.
  97. void FastMove(nv::cloth::Range<physx::PxVec4>&& nvRange, AZStd::vector<AZ::Vector4>& azVector)
  98. {
  99. AZ_Assert(azVector.size() == nvRange.size(),
  100. "Mismatch in number of elements. AZ vector: %zu Nv Range: %u", azVector.size(), nvRange.size());
  101. static_assert(sizeof(physx::PxVec4) == sizeof(AZ::Vector4), "physx::PxVec4 and AZ::Vector4 types have different sizes");
  102. // Reinterpret cast to floats so it does a fast copy.
  103. AZStd::move(
  104. reinterpret_cast<float*>(nvRange.begin()),
  105. reinterpret_cast<float*>(nvRange.end()),
  106. reinterpret_cast<float*>(azVector.begin()));
  107. }
  108. }
  109. Cloth::Cloth(
  110. ClothId id,
  111. const AZStd::vector<SimParticleFormat>& initialParticles,
  112. Fabric* fabric,
  113. NvClothUniquePtr nvCloth)
  114. : m_id(id)
  115. , m_nvCloth(AZStd::move(nvCloth))
  116. , m_fabric(fabric)
  117. , m_initialParticles(initialParticles)
  118. , m_initialParticlesWithMassApplied(initialParticles)
  119. {
  120. m_simParticles = initialParticles;
  121. // Construct the default list of phase configurations
  122. const size_t numPhaseTypes = m_fabric->GetPhaseTypes().size();
  123. m_nvPhaseConfigs.reserve(numPhaseTypes);
  124. for (size_t phaseIndex = 0; phaseIndex < numPhaseTypes; phaseIndex++)
  125. {
  126. m_nvPhaseConfigs.emplace_back(static_cast<uint16_t>(phaseIndex));
  127. }
  128. ApplyPhaseConfigs();
  129. // Set default gravity
  130. const AZ::Vector3 gravity(0.0f, 0.0f, -9.81f);
  131. SetGravity(gravity);
  132. // One more cloth instance using the fabric
  133. m_fabric->m_numClothsUsingFabric++;
  134. }
  135. Cloth::~Cloth()
  136. {
  137. // If cloth is still part of a solver, remove it
  138. if (m_solver)
  139. {
  140. m_solver->RemoveCloth(this);
  141. }
  142. // One less cloth instance using the fabric
  143. m_fabric->m_numClothsUsingFabric--;
  144. }
  145. void Cloth::Update()
  146. {
  147. AZ_PROFILE_FUNCTION(Cloth);
  148. ResolveStaticParticles();
  149. if (!RetrieveSimulationResults())
  150. {
  151. RestoreSimulation();
  152. }
  153. }
  154. ClothId Cloth::GetId() const
  155. {
  156. return m_id;
  157. }
  158. const AZStd::vector<SimParticleFormat>& Cloth::GetInitialParticles() const
  159. {
  160. return m_initialParticles;
  161. }
  162. const AZStd::vector<SimIndexType>& Cloth::GetInitialIndices() const
  163. {
  164. return m_fabric->m_cookedData.m_indices;
  165. }
  166. const AZStd::vector<SimParticleFormat>& Cloth::GetParticles() const
  167. {
  168. return m_simParticles;
  169. }
  170. void Cloth::SetParticles(const AZStd::vector<SimParticleFormat>& particles)
  171. {
  172. if (m_simParticles.size() != particles.size())
  173. {
  174. AZ_Warning("Cloth", false, "Unable to set cloth particles as it doesn't match the number of elements. Number of particles passed %zu, expected %zu.",
  175. particles.size(), m_simParticles.size());
  176. return;
  177. }
  178. m_simParticles = particles;
  179. CopySimParticlesToNvCloth();
  180. }
  181. void Cloth::SetParticles(AZStd::vector<SimParticleFormat>&& particles)
  182. {
  183. if (m_simParticles.size() != particles.size())
  184. {
  185. AZ_Warning("Cloth", false, "Unable to set cloth particles as it doesn't match the number of elements. Number of particles passed %zu, expected %zu.",
  186. particles.size(), m_simParticles.size());
  187. return;
  188. }
  189. m_simParticles = AZStd::move(particles);
  190. CopySimParticlesToNvCloth();
  191. }
  192. void Cloth::DiscardParticleDelta()
  193. {
  194. const nv::cloth::MappedRange<const physx::PxVec4> currentParticles = nv::cloth::readCurrentParticles(*m_nvCloth);
  195. nv::cloth::MappedRange<physx::PxVec4> previousParticles = m_nvCloth->getPreviousParticles();
  196. // Reinterpret cast to floats so it does a fast copy.
  197. AZStd::copy(
  198. reinterpret_cast<const float*>(currentParticles.begin()),
  199. reinterpret_cast<const float*>(currentParticles.end()),
  200. reinterpret_cast<float*>(previousParticles.begin()));
  201. }
  202. const FabricCookedData& Cloth::GetFabricCookedData() const
  203. {
  204. return m_fabric->m_cookedData;
  205. }
  206. IClothConfigurator* Cloth::GetClothConfigurator()
  207. {
  208. return this;
  209. }
  210. void Cloth::SetTransform(const AZ::Transform& transformWorld)
  211. {
  212. m_nvCloth->setTranslation(Internal::AsPxVec3(transformWorld.GetTranslation()));
  213. m_nvCloth->setRotation(Internal::AsPxQuat(transformWorld.GetRotation()));
  214. }
  215. void Cloth::ClearInertia()
  216. {
  217. m_nvCloth->clearInertia();
  218. }
  219. void Cloth::SetMass(float mass)
  220. {
  221. if (AZ::IsClose(m_mass, mass, std::numeric_limits<float>::epsilon()))
  222. {
  223. return;
  224. }
  225. m_mass = mass;
  226. const float inverseMass = (m_mass > 0.0f) ? (1.0f / m_mass) : 0.0f;
  227. for (size_t i = 0; i < m_simParticles.size(); ++i)
  228. {
  229. const float particleInvMass = m_initialParticles[i].GetW() * inverseMass;
  230. m_simParticles[i].SetW(particleInvMass);
  231. m_initialParticlesWithMassApplied[i].SetW(particleInvMass);
  232. }
  233. CopySimInverseMassesToNvCloth();
  234. }
  235. void Cloth::SetGravity(const AZ::Vector3& gravity)
  236. {
  237. m_nvCloth->setGravity(Internal::AsPxVec3(gravity));
  238. }
  239. void Cloth::SetStiffnessFrequency(float frequency)
  240. {
  241. m_nvCloth->setStiffnessFrequency(frequency);
  242. }
  243. void Cloth::SetDamping(const AZ::Vector3& damping)
  244. {
  245. m_nvCloth->setDamping(Internal::AsPxVec3(damping));
  246. }
  247. void Cloth::SetDampingLinearDrag(const AZ::Vector3& linearDrag)
  248. {
  249. m_nvCloth->setLinearDrag(Internal::AsPxVec3(linearDrag));
  250. }
  251. void Cloth::SetDampingAngularDrag(const AZ::Vector3& angularDrag)
  252. {
  253. m_nvCloth->setAngularDrag(Internal::AsPxVec3(angularDrag));
  254. }
  255. void Cloth::SetLinearInertia(const AZ::Vector3& linearInertia)
  256. {
  257. m_nvCloth->setLinearInertia(Internal::AsPxVec3(linearInertia));
  258. }
  259. void Cloth::SetAngularInertia(const AZ::Vector3& angularInertia)
  260. {
  261. m_nvCloth->setAngularInertia(Internal::AsPxVec3(angularInertia));
  262. }
  263. void Cloth::SetCentrifugalInertia(const AZ::Vector3& centrifugalInertia)
  264. {
  265. m_nvCloth->setCentrifugalInertia(Internal::AsPxVec3(centrifugalInertia));
  266. }
  267. void Cloth::SetWindVelocity(const AZ::Vector3& velocity)
  268. {
  269. m_nvCloth->setWindVelocity(Internal::AsPxVec3(velocity));
  270. }
  271. void Cloth::SetWindDragCoefficient(float drag)
  272. {
  273. const float airDragPerc = 0.97f; // To improve cloth stability
  274. m_nvCloth->setDragCoefficient(airDragPerc * drag);
  275. }
  276. void Cloth::SetWindLiftCoefficient(float lift)
  277. {
  278. const float airLiftPerc = 0.8f; // To improve cloth stability
  279. m_nvCloth->setLiftCoefficient(airLiftPerc * lift);
  280. }
  281. void Cloth::SetWindFluidDensity(float density)
  282. {
  283. m_nvCloth->setFluidDensity(density);
  284. }
  285. void Cloth::SetCollisionFriction(float friction)
  286. {
  287. m_nvCloth->setFriction(friction);
  288. }
  289. void Cloth::SetCollisionMassScale(float scale)
  290. {
  291. m_nvCloth->setCollisionMassScale(scale);
  292. }
  293. void Cloth::EnableContinuousCollision(bool value)
  294. {
  295. m_nvCloth->enableContinuousCollision(value);
  296. }
  297. void Cloth::SetCollisionAffectsStaticParticles(bool value)
  298. {
  299. m_collisionAffectsStaticParticles = value;
  300. }
  301. void Cloth::SetSelfCollisionDistance(float distance)
  302. {
  303. m_nvCloth->setSelfCollisionDistance(distance);
  304. }
  305. void Cloth::SetSelfCollisionStiffness(float stiffness)
  306. {
  307. m_nvCloth->setSelfCollisionStiffness(stiffness);
  308. }
  309. void Cloth::SetVerticalPhaseConfig(
  310. float stiffness,
  311. float stiffnessMultiplier,
  312. float compressionLimit,
  313. float stretchLimit)
  314. {
  315. SetPhaseConfig(
  316. nv::cloth::ClothFabricPhaseType::eVERTICAL,
  317. stiffness,
  318. stiffnessMultiplier,
  319. compressionLimit,
  320. stretchLimit);
  321. }
  322. void Cloth::SetHorizontalPhaseConfig(
  323. float stiffness,
  324. float stiffnessMultiplier,
  325. float compressionLimit,
  326. float stretchLimit)
  327. {
  328. SetPhaseConfig(
  329. nv::cloth::ClothFabricPhaseType::eHORIZONTAL,
  330. stiffness,
  331. stiffnessMultiplier,
  332. compressionLimit,
  333. stretchLimit);
  334. }
  335. void Cloth::SetBendingPhaseConfig(
  336. float stiffness,
  337. float stiffnessMultiplier,
  338. float compressionLimit,
  339. float stretchLimit)
  340. {
  341. SetPhaseConfig(
  342. nv::cloth::ClothFabricPhaseType::eBENDING,
  343. stiffness,
  344. stiffnessMultiplier,
  345. compressionLimit,
  346. stretchLimit);
  347. }
  348. void Cloth::SetShearingPhaseConfig(
  349. float stiffness,
  350. float stiffnessMultiplier,
  351. float compressionLimit,
  352. float stretchLimit)
  353. {
  354. SetPhaseConfig(
  355. nv::cloth::ClothFabricPhaseType::eSHEARING,
  356. stiffness,
  357. stiffnessMultiplier,
  358. compressionLimit,
  359. stretchLimit);
  360. }
  361. void Cloth::SetTetherConstraintStiffness(float stiffness)
  362. {
  363. m_nvCloth->setTetherConstraintStiffness(stiffness);
  364. }
  365. void Cloth::SetTetherConstraintScale(float scale)
  366. {
  367. m_nvCloth->setTetherConstraintScale(scale);
  368. }
  369. void Cloth::SetSolverFrequency(float frequency)
  370. {
  371. m_nvCloth->setSolverFrequency(frequency);
  372. }
  373. void Cloth::SetAcceleationFilterWidth(AZ::u32 width)
  374. {
  375. m_nvCloth->setAcceleationFilterWidth(width);
  376. }
  377. void Cloth::SetSphereColliders(const AZStd::vector<AZ::Vector4>& spheres)
  378. {
  379. m_nvCloth->setSpheres(
  380. ToPxVec4NvRange(spheres),
  381. 0, m_nvCloth->getNumSpheres());
  382. }
  383. void Cloth::SetSphereColliders(AZStd::vector<AZ::Vector4>&& spheres)
  384. {
  385. SetSphereColliders(spheres); // NvCloth does not offer a move overload for setSpheres, calling the const reference one.
  386. }
  387. void Cloth::SetCapsuleColliders(const AZStd::vector<AZ::u32>& capsuleIndices)
  388. {
  389. m_nvCloth->setCapsules(
  390. ToNvRange(capsuleIndices),
  391. 0, m_nvCloth->getNumCapsules());
  392. }
  393. void Cloth::SetCapsuleColliders(AZStd::vector<AZ::u32>&& capsuleIndices)
  394. {
  395. SetCapsuleColliders(capsuleIndices); // NvCloth does not offer a move overload for setCapsules, calling the const reference one.
  396. }
  397. void Cloth::SetMotionConstraints(const AZStd::vector<AZ::Vector4>& constraints)
  398. {
  399. if (m_simParticles.size() != constraints.size())
  400. {
  401. AZ_Warning("Cloth", false, "Unable to set motions constraints as it doesn't match the number of particles. Numbers of constraints passed %zu, expected %zu.",
  402. constraints.size(), m_simParticles.size());
  403. return;
  404. }
  405. m_motionConstraints = constraints;
  406. nv::cloth::Range<physx::PxVec4> motionConstraints = m_nvCloth->getMotionConstraints();
  407. Internal::FastCopy(m_motionConstraints, motionConstraints);
  408. }
  409. void Cloth::SetMotionConstraints(AZStd::vector<AZ::Vector4>&& constraints)
  410. {
  411. if (m_simParticles.size() != constraints.size())
  412. {
  413. AZ_Warning("Cloth", false, "Unable to set motions constraints as it doesn't match the number of particles. Numbers of constraints passed %zu, expected %zu.",
  414. constraints.size(), m_simParticles.size());
  415. return;
  416. }
  417. m_motionConstraints = AZStd::move(constraints);
  418. nv::cloth::Range<physx::PxVec4> motionConstraints = m_nvCloth->getMotionConstraints();
  419. Internal::FastCopy(m_motionConstraints, motionConstraints);
  420. }
  421. void Cloth::ClearMotionConstraints()
  422. {
  423. m_motionConstraints.clear();
  424. m_nvCloth->clearMotionConstraints();
  425. }
  426. void Cloth::SetMotionConstraintsScale(float scale)
  427. {
  428. m_nvCloth->setMotionConstraintScaleBias(scale, m_nvCloth->getMotionConstraintBias());
  429. }
  430. void Cloth::SetMotionConstraintsBias(float bias)
  431. {
  432. m_nvCloth->setMotionConstraintScaleBias(m_nvCloth->getMotionConstraintScale(), bias);
  433. }
  434. void Cloth::SetMotionConstraintsStiffness(float stiffness)
  435. {
  436. m_nvCloth->setMotionConstraintStiffness(stiffness);
  437. }
  438. void Cloth::SetSeparationConstraints(const AZStd::vector<AZ::Vector4>& constraints)
  439. {
  440. if (m_simParticles.size() != constraints.size())
  441. {
  442. AZ_Warning("Cloth", false, "Unable to set separation constraints as it doesn't match the number of particles. Numbers of constraints passed %zu, expected %zu.",
  443. constraints.size(), m_simParticles.size());
  444. return;
  445. }
  446. nv::cloth::Range<physx::PxVec4> separationConstraints = m_nvCloth->getSeparationConstraints();
  447. Internal::FastCopy(constraints, separationConstraints);
  448. }
  449. void Cloth::SetSeparationConstraints(AZStd::vector<AZ::Vector4>&& constraints)
  450. {
  451. if (m_simParticles.size() != constraints.size())
  452. {
  453. AZ_Warning("Cloth", false, "Unable to set separation constraints as it doesn't match the number of particles. Numbers of constraints passed %zu, expected %zu.",
  454. constraints.size(), m_simParticles.size());
  455. return;
  456. }
  457. nv::cloth::Range<physx::PxVec4> separationConstraints = m_nvCloth->getSeparationConstraints();
  458. Internal::FastMove(AZStd::move(constraints), separationConstraints);
  459. }
  460. void Cloth::ClearSeparationConstraints()
  461. {
  462. m_nvCloth->clearSeparationConstraints();
  463. }
  464. void Cloth::ResolveStaticParticles()
  465. {
  466. if (m_collisionAffectsStaticParticles)
  467. {
  468. // Nothing to do as in NvCloth colliders affect static particles.
  469. return;
  470. }
  471. // During simulation static particle are always affected by colliders and motion constraints.
  472. // To remove the effect of colliders on Static Particles we will restore their positions,
  473. // either with the motion constraints (if existent) or the last simulated particles.
  474. nv::cloth::MappedRange<physx::PxVec4> particles = m_nvCloth->getCurrentParticles();
  475. const AZStd::vector<AZ::Vector4>& positions = m_motionConstraints.empty()
  476. ? m_simParticles
  477. : m_motionConstraints;
  478. for (AZ::u32 i = 0; i < particles.size(); ++i)
  479. {
  480. // Checking NvCloth current particles is important because their W component will
  481. // have the result left by the simulation applying both inverse masses and motion constraints.
  482. if (particles[i].w == 0.0f)
  483. {
  484. auto& particle = particles[i];
  485. const auto& position = positions[i];
  486. particle.x = position.GetX();
  487. particle.y = position.GetY();
  488. particle.z = position.GetZ();
  489. }
  490. }
  491. }
  492. bool Cloth::RetrieveSimulationResults()
  493. {
  494. const nv::cloth::MappedRange<const physx::PxVec4> particles = nv::cloth::readCurrentParticles(*m_nvCloth);
  495. bool validCloth =
  496. AZStd::all_of(particles.begin(), particles.end(), [](const physx::PxVec4& particle)
  497. {
  498. return particle.isFinite();
  499. })
  500. &&
  501. // On some platforms when cloth simulation gets corrupted it puts all particles' position to (0,0,0)
  502. AZStd::any_of(particles.begin(), particles.end(), [](const physx::PxVec4& particle)
  503. {
  504. return particle.x != 0.0f || particle.y != 0.0f || particle.z != 0.0f;
  505. });
  506. if (validCloth)
  507. {
  508. for (AZ::u32 i = 0; i < particles.size(); ++i)
  509. {
  510. m_simParticles[i].SetX(particles[i].x);
  511. m_simParticles[i].SetY(particles[i].y);
  512. m_simParticles[i].SetZ(particles[i].z);
  513. // Not copying inverse masses on purpose since they could be different after running the simulation.
  514. // This solves a problem when using a value of zero in the motion constraints distance
  515. // or scale. All inverse masses would go to zero and since we were copying them back,
  516. // the original data got lost and it was not able to return to a normal state after
  517. // changing the values back to values other than zero.
  518. }
  519. m_numInvalidSimulations = 0; // Reset counter as the results were valid
  520. }
  521. return validCloth;
  522. }
  523. void Cloth::RestoreSimulation()
  524. {
  525. nv::cloth::MappedRange<physx::PxVec4> previousParticles = m_nvCloth->getPreviousParticles();
  526. nv::cloth::MappedRange<physx::PxVec4> currentParticles = m_nvCloth->getCurrentParticles();
  527. const AZ::u32 maxAttemptsToRestoreCloth = 15;
  528. if (m_numInvalidSimulations <= maxAttemptsToRestoreCloth)
  529. {
  530. // Leave the NvCloth simulation particles in their last known good position.
  531. Internal::FastCopy(m_simParticles, previousParticles);
  532. Internal::FastCopy(m_simParticles, currentParticles);
  533. }
  534. else
  535. {
  536. // Reset NvCloth simulation particles to their initial position if after a number of
  537. // attempts cloth has not been restored to a stable state.
  538. Internal::FastCopy(m_initialParticlesWithMassApplied, previousParticles);
  539. Internal::FastCopy(m_initialParticlesWithMassApplied, currentParticles);
  540. }
  541. m_nvCloth->clearInertia();
  542. m_nvCloth->clearInterpolation();
  543. m_numInvalidSimulations++;
  544. }
  545. void Cloth::CopySimParticlesToNvCloth()
  546. {
  547. // The positions must be copied into the current particles inside NvCloth.
  548. // Note: Inverse masses are copied as well to do a fast copy,
  549. // but inverse masses copied to current particles have no effect.
  550. nv::cloth::MappedRange<physx::PxVec4> currentParticles = m_nvCloth->getCurrentParticles();
  551. Internal::FastCopy(m_simParticles, currentParticles);
  552. CopySimInverseMassesToNvCloth();
  553. }
  554. void Cloth::CopySimInverseMassesToNvCloth()
  555. {
  556. // The inverse masses must be copied into the previous particles inside NvCloth
  557. // to take effect for the next simulation update.
  558. nv::cloth::MappedRange<physx::PxVec4> previousParticles = m_nvCloth->getPreviousParticles();
  559. for (AZ::u32 i = 0; i < previousParticles.size(); ++i)
  560. {
  561. previousParticles[i].w = m_simParticles[i].GetW();
  562. }
  563. }
  564. void Cloth::SetPhaseConfig(
  565. int32_t phaseType,
  566. float stiffness,
  567. float stiffnessMultiplier,
  568. float compressionLimit,
  569. float stretchLimit)
  570. {
  571. const auto& phaseTypes = m_fabric->GetPhaseTypes();
  572. for (size_t i = 0; i < phaseTypes.size(); ++i)
  573. {
  574. if (phaseTypes[i] == phaseType)
  575. {
  576. m_nvPhaseConfigs[i].mStiffness = stiffness;
  577. m_nvPhaseConfigs[i].mStiffnessMultiplier = 1.0f - AZ::GetClamp(stiffnessMultiplier, 0.0f, 1.0f); // Internally a value of 1 means no scale inside nvcloth.
  578. m_nvPhaseConfigs[i].mCompressionLimit = 1.0f + compressionLimit; // A value of 1.0f is no compression inside nvcloth. From [0.0, INF] to [1.0, INF].
  579. m_nvPhaseConfigs[i].mStretchLimit = 1.0f + stretchLimit; // A value of 1.0f is no stretch inside nvcloth. From [0.0, INF] to [1.0, INF].
  580. }
  581. }
  582. ApplyPhaseConfigs();
  583. }
  584. void Cloth::ApplyPhaseConfigs()
  585. {
  586. m_nvCloth->setPhaseConfig(
  587. ToNvRange(m_nvPhaseConfigs));
  588. }
  589. } // namespace NvCloth