123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <AzCore/Math/Transform.h>
- #include <AzCore/Math/Quaternion.h>
- #include <System/Cloth.h>
- #include <System/Fabric.h>
- #include <System/Solver.h>
- // NvCloth library includes
- #include <NvCloth/Cloth.h>
- #include <NvClothExt/ClothFabricCooker.h>
- #include <foundation/PxVec3.h>
- #include <foundation/PxVec4.h>
- #include <foundation/PxQuat.h>
- AZ_DEFINE_BUDGET(Cloth);
- namespace NvCloth
- {
- namespace Internal
- {
- // Returns AZ::Vector3 as physx::PxVec3 using the same memory.
- // It's safe to reinterpret AZ::Vector3 as physx::PxVec3 because they have the same memory layout
- // and AZ::Vector3 has more memory alignment restrictions than physx::PxVec3.
- // The opposite operation would NOT be safe.
- physx::PxVec3& AsPxVec3(AZ::Vector3& azVec)
- {
- return *reinterpret_cast<physx::PxVec3*>(&azVec);
- }
- const physx::PxVec3& AsPxVec3(const AZ::Vector3& azVec)
- {
- return *reinterpret_cast<const physx::PxVec3*>(&azVec);
- }
- // Returns AZ::Quaternion as physx::PxQuat using the same memory.
- // It's safe to reinterpret AZ::Quaternion as physx::PxQuat because they have the same memory layout
- // and AZ::Quaternion has more memory alignment restrictions than physx::PxQuat.
- // The opposite operation would NOT be safe.
- physx::PxQuat& AsPxQuat(AZ::Quaternion& azQuat)
- {
- return *reinterpret_cast<physx::PxQuat*>(&azQuat);
- }
- const physx::PxQuat& AsPxQuat(const AZ::Quaternion& azQuat)
- {
- return *reinterpret_cast<const physx::PxQuat*>(&azQuat);
- }
- // Copies an AZ vector of AZ::Vector4 elements as a NvCloth Range of physx::PxVec4 elements.
- //
- // It's safe to reinterpret AZ::Vector4 as physx::PxVec4 because they have the same memory layout.
- // Each one has its own memory with their appropriate alignments.
- void FastCopy(const AZStd::vector<AZ::Vector4>& azVector, nv::cloth::Range<physx::PxVec4>& nvRange)
- {
- AZ_Assert(azVector.size() == nvRange.size(),
- "Mismatch in number of elements. AZ vector: %zu Nv Range: %u", azVector.size(), nvRange.size());
- static_assert(sizeof(physx::PxVec4) == sizeof(AZ::Vector4), "physx::PxVec4 and AZ::Vector4 types have different sizes");
- // Reinterpret cast to floats so it does a fast copy.
- AZStd::copy(
- reinterpret_cast<const float*>(azVector.data()),
- reinterpret_cast<const float*>(azVector.data() + azVector.size()),
- reinterpret_cast<float*>(nvRange.begin()));
- }
- // Copies a NvCloth Range of physx::PxVec4 elements as an AZ vector of AZ::Vector4 elements.
- //
- // It's safe to reinterpret AZ::Vector4 as physx::PxVec4 because they have the same memory layout.
- // Each one has its own memory with their appropriate alignments.
- void FastCopy(const nv::cloth::Range<physx::PxVec4>& nvRange, AZStd::vector<AZ::Vector4>& azVector)
- {
- AZ_Assert(azVector.size() == nvRange.size(),
- "Mismatch in number of elements. AZ vector: %zu Nv Range: %u", azVector.size(), nvRange.size());
- static_assert(sizeof(physx::PxVec4) == sizeof(AZ::Vector4), "physx::PxVec4 and AZ::Vector4 types have different sizes");
- // Reinterpret cast to floats so it does a fast copy.
- AZStd::copy(
- reinterpret_cast<const float*>(nvRange.begin()),
- reinterpret_cast<const float*>(nvRange.end()),
- reinterpret_cast<float*>(azVector.begin()));
- }
- // Moves an AZ vector of AZ::Vector4 elements as a NvCloth Range of physx::PxVec4 elements.
- //
- // It's safe to reinterpret AZ::Vector4 as physx::PxVec4 because they have the same memory layout.
- // Each one has its own memory with their appropriate alignments.
- void FastMove(AZStd::vector<AZ::Vector4>&& azVector, nv::cloth::Range<physx::PxVec4>& nvRange)
- {
- AZ_Assert(azVector.size() == nvRange.size(),
- "Mismatch in number of elements. AZ vector: %zu Nv Range: %u", azVector.size(), nvRange.size());
- static_assert(sizeof(physx::PxVec4) == sizeof(AZ::Vector4), "physx::PxVec4 and AZ::Vector4 types have different sizes");
- // Reinterpret cast to floats so it does a fast move.
- AZStd::move(
- reinterpret_cast<float*>(azVector.data()),
- reinterpret_cast<float*>(azVector.data() + azVector.size()),
- reinterpret_cast<float*>(nvRange.begin()));
- }
- // Moves a NvCloth Range of physx::PxVec4 elements as an AZ vector of AZ::Vector4 elements.
- //
- // It's safe to reinterpret AZ::Vector4 as physx::PxVec4 because they have the same memory layout.
- // Each one has its own memory with their appropriate alignments.
- void FastMove(nv::cloth::Range<physx::PxVec4>&& nvRange, AZStd::vector<AZ::Vector4>& azVector)
- {
- AZ_Assert(azVector.size() == nvRange.size(),
- "Mismatch in number of elements. AZ vector: %zu Nv Range: %u", azVector.size(), nvRange.size());
- static_assert(sizeof(physx::PxVec4) == sizeof(AZ::Vector4), "physx::PxVec4 and AZ::Vector4 types have different sizes");
- // Reinterpret cast to floats so it does a fast copy.
- AZStd::move(
- reinterpret_cast<float*>(nvRange.begin()),
- reinterpret_cast<float*>(nvRange.end()),
- reinterpret_cast<float*>(azVector.begin()));
- }
- }
- Cloth::Cloth(
- ClothId id,
- const AZStd::vector<SimParticleFormat>& initialParticles,
- Fabric* fabric,
- NvClothUniquePtr nvCloth)
- : m_id(id)
- , m_nvCloth(AZStd::move(nvCloth))
- , m_fabric(fabric)
- , m_initialParticles(initialParticles)
- , m_initialParticlesWithMassApplied(initialParticles)
- {
- m_simParticles = initialParticles;
- // Construct the default list of phase configurations
- const size_t numPhaseTypes = m_fabric->GetPhaseTypes().size();
- m_nvPhaseConfigs.reserve(numPhaseTypes);
- for (size_t phaseIndex = 0; phaseIndex < numPhaseTypes; phaseIndex++)
- {
- m_nvPhaseConfigs.emplace_back(static_cast<uint16_t>(phaseIndex));
- }
- ApplyPhaseConfigs();
- // Set default gravity
- const AZ::Vector3 gravity(0.0f, 0.0f, -9.81f);
- SetGravity(gravity);
- // One more cloth instance using the fabric
- m_fabric->m_numClothsUsingFabric++;
- }
- Cloth::~Cloth()
- {
- // If cloth is still part of a solver, remove it
- if (m_solver)
- {
- m_solver->RemoveCloth(this);
- }
- // One less cloth instance using the fabric
- m_fabric->m_numClothsUsingFabric--;
- }
- void Cloth::Update()
- {
- AZ_PROFILE_FUNCTION(Cloth);
- ResolveStaticParticles();
- if (!RetrieveSimulationResults())
- {
- RestoreSimulation();
- }
- }
- ClothId Cloth::GetId() const
- {
- return m_id;
- }
- const AZStd::vector<SimParticleFormat>& Cloth::GetInitialParticles() const
- {
- return m_initialParticles;
- }
- const AZStd::vector<SimIndexType>& Cloth::GetInitialIndices() const
- {
- return m_fabric->m_cookedData.m_indices;
- }
- const AZStd::vector<SimParticleFormat>& Cloth::GetParticles() const
- {
- return m_simParticles;
- }
- void Cloth::SetParticles(const AZStd::vector<SimParticleFormat>& particles)
- {
- if (m_simParticles.size() != particles.size())
- {
- 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.",
- particles.size(), m_simParticles.size());
- return;
- }
- m_simParticles = particles;
- CopySimParticlesToNvCloth();
- }
- void Cloth::SetParticles(AZStd::vector<SimParticleFormat>&& particles)
- {
- if (m_simParticles.size() != particles.size())
- {
- 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.",
- particles.size(), m_simParticles.size());
- return;
- }
- m_simParticles = AZStd::move(particles);
- CopySimParticlesToNvCloth();
- }
- void Cloth::DiscardParticleDelta()
- {
- const nv::cloth::MappedRange<const physx::PxVec4> currentParticles = nv::cloth::readCurrentParticles(*m_nvCloth);
- nv::cloth::MappedRange<physx::PxVec4> previousParticles = m_nvCloth->getPreviousParticles();
- // Reinterpret cast to floats so it does a fast copy.
- AZStd::copy(
- reinterpret_cast<const float*>(currentParticles.begin()),
- reinterpret_cast<const float*>(currentParticles.end()),
- reinterpret_cast<float*>(previousParticles.begin()));
- }
- const FabricCookedData& Cloth::GetFabricCookedData() const
- {
- return m_fabric->m_cookedData;
- }
- IClothConfigurator* Cloth::GetClothConfigurator()
- {
- return this;
- }
- void Cloth::SetTransform(const AZ::Transform& transformWorld)
- {
- m_nvCloth->setTranslation(Internal::AsPxVec3(transformWorld.GetTranslation()));
- m_nvCloth->setRotation(Internal::AsPxQuat(transformWorld.GetRotation()));
- }
- void Cloth::ClearInertia()
- {
- m_nvCloth->clearInertia();
- }
- void Cloth::SetMass(float mass)
- {
- if (AZ::IsClose(m_mass, mass, std::numeric_limits<float>::epsilon()))
- {
- return;
- }
- m_mass = mass;
- const float inverseMass = (m_mass > 0.0f) ? (1.0f / m_mass) : 0.0f;
- for (size_t i = 0; i < m_simParticles.size(); ++i)
- {
- const float particleInvMass = m_initialParticles[i].GetW() * inverseMass;
- m_simParticles[i].SetW(particleInvMass);
- m_initialParticlesWithMassApplied[i].SetW(particleInvMass);
- }
- CopySimInverseMassesToNvCloth();
- }
- void Cloth::SetGravity(const AZ::Vector3& gravity)
- {
- m_nvCloth->setGravity(Internal::AsPxVec3(gravity));
- }
- void Cloth::SetStiffnessFrequency(float frequency)
- {
- m_nvCloth->setStiffnessFrequency(frequency);
- }
- void Cloth::SetDamping(const AZ::Vector3& damping)
- {
- m_nvCloth->setDamping(Internal::AsPxVec3(damping));
- }
- void Cloth::SetDampingLinearDrag(const AZ::Vector3& linearDrag)
- {
- m_nvCloth->setLinearDrag(Internal::AsPxVec3(linearDrag));
- }
- void Cloth::SetDampingAngularDrag(const AZ::Vector3& angularDrag)
- {
- m_nvCloth->setAngularDrag(Internal::AsPxVec3(angularDrag));
- }
- void Cloth::SetLinearInertia(const AZ::Vector3& linearInertia)
- {
- m_nvCloth->setLinearInertia(Internal::AsPxVec3(linearInertia));
- }
- void Cloth::SetAngularInertia(const AZ::Vector3& angularInertia)
- {
- m_nvCloth->setAngularInertia(Internal::AsPxVec3(angularInertia));
- }
- void Cloth::SetCentrifugalInertia(const AZ::Vector3& centrifugalInertia)
- {
- m_nvCloth->setCentrifugalInertia(Internal::AsPxVec3(centrifugalInertia));
- }
- void Cloth::SetWindVelocity(const AZ::Vector3& velocity)
- {
- m_nvCloth->setWindVelocity(Internal::AsPxVec3(velocity));
- }
- void Cloth::SetWindDragCoefficient(float drag)
- {
- const float airDragPerc = 0.97f; // To improve cloth stability
- m_nvCloth->setDragCoefficient(airDragPerc * drag);
- }
- void Cloth::SetWindLiftCoefficient(float lift)
- {
- const float airLiftPerc = 0.8f; // To improve cloth stability
- m_nvCloth->setLiftCoefficient(airLiftPerc * lift);
- }
- void Cloth::SetWindFluidDensity(float density)
- {
- m_nvCloth->setFluidDensity(density);
- }
- void Cloth::SetCollisionFriction(float friction)
- {
- m_nvCloth->setFriction(friction);
- }
- void Cloth::SetCollisionMassScale(float scale)
- {
- m_nvCloth->setCollisionMassScale(scale);
- }
- void Cloth::EnableContinuousCollision(bool value)
- {
- m_nvCloth->enableContinuousCollision(value);
- }
- void Cloth::SetCollisionAffectsStaticParticles(bool value)
- {
- m_collisionAffectsStaticParticles = value;
- }
- void Cloth::SetSelfCollisionDistance(float distance)
- {
- m_nvCloth->setSelfCollisionDistance(distance);
- }
- void Cloth::SetSelfCollisionStiffness(float stiffness)
- {
- m_nvCloth->setSelfCollisionStiffness(stiffness);
- }
- void Cloth::SetVerticalPhaseConfig(
- float stiffness,
- float stiffnessMultiplier,
- float compressionLimit,
- float stretchLimit)
- {
- SetPhaseConfig(
- nv::cloth::ClothFabricPhaseType::eVERTICAL,
- stiffness,
- stiffnessMultiplier,
- compressionLimit,
- stretchLimit);
- }
- void Cloth::SetHorizontalPhaseConfig(
- float stiffness,
- float stiffnessMultiplier,
- float compressionLimit,
- float stretchLimit)
- {
- SetPhaseConfig(
- nv::cloth::ClothFabricPhaseType::eHORIZONTAL,
- stiffness,
- stiffnessMultiplier,
- compressionLimit,
- stretchLimit);
- }
- void Cloth::SetBendingPhaseConfig(
- float stiffness,
- float stiffnessMultiplier,
- float compressionLimit,
- float stretchLimit)
- {
- SetPhaseConfig(
- nv::cloth::ClothFabricPhaseType::eBENDING,
- stiffness,
- stiffnessMultiplier,
- compressionLimit,
- stretchLimit);
- }
- void Cloth::SetShearingPhaseConfig(
- float stiffness,
- float stiffnessMultiplier,
- float compressionLimit,
- float stretchLimit)
- {
- SetPhaseConfig(
- nv::cloth::ClothFabricPhaseType::eSHEARING,
- stiffness,
- stiffnessMultiplier,
- compressionLimit,
- stretchLimit);
- }
- void Cloth::SetTetherConstraintStiffness(float stiffness)
- {
- m_nvCloth->setTetherConstraintStiffness(stiffness);
- }
- void Cloth::SetTetherConstraintScale(float scale)
- {
- m_nvCloth->setTetherConstraintScale(scale);
- }
- void Cloth::SetSolverFrequency(float frequency)
- {
- m_nvCloth->setSolverFrequency(frequency);
- }
- void Cloth::SetAcceleationFilterWidth(AZ::u32 width)
- {
- m_nvCloth->setAcceleationFilterWidth(width);
- }
- void Cloth::SetSphereColliders(const AZStd::vector<AZ::Vector4>& spheres)
- {
- m_nvCloth->setSpheres(
- ToPxVec4NvRange(spheres),
- 0, m_nvCloth->getNumSpheres());
- }
- void Cloth::SetSphereColliders(AZStd::vector<AZ::Vector4>&& spheres)
- {
- SetSphereColliders(spheres); // NvCloth does not offer a move overload for setSpheres, calling the const reference one.
- }
- void Cloth::SetCapsuleColliders(const AZStd::vector<AZ::u32>& capsuleIndices)
- {
- m_nvCloth->setCapsules(
- ToNvRange(capsuleIndices),
- 0, m_nvCloth->getNumCapsules());
- }
- void Cloth::SetCapsuleColliders(AZStd::vector<AZ::u32>&& capsuleIndices)
- {
- SetCapsuleColliders(capsuleIndices); // NvCloth does not offer a move overload for setCapsules, calling the const reference one.
- }
- void Cloth::SetMotionConstraints(const AZStd::vector<AZ::Vector4>& constraints)
- {
- if (m_simParticles.size() != constraints.size())
- {
- 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.",
- constraints.size(), m_simParticles.size());
- return;
- }
- m_motionConstraints = constraints;
- nv::cloth::Range<physx::PxVec4> motionConstraints = m_nvCloth->getMotionConstraints();
- Internal::FastCopy(m_motionConstraints, motionConstraints);
- }
- void Cloth::SetMotionConstraints(AZStd::vector<AZ::Vector4>&& constraints)
- {
- if (m_simParticles.size() != constraints.size())
- {
- 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.",
- constraints.size(), m_simParticles.size());
- return;
- }
- m_motionConstraints = AZStd::move(constraints);
- nv::cloth::Range<physx::PxVec4> motionConstraints = m_nvCloth->getMotionConstraints();
- Internal::FastCopy(m_motionConstraints, motionConstraints);
- }
- void Cloth::ClearMotionConstraints()
- {
- m_motionConstraints.clear();
- m_nvCloth->clearMotionConstraints();
- }
- void Cloth::SetMotionConstraintsScale(float scale)
- {
- m_nvCloth->setMotionConstraintScaleBias(scale, m_nvCloth->getMotionConstraintBias());
- }
- void Cloth::SetMotionConstraintsBias(float bias)
- {
- m_nvCloth->setMotionConstraintScaleBias(m_nvCloth->getMotionConstraintScale(), bias);
- }
- void Cloth::SetMotionConstraintsStiffness(float stiffness)
- {
- m_nvCloth->setMotionConstraintStiffness(stiffness);
- }
- void Cloth::SetSeparationConstraints(const AZStd::vector<AZ::Vector4>& constraints)
- {
- if (m_simParticles.size() != constraints.size())
- {
- 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.",
- constraints.size(), m_simParticles.size());
- return;
- }
- nv::cloth::Range<physx::PxVec4> separationConstraints = m_nvCloth->getSeparationConstraints();
- Internal::FastCopy(constraints, separationConstraints);
- }
- void Cloth::SetSeparationConstraints(AZStd::vector<AZ::Vector4>&& constraints)
- {
- if (m_simParticles.size() != constraints.size())
- {
- 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.",
- constraints.size(), m_simParticles.size());
- return;
- }
- nv::cloth::Range<physx::PxVec4> separationConstraints = m_nvCloth->getSeparationConstraints();
- Internal::FastMove(AZStd::move(constraints), separationConstraints);
- }
- void Cloth::ClearSeparationConstraints()
- {
- m_nvCloth->clearSeparationConstraints();
- }
- void Cloth::ResolveStaticParticles()
- {
- if (m_collisionAffectsStaticParticles)
- {
- // Nothing to do as in NvCloth colliders affect static particles.
- return;
- }
- // During simulation static particle are always affected by colliders and motion constraints.
- // To remove the effect of colliders on Static Particles we will restore their positions,
- // either with the motion constraints (if existent) or the last simulated particles.
- nv::cloth::MappedRange<physx::PxVec4> particles = m_nvCloth->getCurrentParticles();
- const AZStd::vector<AZ::Vector4>& positions = m_motionConstraints.empty()
- ? m_simParticles
- : m_motionConstraints;
- for (AZ::u32 i = 0; i < particles.size(); ++i)
- {
- // Checking NvCloth current particles is important because their W component will
- // have the result left by the simulation applying both inverse masses and motion constraints.
- if (particles[i].w == 0.0f)
- {
- auto& particle = particles[i];
- const auto& position = positions[i];
- particle.x = position.GetX();
- particle.y = position.GetY();
- particle.z = position.GetZ();
- }
- }
- }
- bool Cloth::RetrieveSimulationResults()
- {
- const nv::cloth::MappedRange<const physx::PxVec4> particles = nv::cloth::readCurrentParticles(*m_nvCloth);
- bool validCloth =
- AZStd::all_of(particles.begin(), particles.end(), [](const physx::PxVec4& particle)
- {
- return particle.isFinite();
- })
- &&
- // On some platforms when cloth simulation gets corrupted it puts all particles' position to (0,0,0)
- AZStd::any_of(particles.begin(), particles.end(), [](const physx::PxVec4& particle)
- {
- return particle.x != 0.0f || particle.y != 0.0f || particle.z != 0.0f;
- });
- if (validCloth)
- {
- for (AZ::u32 i = 0; i < particles.size(); ++i)
- {
- m_simParticles[i].SetX(particles[i].x);
- m_simParticles[i].SetY(particles[i].y);
- m_simParticles[i].SetZ(particles[i].z);
- // Not copying inverse masses on purpose since they could be different after running the simulation.
- // This solves a problem when using a value of zero in the motion constraints distance
- // or scale. All inverse masses would go to zero and since we were copying them back,
- // the original data got lost and it was not able to return to a normal state after
- // changing the values back to values other than zero.
- }
- m_numInvalidSimulations = 0; // Reset counter as the results were valid
- }
- return validCloth;
- }
- void Cloth::RestoreSimulation()
- {
- nv::cloth::MappedRange<physx::PxVec4> previousParticles = m_nvCloth->getPreviousParticles();
- nv::cloth::MappedRange<physx::PxVec4> currentParticles = m_nvCloth->getCurrentParticles();
- const AZ::u32 maxAttemptsToRestoreCloth = 15;
- if (m_numInvalidSimulations <= maxAttemptsToRestoreCloth)
- {
- // Leave the NvCloth simulation particles in their last known good position.
- Internal::FastCopy(m_simParticles, previousParticles);
- Internal::FastCopy(m_simParticles, currentParticles);
- }
- else
- {
- // Reset NvCloth simulation particles to their initial position if after a number of
- // attempts cloth has not been restored to a stable state.
- Internal::FastCopy(m_initialParticlesWithMassApplied, previousParticles);
- Internal::FastCopy(m_initialParticlesWithMassApplied, currentParticles);
- }
- m_nvCloth->clearInertia();
- m_nvCloth->clearInterpolation();
- m_numInvalidSimulations++;
- }
- void Cloth::CopySimParticlesToNvCloth()
- {
- // The positions must be copied into the current particles inside NvCloth.
- // Note: Inverse masses are copied as well to do a fast copy,
- // but inverse masses copied to current particles have no effect.
- nv::cloth::MappedRange<physx::PxVec4> currentParticles = m_nvCloth->getCurrentParticles();
- Internal::FastCopy(m_simParticles, currentParticles);
- CopySimInverseMassesToNvCloth();
- }
- void Cloth::CopySimInverseMassesToNvCloth()
- {
- // The inverse masses must be copied into the previous particles inside NvCloth
- // to take effect for the next simulation update.
- nv::cloth::MappedRange<physx::PxVec4> previousParticles = m_nvCloth->getPreviousParticles();
- for (AZ::u32 i = 0; i < previousParticles.size(); ++i)
- {
- previousParticles[i].w = m_simParticles[i].GetW();
- }
- }
- void Cloth::SetPhaseConfig(
- int32_t phaseType,
- float stiffness,
- float stiffnessMultiplier,
- float compressionLimit,
- float stretchLimit)
- {
- const auto& phaseTypes = m_fabric->GetPhaseTypes();
- for (size_t i = 0; i < phaseTypes.size(); ++i)
- {
- if (phaseTypes[i] == phaseType)
- {
- m_nvPhaseConfigs[i].mStiffness = stiffness;
- m_nvPhaseConfigs[i].mStiffnessMultiplier = 1.0f - AZ::GetClamp(stiffnessMultiplier, 0.0f, 1.0f); // Internally a value of 1 means no scale inside nvcloth.
- 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].
- 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].
- }
- }
- ApplyPhaseConfigs();
- }
- void Cloth::ApplyPhaseConfigs()
- {
- m_nvCloth->setPhaseConfig(
- ToNvRange(m_nvPhaseConfigs));
- }
- } // namespace NvCloth
|