diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Source/SimulationController/src/cloth | |
| download | physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip | |
Initial commit:
PhysX 3.4.0 Update @ 21294896
APEX 1.4.0 Update @ 21275617
[CL 21300167]
Diffstat (limited to 'PhysX_3.4/Source/SimulationController/src/cloth')
6 files changed, 2812 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/SimulationController/src/cloth/ScClothCore.cpp b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothCore.cpp new file mode 100644 index 00000000..8cfa74d5 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothCore.cpp @@ -0,0 +1,1160 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#include "ScClothCore.h" +#if PX_USE_CLOTH_API + +using namespace physx; +using namespace cloth; + +#include "PxClothParticleData.h" +#include "PxClothTypes.h" + +#include "ScClothFabricCore.h" +#include "ScClothSim.h" +#include "ScPhysics.h" +#include "ScScene.h" + +#include "Types.h" +#include "Range.h" +#include "Factory.h" +#include "Cloth.h" +#include "Fabric.h" +#include "PsHash.h" + +namespace +{ + template <typename D, typename S> + PX_FORCE_INLINE cloth::Range<D> createRange(S begin, PxU32 size) + { + D* start = reinterpret_cast<D*>(begin); + D* end = start + size; + + return cloth::Range<D>(start, end); + } +} + +bool Sc::DefaultClothInterCollisionFilter(void* cloth0, void* cloth1) +{ + PX_ASSERT(cloth0); + PX_ASSERT(cloth1); + + Sc::ClothCore* scCloth0 = static_cast<Sc::ClothCore*>(cloth0); + Sc::ClothCore* scCloth1 = static_cast<Sc::ClothCore*>(cloth1); + + const Sc::Scene& scene = scCloth0->getSim()->getScene(); + PX_ASSERT(&scCloth1->getSim()->getScene() == &scene); + + PxSimulationFilterShader shader = scene.getFilterShaderFast(); + + PxPairFlags pairFlags; + PxFilterFlags filterFlags = shader( + PxFilterObjectType::eCLOTH, scCloth0->getSimulationFilterData(), + PxFilterObjectType::eCLOTH, scCloth1->getSimulationFilterData(), + pairFlags, + scene.getFilterShaderDataFast(), + scene.getFilterShaderDataSizeFast()); + + if (filterFlags&PxFilterFlag::eCALLBACK) + { + // create unique pair id from cloth core ptrs + const PxU32 pairId = shdfnd::hash(shdfnd::Pair<Sc::ClothCore*, Sc::ClothCore*>(scCloth0, scCloth1)); + + filterFlags = scene.getFilterCallbackFast()->pairFound(pairId, + PxFilterObjectType::eCLOTH, scCloth0->getSimulationFilterData(), scCloth0->getPxCloth(), NULL, + PxFilterObjectType::eCLOTH, scCloth1->getSimulationFilterData(), scCloth1->getPxCloth(), NULL, pairFlags); + } + + if (filterFlags&PxFilterFlag::eKILL || filterFlags&PxFilterFlag::eSUPPRESS) + return false; + + return true; +} + + +Sc::ClothCore::ClothCore(const PxTransform& globalPose, Sc::ClothFabricCore& fabric, const PxClothParticle* particles, PxClothFlags flags) : + ActorCore(PxActorType::eCLOTH, PxActorFlag::eVISUALIZATION, PX_DEFAULT_CLIENT, 0, 0), + mExternalAcceleration(0.0f), + mFabric(&fabric), + mBulkData(NULL), + mClothFlags(flags), + mContactOffset(0.0f), + mRestOffset(0.0f), + mNumUserSpheres(0), + mNumUserCapsules(0), + mNumUserPlanes(0), + mNumUserConvexes(0), + mNumUserTriangles(0) +{ + initLowLevel(globalPose, particles); +} + + +Sc::ClothCore::~ClothCore() +{ + PX_ASSERT(getSim() == NULL); + + if (mPhaseConfigs) + PX_FREE(mPhaseConfigs); + + cloth::Fabric* fabric = &mLowLevelCloth->getFabric(); + + PX_DELETE(mLowLevelCloth); + + // If a cloth fabric gets deleted while the simulation is running, the fabric has to be delayed destroyed but + // ScClothFabric is then gone already. So we delete here in this case. It would work automatically if the fabric + // deleted itself on refCount 0 but doing it the way below keeps the LL interface independent. + if (fabric->getRefCount() == 0) + PX_DELETE(fabric); +} + +void Sc::ClothCore::initLowLevel(const PxTransform& globalPose, const PxClothParticle* particles) +{ + PX_ASSERT(mFabric); + + PxU32 nbPhases = mFabric->getNbPhases(); + mPhaseConfigs = reinterpret_cast<cloth::PhaseConfig*>(PX_ALLOC(nbPhases * sizeof(cloth::PhaseConfig), "cloth::PhaseConfig")); + + if (mPhaseConfigs) + { + for(PxU16 i=0; i < nbPhases; i++) + { + cloth::PhaseConfig config(i); + PX_PLACEMENT_NEW(mPhaseConfigs + i, cloth::PhaseConfig)(config); + } + + // Create the low level object + cloth::Range<const PxVec4> particlesRange = createRange<const PxVec4>(particles, mFabric->getNbParticles()); + + //!!!CL todo: error processing if creation fails + mLowLevelCloth = Sc::Physics::getInstance().getLowLevelClothFactory().createCloth(particlesRange, mFabric->getLowLevelFabric()); + + if (mLowLevelCloth) + { + setGlobalPose(globalPose); + + cloth::Range<const cloth::PhaseConfig> phaseConfigRange = createRange<const cloth::PhaseConfig>(mPhaseConfigs, nbPhases); + mLowLevelCloth->setPhaseConfig(phaseConfigRange); + + mLowLevelCloth->enableContinuousCollision(mClothFlags & PxClothFlag::eSWEPT_CONTACT); + + mLowLevelCloth->setUserData(this); + + wakeUp(Physics::sWakeCounterOnCreation); + } + } +} + +// PX_SERIALIZATION + +void Sc::ClothCore::updateBulkData(ClothBulkData& bulkData) +{ + cloth::MappedRange<const PxVec4> particles = cloth::readCurrentParticles(*mLowLevelCloth); + bulkData.mParticles.resize(getNbParticles(), PxClothParticle(PxVec3(0.0f), 0.0f)); + PxMemCopy(bulkData.mParticles.begin(), particles.begin(), particles.size() * sizeof(PxVec4)); + + if (getNbVirtualParticles()) + { + // could avoid a lot of the construction overhead inside + // resize() if Array supported insertRange() instead + bulkData.mVpData.resize(getNbVirtualParticles()*4); + bulkData.mVpWeightData.resize(getNbVirtualParticleWeights(), PxVec3(0.0f)); + + getVirtualParticles(bulkData.mVpData.begin()); + getVirtualParticleWeights(bulkData.mVpWeightData.begin()); + } + + if (getNbCollisionSpheres() || getNbCollisionConvexes() || getNbCollisionTriangles()) + { + bulkData.mCollisionSpheres.resize(getNbCollisionSpheres()); + bulkData.mCollisionPairs.resize(getNbCollisionCapsules()*2); + bulkData.mCollisionPlanes.resize(getNbCollisionPlanes()); + bulkData.mConvexMasks.resize(getNbCollisionConvexes()); + bulkData.mCollisionTriangles.resize(getNbCollisionTriangles()); + + getCollisionData(bulkData.mCollisionSpheres.begin(), bulkData.mCollisionPairs.begin(), + bulkData.mCollisionPlanes.begin(), bulkData.mConvexMasks.begin(), bulkData.mCollisionTriangles.begin()); + } + + if (mLowLevelCloth->getNumMotionConstraints()) + { + bulkData.mConstraints.resize(mLowLevelCloth->getNumMotionConstraints(), PxClothParticleMotionConstraint(PxVec3(0.0f), 0.0f)); + getMotionConstraints(bulkData.mConstraints.begin()); + } + + if (mLowLevelCloth->getNumSeparationConstraints()) + { + bulkData.mSeparationConstraints.resize(mLowLevelCloth->getNumSeparationConstraints(), PxClothParticleSeparationConstraint(PxVec3(0.0f), 0.0f)); + getSeparationConstraints(bulkData.mSeparationConstraints.begin()); + } + + if (mLowLevelCloth->getNumParticleAccelerations()) + { + bulkData.mParticleAccelerations.resize(mLowLevelCloth->getNumParticleAccelerations()); + getParticleAccelerations(bulkData.mParticleAccelerations.begin()); + } + + if(mLowLevelCloth->getNumSelfCollisionIndices()) + { + bulkData.mSelfCollisionIndices.resize(mLowLevelCloth->getNumSelfCollisionIndices()); + getSelfCollisionIndices(bulkData.mSelfCollisionIndices.begin()); + } + + if (mLowLevelCloth->getNumRestPositions()) + { + bulkData.mRestPositions.resize(mLowLevelCloth->getNumRestPositions(), PxVec4(0.0f)); + getRestPositions(bulkData.mRestPositions.begin()); + } + + bulkData.mTetherConstraintScale = mLowLevelCloth->getTetherConstraintScale(); + bulkData.mTetherConstraintStiffness = mLowLevelCloth->getTetherConstraintStiffness(); + bulkData.mMotionConstraintScale = mLowLevelCloth->getMotionConstraintScale(); + bulkData.mMotionConstraintBias = mLowLevelCloth->getMotionConstraintBias(); + bulkData.mMotionConstraintStiffness = mLowLevelCloth->getMotionConstraintStiffness(); + bulkData.mAcceleration = getExternalAcceleration(); + bulkData.mDamping = mLowLevelCloth->getDamping(); + bulkData.mFriction = mLowLevelCloth->getFriction(); + bulkData.mCollisionMassScale = mLowLevelCloth->getCollisionMassScale(); + bulkData.mLinearDrag = mLowLevelCloth->getLinearDrag(); + bulkData.mAngularDrag = mLowLevelCloth->getAngularDrag(); + bulkData.mLinearInertia = mLowLevelCloth->getLinearInertia(); + bulkData.mAngularInertia = mLowLevelCloth->getAngularInertia(); + bulkData.mCentrifugalInertia = mLowLevelCloth->getCentrifugalInertia(); + bulkData.mSolverFrequency = mLowLevelCloth->getSolverFrequency(); + bulkData.mStiffnessFrequency = mLowLevelCloth->getStiffnessFrequency(); + bulkData.mSelfCollisionDistance = mLowLevelCloth->getSelfCollisionDistance(); + bulkData.mSelfCollisionStiffness = mLowLevelCloth->getSelfCollisionStiffness(); + bulkData.mGlobalPose = getGlobalPose(); + bulkData.mSleepThreshold = mLowLevelCloth->getSleepThreshold(); + bulkData.mWakeCounter = getWakeCounter(); + bulkData.mWindVelocity = getWindVelocity(); + bulkData.mDragCoefficient = getDragCoefficient(); + bulkData.mLiftCoefficient = getLiftCoefficient(); +} + +void Sc::ClothCore::resolveReferences(Sc::ClothFabricCore& fabric) +{ + PX_ASSERT(mBulkData); + + mFabric = &fabric; + + // at this point we have all our bulk data and a reference + // to the Sc::ClothFabricCore object so we can go ahead + // and create the low level cloth object + + initLowLevel(mBulkData->mGlobalPose, mBulkData->mParticles.begin()); + + mLowLevelCloth->setSpheres(createRange<PxVec4>(mBulkData->mCollisionSpheres.begin(), mBulkData->mCollisionSpheres.size()), 0, 0); + mLowLevelCloth->setCapsules(createRange<PxU32>(mBulkData->mCollisionPairs.begin(), mBulkData->mCollisionPairs.size()/2), 0, 0); + mLowLevelCloth->setPlanes(createRange<PxVec4>(mBulkData->mCollisionPlanes.begin(), mBulkData->mCollisionPlanes.size()), 0, 0); + mLowLevelCloth->setConvexes(createRange<PxU32>(mBulkData->mConvexMasks.begin(), mBulkData->mConvexMasks.size()), 0, 0); + mLowLevelCloth->setTriangles(createRange<PxVec3>(mBulkData->mCollisionTriangles.begin(), mBulkData->mCollisionTriangles.size()*3), 0, 0); + + // update virtual particles + if (mBulkData->mVpData.size()) + setVirtualParticles(mBulkData->mVpData.size()/4, mBulkData->mVpData.begin(), + mBulkData->mVpWeightData.size(), mBulkData->mVpWeightData.begin()); + + // update motion constraints + if (mBulkData->mConstraints.size()) + setMotionConstraints(mBulkData->mConstraints.begin()); + + // update separation constraints + if (mBulkData->mSeparationConstraints.size()) + setSeparationConstraints(mBulkData->mSeparationConstraints.begin()); + + // update particle accelerations + if (mBulkData->mParticleAccelerations.size()) + setParticleAccelerations(mBulkData->mParticleAccelerations.begin()); + + if (mBulkData->mSelfCollisionIndices.size()) + { + setSelfCollisionIndices(mBulkData->mSelfCollisionIndices.begin(), + mBulkData->mSelfCollisionIndices.size()); + } + + // update rest positions + if (mBulkData->mRestPositions.size()) + setRestPositions(mBulkData->mRestPositions.begin()); + + mLowLevelCloth->setTetherConstraintScale(mBulkData->mTetherConstraintScale); + mLowLevelCloth->setTetherConstraintStiffness(mBulkData->mTetherConstraintStiffness); + mLowLevelCloth->setMotionConstraintScaleBias(mBulkData->mMotionConstraintScale, mBulkData->mMotionConstraintBias); + mLowLevelCloth->setMotionConstraintStiffness(mBulkData->mMotionConstraintStiffness); + setExternalAcceleration(mBulkData->mAcceleration); + mLowLevelCloth->setDamping(mBulkData->mDamping); + mLowLevelCloth->setFriction(mBulkData->mFriction); + mLowLevelCloth->setCollisionMassScale(mBulkData->mCollisionMassScale); + mLowLevelCloth->setLinearDrag(mBulkData->mLinearDrag); + mLowLevelCloth->setAngularDrag(mBulkData->mAngularDrag); + mLowLevelCloth->setLinearInertia(mBulkData->mLinearInertia); + mLowLevelCloth->setAngularInertia(mBulkData->mAngularInertia); + mLowLevelCloth->setCentrifugalInertia(mBulkData->mCentrifugalInertia); + mLowLevelCloth->setSolverFrequency(mBulkData->mSolverFrequency); + mLowLevelCloth->setStiffnessFrequency(mBulkData->mStiffnessFrequency); + mLowLevelCloth->setSelfCollisionDistance(mBulkData->mSelfCollisionDistance); + mLowLevelCloth->setSelfCollisionStiffness(mBulkData->mSelfCollisionStiffness); + + mLowLevelCloth->setSleepThreshold(mBulkData->mSleepThreshold); + setWakeCounter(mBulkData->mWakeCounter); + + mLowLevelCloth->setWindVelocity(mBulkData->mWindVelocity); + mLowLevelCloth->setDragCoefficient(mBulkData->mDragCoefficient); + mLowLevelCloth->setLiftCoefficient(mBulkData->mLiftCoefficient); + + mBulkData = NULL; +} + +void Sc::ClothBulkData::exportExtraData(PxSerializationContext& context) +{ + Cm::exportArray(mParticles, context); + Cm::exportArray(mVpData, context); + Cm::exportArray(mVpWeightData, context); + Cm::exportArray(mCollisionSpheres, context); + Cm::exportArray(mCollisionPairs, context); + Cm::exportArray(mCollisionPlanes, context); + Cm::exportArray(mConvexMasks, context); + Cm::exportArray(mCollisionTriangles, context); + Cm::exportArray(mConstraints, context); + Cm::exportArray(mSeparationConstraints, context); + Cm::exportArray(mParticleAccelerations, context); + Cm::exportArray(mRestPositions, context); +} + +void Sc::ClothBulkData::importExtraData(PxDeserializationContext& context) +{ + Cm::importArray(mParticles, context); + Cm::importArray(mVpData, context); + Cm::importArray(mVpWeightData, context); + Cm::importArray(mCollisionSpheres, context); + Cm::importArray(mCollisionPairs, context); + Cm::importArray(mCollisionPlanes, context); + Cm::importArray(mConvexMasks, context); + Cm::importArray(mCollisionTriangles, context); + Cm::importArray(mConstraints, context); + Cm::importArray(mSeparationConstraints, context); + Cm::importArray(mParticleAccelerations, context); + Cm::importArray(mRestPositions, context); +} + +void Sc::ClothCore::exportExtraData(PxSerializationContext& stream) +{ + PX_ALLOCA(buf, ClothBulkData, 1); + Cm::markSerializedMem(buf, sizeof(ClothBulkData)); + ClothBulkData* bulkData = PX_PLACEMENT_NEW(buf, ClothBulkData); + updateBulkData(*bulkData); + stream.writeData(bulkData, sizeof(ClothBulkData)); + bulkData->exportExtraData(stream); + bulkData->~ClothBulkData(); +} + + +void Sc::ClothCore::importExtraData(PxDeserializationContext& context) +{ + mBulkData = context.readExtraData<ClothBulkData>(); + mBulkData->importExtraData(context); +} + +//~PX_SERIALIZATION + + +void Sc::ClothCore::setParticles(const PxClothParticle* currentParticles, const PxClothParticle* previousParticles) +{ + if (currentParticles) + { + cloth::MappedRange<PxVec4> particlesRange = mLowLevelCloth->getCurrentParticles(); + if(reinterpret_cast<const PxClothParticle*>(particlesRange.begin()) != currentParticles) + PxMemCopy(particlesRange.begin(), currentParticles, particlesRange.size() * sizeof(PxVec4)); + } + + if (previousParticles) + { + cloth::MappedRange<PxVec4> particlesRange = mLowLevelCloth->getPreviousParticles(); + if(reinterpret_cast<const PxClothParticle*>(particlesRange.begin()) != previousParticles) + PxMemCopy(particlesRange.begin(), previousParticles, particlesRange.size() * sizeof(PxVec4)); + } +} + +PxU32 Sc::ClothCore::getNbParticles() const +{ + return mLowLevelCloth->getNumParticles(); +} + +void Sc::ClothCore::setMotionConstraints(const PxClothParticleMotionConstraint* motionConstraints) +{ + if(motionConstraints) + { + cloth::Range<PxVec4> motionConstraintsRange = mLowLevelCloth->getMotionConstraints(); + PxMemCopy(motionConstraintsRange.begin(), motionConstraints, + PxU32(motionConstraintsRange.size() * sizeof(PxClothParticleMotionConstraint))); + } else { + mLowLevelCloth->clearMotionConstraints(); + } +} + +bool Sc::ClothCore::getMotionConstraints(PxClothParticleMotionConstraint* motionConstraintsBuffer) const +{ + PxU32 nbConstraints = mLowLevelCloth->getNumMotionConstraints(); + + if (nbConstraints) + { + PxVec4* constrData = reinterpret_cast<PxVec4*>(motionConstraintsBuffer); + cloth::Range<PxVec4> constrRange = createRange<PxVec4>(constrData, nbConstraints); + + mLowLevelCloth->getFactory().extractMotionConstraints(*mLowLevelCloth, constrRange); + + return true; + } + else + return false; +} + +PxU32 Sc::ClothCore::getNbMotionConstraints() const +{ + return mLowLevelCloth->getNumMotionConstraints(); +} + +void Sc::ClothCore::setMotionConstraintConfig(const PxClothMotionConstraintConfig& config) +{ + mLowLevelCloth->setMotionConstraintScaleBias(config.scale, config.bias); + mLowLevelCloth->setMotionConstraintStiffness(config.stiffness); +} + + +PxClothMotionConstraintConfig Sc::ClothCore::getMotionConstraintConfig() const +{ + PxClothMotionConstraintConfig result; + result.scale = mLowLevelCloth->getMotionConstraintScale(); + result.bias = mLowLevelCloth->getMotionConstraintBias(); + result.stiffness = mLowLevelCloth->getMotionConstraintStiffness(); + return result; +} + +void Sc::ClothCore::setSeparationConstraints(const PxClothParticleSeparationConstraint* separationConstraints) +{ + if (separationConstraints) + { + cloth::Range<PxVec4> separationConstraintsRange = mLowLevelCloth->getSeparationConstraints(); + PxMemCopy(separationConstraintsRange.begin(), separationConstraints, + PxU32(separationConstraintsRange.size() * sizeof(PxClothParticleSeparationConstraint))); + } else { + mLowLevelCloth->clearSeparationConstraints(); + } +} + +bool Sc::ClothCore::getSeparationConstraints(PxClothParticleSeparationConstraint* separationConstraintsBuffer) const +{ + PxU32 nbConstraints = mLowLevelCloth->getNumSeparationConstraints(); + + if (nbConstraints) + { + PxVec4* constrData = reinterpret_cast<PxVec4*>(separationConstraintsBuffer); + cloth::Range<PxVec4> constrRange = createRange<PxVec4>(constrData, nbConstraints); + + mLowLevelCloth->getFactory().extractSeparationConstraints(*mLowLevelCloth, constrRange); + + return true; + } + else + return false; +} + +PxU32 Sc::ClothCore::getNbSeparationConstraints() const +{ + return mLowLevelCloth->getNumSeparationConstraints(); +} + +void Sc::ClothCore::clearInterpolation() +{ + return mLowLevelCloth->clearInterpolation(); +} + +void Sc::ClothCore::setParticleAccelerations(const PxVec4* particleAccelerations) +{ + if(particleAccelerations) + { + cloth::Range<PxVec4> accelerationsRange = mLowLevelCloth->getParticleAccelerations(); + PxMemCopy(accelerationsRange.begin(), + particleAccelerations, accelerationsRange.size() * sizeof(PxVec4)); + } else { + mLowLevelCloth->clearParticleAccelerations(); + } +} + +bool Sc::ClothCore::getParticleAccelerations(PxVec4* particleAccelerationBuffer) const +{ + PxU32 nbAccelerations = mLowLevelCloth->getNumParticleAccelerations(); + + if (nbAccelerations) + { + PxVec4* accelData = reinterpret_cast<PxVec4*>(particleAccelerationBuffer); + cloth::Range<PxVec4> accelRange = createRange<PxVec4>(accelData, nbAccelerations); + + mLowLevelCloth->getFactory().extractParticleAccelerations(*mLowLevelCloth, accelRange); + + return true; + } + else + return false; +} + +PxU32 Sc::ClothCore::getNbParticleAccelerations() const +{ + return mLowLevelCloth->getNumParticleAccelerations(); +} + + +void Sc::ClothCore::addCollisionSphere(const PxClothCollisionSphere& sphere) +{ + const PxVec4* data = reinterpret_cast<const PxVec4*>(&sphere); + mLowLevelCloth->setSpheres(createRange<const PxVec4>(data, 1), mNumUserSpheres, mNumUserSpheres); + ++mNumUserSpheres; +} +void Sc::ClothCore::removeCollisionSphere(PxU32 index) +{ + PxU32 numCapsules = mLowLevelCloth->getNumCapsules(); + mLowLevelCloth->setSpheres(cloth::Range<const PxVec4>(), index, index+1); + mNumUserCapsules -= numCapsules - mLowLevelCloth->getNumCapsules(); + --mNumUserSpheres; +} +void Sc::ClothCore::setCollisionSpheres(const PxClothCollisionSphere* spheresBuffer, PxU32 count) +{ + const PxVec4* data = reinterpret_cast<const PxVec4*>(spheresBuffer); + PxU32 numCapsules = mLowLevelCloth->getNumCapsules(); + mLowLevelCloth->setSpheres(createRange<const PxVec4>(data, count), 0, mNumUserSpheres); + mNumUserCapsules -= numCapsules - mLowLevelCloth->getNumCapsules(); + mNumUserSpheres = count; +} +PxU32 Sc::ClothCore::getNbCollisionSpheres() const +{ + return mLowLevelCloth->getNumSpheres(); +} + +void Sc::ClothCore::getCollisionData(PxClothCollisionSphere* spheresBuffer, PxU32* capsulesBuffer, + PxClothCollisionPlane* planesBuffer, PxU32* convexesBuffer, PxClothCollisionTriangle* trianglesBuffer) const +{ + PxVec4* sphereData = reinterpret_cast<PxVec4*>(spheresBuffer); + cloth::Range<PxVec4> sphereRange = createRange<PxVec4>(sphereData, sphereData ? mLowLevelCloth->getNumSpheres() : 0); + uint32_t* capsuleData = reinterpret_cast<uint32_t*>(capsulesBuffer); + cloth::Range<uint32_t> capsuleRange = createRange<uint32_t>(capsuleData, capsuleData ? 2*mLowLevelCloth->getNumCapsules() : 0); + PxVec4* planeData = reinterpret_cast<PxVec4*>(planesBuffer); + cloth::Range<PxVec4> planeRange = createRange<PxVec4>(planeData, planeData ? mLowLevelCloth->getNumPlanes() : 0); + uint32_t* convexData = reinterpret_cast<uint32_t*>(convexesBuffer); + cloth::Range<uint32_t> convexRange = createRange<uint32_t>(convexData, convexData ? mLowLevelCloth->getNumConvexes() : 0); + PxVec3* triangleData = reinterpret_cast<PxVec3*>(trianglesBuffer); + cloth::Range<PxVec3> triangleRange = createRange<PxVec3>(triangleData, triangleData ? mLowLevelCloth->getNumTriangles() * 3 : 0); + + mLowLevelCloth->getFactory().extractCollisionData(*mLowLevelCloth, sphereRange, capsuleRange, planeRange, convexRange, triangleRange); +} + +void Sc::ClothCore::addCollisionCapsule(PxU32 first, PxU32 second) +{ + PxU32 indices[2] = { first, second }; + mLowLevelCloth->setCapsules(createRange<const PxU32>(indices, 2), mNumUserCapsules, mNumUserCapsules); + ++mNumUserCapsules; +} +void Sc::ClothCore::removeCollisionCapsule(PxU32 index) +{ + mLowLevelCloth->setCapsules(cloth::Range<const PxU32>(), index, index+1); + --mNumUserCapsules; +} +PxU32 Sc::ClothCore::getNbCollisionCapsules() const +{ + return mLowLevelCloth->getNumCapsules(); +} + +void Sc::ClothCore::addCollisionTriangle(const PxClothCollisionTriangle& triangle) +{ + mLowLevelCloth->setTriangles(createRange<const PxVec3>(&triangle, 3), mNumUserTriangles, mNumUserTriangles); + ++mNumUserTriangles; +} +void Sc::ClothCore::removeCollisionTriangle(PxU32 index) +{ + mLowLevelCloth->setTriangles(cloth::Range<const PxVec3>(), index, index+1); + --mNumUserTriangles; +} +void Sc::ClothCore::setCollisionTriangles(const PxClothCollisionTriangle* trianglesBuffer, PxU32 count) +{ + mLowLevelCloth->setTriangles(createRange<const PxVec3>(trianglesBuffer, count*3), 0, mNumUserTriangles); + mNumUserTriangles = count; +} +PxU32 Sc::ClothCore::getNbCollisionTriangles() const +{ + return mLowLevelCloth->getNumTriangles(); +} + +void Sc::ClothCore::addCollisionPlane(const PxClothCollisionPlane& plane) +{ + mLowLevelCloth->setPlanes(createRange<const PxVec4>(&plane, 1), mNumUserPlanes, mNumUserPlanes); + ++mNumUserPlanes; +} +void Sc::ClothCore::removeCollisionPlane(PxU32 index) +{ + PxU32 numConvexes = mLowLevelCloth->getNumConvexes(); + mLowLevelCloth->setPlanes(cloth::Range<const PxVec4>(), index, index+1); + mNumUserConvexes -= numConvexes - mLowLevelCloth->getNumConvexes(); + --mNumUserPlanes; +} +void Sc::ClothCore::setCollisionPlanes(const PxClothCollisionPlane* planesBuffer, PxU32 count) +{ + PxU32 numConvexes = mLowLevelCloth->getNumConvexes(); + mLowLevelCloth->setPlanes(createRange<const PxVec4>(planesBuffer, count), 0, mNumUserPlanes); + mNumUserConvexes -= numConvexes - mLowLevelCloth->getNumConvexes(); + mNumUserPlanes = count; +} +PxU32 Sc::ClothCore::getNbCollisionPlanes() const +{ + return mLowLevelCloth->getNumPlanes(); +} + +void Sc::ClothCore::addCollisionConvex(PxU32 mask) +{ + mLowLevelCloth->setConvexes(createRange<const PxU32>(&mask, 1), mNumUserConvexes, mNumUserConvexes); + ++mNumUserConvexes; +} +void Sc::ClothCore::removeCollisionConvex(PxU32 index) +{ + mLowLevelCloth->setConvexes(cloth::Range<const PxU32>(), index, index+1); + --mNumUserConvexes; +} +PxU32 Sc::ClothCore::getNbCollisionConvexes() const +{ + return mLowLevelCloth->getNumConvexes(); +} + +void Sc::ClothCore::setVirtualParticles(PxU32 numParticles, const PxU32* indices, PxU32 numWeights, const PxVec3* weights) +{ + cloth::Range<const PxU32[4]> vertexAndWeightIndicesRange = createRange<const PxU32[4]>(indices, numParticles); + cloth::Range<const PxVec3> weightTableRange = createRange<const PxVec3>(weights, numWeights); + + mLowLevelCloth->setVirtualParticles(vertexAndWeightIndicesRange, weightTableRange); +} + + +PxU32 Sc::ClothCore::getNbVirtualParticles() const +{ + return mLowLevelCloth->getNumVirtualParticles(); +} + + +void Sc::ClothCore::getVirtualParticles(PxU32* indicesBuffer) const +{ + PxU32 numVParticles = PxU32(mLowLevelCloth->getNumVirtualParticles()); + PxU32 (*data)[4] = reinterpret_cast<PxU32(*)[4]>(indicesBuffer); + cloth::Range<PxU32[4]> vParticleRange(data, data + numVParticles); + cloth::Range<PxVec3> weightTableRange; + + mLowLevelCloth->getFactory().extractVirtualParticles(*mLowLevelCloth, vParticleRange, weightTableRange); +} + + +PxU32 Sc::ClothCore::getNbVirtualParticleWeights() const +{ + return mLowLevelCloth->getNumVirtualParticleWeights(); +} + + +void Sc::ClothCore::getVirtualParticleWeights(PxVec3* weightsBuffer) const +{ + PxU32 numWeights = PxU32(mLowLevelCloth->getNumVirtualParticleWeights()); + cloth::Range<PxU32[4]> indicesRange; + cloth::Range<PxVec3> weightsRange(weightsBuffer, weightsBuffer + numWeights); + + mLowLevelCloth->getFactory().extractVirtualParticles(*mLowLevelCloth, indicesRange, weightsRange); +} + + +PxTransform Sc::ClothCore::getGlobalPose() const +{ + PxTransform pose(mLowLevelCloth->getTranslation(), mLowLevelCloth->getRotation()); + return pose; +} + + +void Sc::ClothCore::setGlobalPose(const PxTransform& pose) +{ + mLowLevelCloth->setTranslation(pose.p); + mLowLevelCloth->setRotation(pose.q); + mLowLevelCloth->clearInertia(); +} + +PxVec3 Sc::ClothCore::getLinearInertiaScale() const +{ + return mLowLevelCloth->getLinearInertia(); +} + +void Sc::ClothCore::setLinearInertiaScale(PxVec3 scale) +{ + mLowLevelCloth->setLinearInertia(scale); +} + +PxVec3 Sc::ClothCore::getAngularInertiaScale() const +{ + return mLowLevelCloth->getAngularInertia(); +} + +void Sc::ClothCore::setAngularInertiaScale(PxVec3 scale) +{ + mLowLevelCloth->setAngularInertia(scale); +} + +PxVec3 Sc::ClothCore::getCentrifugalInertiaScale() const +{ + return mLowLevelCloth->getCentrifugalInertia(); +} + +void Sc::ClothCore::setCentrifugalInertiaScale(PxVec3 scale) +{ + mLowLevelCloth->setCentrifugalInertia(scale); +} + +void Sc::ClothCore::setTargetPose(const PxTransform& pose) +{ + //!!!CL todo: behavior for free-standing cloth? + mLowLevelCloth->setTranslation(pose.p); + mLowLevelCloth->setRotation(pose.q); +} + + +void Sc::ClothCore::setExternalAcceleration(PxVec3 acceleration) +{ + mExternalAcceleration = acceleration; +} + + +PxVec3 Sc::ClothCore::getExternalAcceleration() const +{ + return mExternalAcceleration; +} + + +void Sc::ClothCore::setDampingCoefficient(PxVec3 dampingCoefficient) +{ + mLowLevelCloth->setDamping(dampingCoefficient); +} + + +PxVec3 Sc::ClothCore::getDampingCoefficient() const +{ + return mLowLevelCloth->getDamping(); +} + +void Sc::ClothCore::setFrictionCoefficient(PxReal frictionCoefficient) +{ + mLowLevelCloth->setFriction(frictionCoefficient); +} + + +PxReal Sc::ClothCore::getFrictionCoefficient() const +{ + return mLowLevelCloth->getFriction(); +} + +void Sc::ClothCore::setLinearDragCoefficient(PxVec3 dragCoefficient) +{ + mLowLevelCloth->setLinearDrag(dragCoefficient); +} + +PxVec3 Sc::ClothCore::getLinearDragCoefficient() const +{ + return mLowLevelCloth->getLinearDrag(); +} +void Sc::ClothCore::setAngularDragCoefficient(PxVec3 dragCoefficient) +{ + mLowLevelCloth->setAngularDrag(dragCoefficient); +} + +PxVec3 Sc::ClothCore::getAngularDragCoefficient() const +{ + return mLowLevelCloth->getAngularDrag(); +} + +void Sc::ClothCore::setCollisionMassScale(PxReal scalingCoefficient) +{ + mLowLevelCloth->setCollisionMassScale(scalingCoefficient); +} +PxReal Sc::ClothCore::getCollisionMassScale() const +{ + return mLowLevelCloth->getCollisionMassScale(); +} + +void Sc::ClothCore::setSelfCollisionDistance(PxReal distance) +{ + mLowLevelCloth->setSelfCollisionDistance(distance); +} +PxReal Sc::ClothCore::getSelfCollisionDistance() const +{ + return mLowLevelCloth->getSelfCollisionDistance(); +} +void Sc::ClothCore::setSelfCollisionStiffness(PxReal stiffness) +{ + mLowLevelCloth->setSelfCollisionStiffness(stiffness); +} +PxReal Sc::ClothCore::getSelfCollisionStiffness() const +{ + return mLowLevelCloth->getSelfCollisionStiffness(); +} + +void Sc::ClothCore::setSelfCollisionIndices(const PxU32* indices, PxU32 nbIndices) +{ + mLowLevelCloth->setSelfCollisionIndices( + cloth::Range<const PxU32>(indices, indices + nbIndices)); +} + +bool Sc::ClothCore::getSelfCollisionIndices(PxU32* indices) const +{ + PxU32 nbIndices = mLowLevelCloth->getNumSelfCollisionIndices(); + mLowLevelCloth->getFactory().extractSelfCollisionIndices( + *mLowLevelCloth, cloth::Range<PxU32>(indices, indices + nbIndices)); + return !!nbIndices; +} + +PxU32 Sc::ClothCore::getNbSelfCollisionIndices() const +{ + return mLowLevelCloth->getNumSelfCollisionIndices(); +} + +void Sc::ClothCore::setRestPositions(const PxVec4* restPositions) +{ + PxU32 size = restPositions ? mLowLevelCloth->getNumParticles() : 0; + mLowLevelCloth->setRestPositions(cloth::Range<const PxVec4>(restPositions, restPositions + size)); +} + +bool Sc::ClothCore::getRestPositions(PxVec4* restPositions) const +{ + PxU32 size = mLowLevelCloth->getNumRestPositions(); + mLowLevelCloth->getFactory().extractRestPositions(*mLowLevelCloth, + cloth::Range<PxVec4>(restPositions, restPositions + size)); + return true; +} + +PxU32 Sc::ClothCore::getNbRestPositions() const +{ + return mLowLevelCloth->getNumRestPositions(); +} + +void Sc::ClothCore::setSolverFrequency(PxReal solverFreq) +{ + mLowLevelCloth->setSolverFrequency(solverFreq); +} + +PxReal Sc::ClothCore::getSolverFrequency() const +{ + return mLowLevelCloth->getSolverFrequency(); +} + +void Sc::ClothCore::setStiffnessFrequency(PxReal frequency) +{ + mLowLevelCloth->setStiffnessFrequency(frequency); +} + + +PxReal Sc::ClothCore::getStiffnessFrequency() const +{ + return mLowLevelCloth->getStiffnessFrequency(); +} + +void physx::Sc::ClothCore::setStretchConfig(PxClothFabricPhaseType::Enum type, const PxClothStretchConfig& config) +{ + cloth::PhaseConfig pc; + pc.mStiffness = config.stiffness; + pc.mStiffnessMultiplier = config.stiffnessMultiplier; + pc.mStretchLimit = config.stretchLimit; + pc.mCompressionLimit = config.compressionLimit; + + PxU32 nbPhases = mFabric->getNbPhases(); + for(PxU32 i=0; i < nbPhases; i++) + { + // update phase config copies (but preserve existing phase index) + if (mFabric->getPhaseType(i) == type) + { + mPhaseConfigs[i].mStiffness = config.stiffness; + mPhaseConfigs[i].mStiffnessMultiplier = config.stiffnessMultiplier; + mPhaseConfigs[i].mCompressionLimit = config.compressionLimit; + mPhaseConfigs[i].mStretchLimit = config.stretchLimit; + } + } + + // set to low level + cloth::Range<const cloth::PhaseConfig> phaseConfigRange = createRange<const cloth::PhaseConfig>(mPhaseConfigs, nbPhases); + mLowLevelCloth->setPhaseConfig(phaseConfigRange); +} + +void Sc::ClothCore::setTetherConfig(const PxClothTetherConfig& config) +{ + mLowLevelCloth->setTetherConstraintScale(config.stretchLimit); + mLowLevelCloth->setTetherConstraintStiffness(config.stiffness); +} + +PxClothStretchConfig Sc::ClothCore::getStretchConfig(PxClothFabricPhaseType::Enum type) const +{ + cloth::PhaseConfig pc; + PxU32 nbPhases = mFabric->getNbPhases(); + for(PxU32 i=0; i < nbPhases; i++) + { + if (mFabric->getPhaseType(i) == type) + { + pc = mPhaseConfigs[i]; + break; + } + } + + return PxClothStretchConfig(pc.mStiffness, pc.mStiffnessMultiplier, pc.mCompressionLimit, pc.mStretchLimit); +} + +PxClothTetherConfig Sc::ClothCore::getTetherConfig() const +{ + return PxClothTetherConfig( + mLowLevelCloth->getTetherConstraintStiffness(), + mLowLevelCloth->getTetherConstraintScale()); +} + + +void Sc::ClothCore::setClothFlags(PxClothFlags flags) +{ + PxClothFlags diff = mClothFlags ^ flags; + mClothFlags = flags; + + if((diff & ~flags) & PxClothFlag::eSCENE_COLLISION) + getSim()->clearCollisionShapes(); + + if(diff & PxClothFlag::eSWEPT_CONTACT) + mLowLevelCloth->enableContinuousCollision(flags.isSet(PxClothFlag::eSWEPT_CONTACT)); + + if((diff & PxClothFlag::eCUDA) && getSim()) + getSim()->reinsert(); +} + + +PxClothFlags Sc::ClothCore::getClothFlags() const +{ + return mClothFlags; +} + +void Sc::ClothCore::setWindVelocity(PxVec3 value) +{ + mLowLevelCloth->setWindVelocity(value); +} +PxVec3 Sc::ClothCore::getWindVelocity() const +{ + return mLowLevelCloth->getWindVelocity(); +} +void Sc::ClothCore::setDragCoefficient(PxReal value) +{ + mLowLevelCloth->setDragCoefficient(value); +} +PxReal Sc::ClothCore::getDragCoefficient() const +{ + return mLowLevelCloth->getDragCoefficient(); +} +void Sc::ClothCore::setLiftCoefficient(PxReal value) +{ + mLowLevelCloth->setLiftCoefficient(value); +} +PxReal Sc::ClothCore::getLiftCoefficient() const +{ + return mLowLevelCloth->getLiftCoefficient(); +} + +bool Sc::ClothCore::isSleeping() const +{ + return mLowLevelCloth->isAsleep(); +} + + +PxReal Sc::ClothCore::getSleepLinearVelocity() const +{ + return mLowLevelCloth->getSleepThreshold(); +} + + +void Sc::ClothCore::setSleepLinearVelocity(PxReal threshold) +{ + mLowLevelCloth->setSleepThreshold(threshold); // does wake the cloth up automatically +} + + +void Sc::ClothCore::setWakeCounter(PxReal wakeCounterValue) +{ + if(wakeCounterValue > PX_MAX_U32 / 1000) + return mLowLevelCloth->setSleepTestInterval(PX_MAX_U32); + + PxU32 intervalsToSleep = PxU32(wakeCounterValue * 1000); + + // test at least 5 times until sleep, or 5 times per second + PxU32 testInterval = PxMax(1u, PxMin(intervalsToSleep / 5, 200u)); + PxU32 afterCount = intervalsToSleep / testInterval; + + bool wasSleeping = mLowLevelCloth->isAsleep(); + + // does wake the cloth up automatically + mLowLevelCloth->setSleepTestInterval(testInterval); + mLowLevelCloth->setSleepAfterCount(afterCount); + + // setWakeCounter(0) should not change the sleep state, put back to sleep + if (wasSleeping && wakeCounterValue == 0.0f) + mLowLevelCloth->putToSleep(); +} + +PxReal Sc::ClothCore::getWakeCounter() const +{ + PxU32 testInterval = mLowLevelCloth->getSleepTestInterval(); + if(testInterval == PX_MAX_U32) + return PX_MAX_REAL; + + PxU32 afterCount = mLowLevelCloth->getSleepAfterCount(); + PxU32 passCount = mLowLevelCloth->getSleepPassCount(); + + if (passCount >= afterCount) + return 0.0f; + + return (afterCount - passCount) * testInterval / 1000.0f; +} + +void Sc::ClothCore::wakeUp(PxReal wakeCounter) +{ + setWakeCounter(wakeCounter); +} + + +void Sc::ClothCore::putToSleep() +{ + mLowLevelCloth->putToSleep(); +} + + +void Sc::ClothCore::getParticleData(PxClothParticleData& data) +{ + if(data.getDataAccessFlags() & PxDataAccessFlag::eDEVICE) + { + cloth::GpuParticles particles = mLowLevelCloth->getGpuParticles(); + data.particles = reinterpret_cast<PxClothParticle*>(particles.mCurrent); + data.previousParticles = reinterpret_cast<PxClothParticle*>(particles.mPrevious); + } + else + { + mLowLevelCloth->lockParticles(); + // When eWRITABLE flag is set, write happens during PxClothParticleData::unlock() + data.particles = reinterpret_cast<PxClothParticle*>(const_cast<PxVec4*>( + cloth::readCurrentParticles(*mLowLevelCloth).begin())); + data.previousParticles = reinterpret_cast<PxClothParticle*>(const_cast<PxVec4*>( + cloth::readPreviousParticles(*mLowLevelCloth).begin())); + } +} + +void Sc::ClothCore::unlockParticleData() +{ + mLowLevelCloth->unlockParticles(); +} + + +PxReal Sc::ClothCore::getPreviousTimeStep() const +{ + return mLowLevelCloth->getPreviousIterationDt(); +} + + +PxBounds3 Sc::ClothCore::getWorldBounds() const +{ + const PxVec3& center = reinterpret_cast<const PxVec3&>(mLowLevelCloth->getBoundingBoxCenter()); + const PxVec3& extent = reinterpret_cast<const PxVec3&>(mLowLevelCloth->getBoundingBoxScale()); + + PxBounds3 localBounds = PxBounds3::centerExtents(center, extent); + + PX_ASSERT(!localBounds.isEmpty()); + return PxBounds3::transformFast(getGlobalPose(), localBounds); +} + +void Sc::ClothCore::setSimulationFilterData(const PxFilterData& data) +{ + mFilterData = data; +} + +PxFilterData Sc::ClothCore::getSimulationFilterData() const +{ + return mFilterData; +} + +void Sc::ClothCore::setContactOffset(PxReal offset) +{ + mContactOffset = offset; +} + +PxReal Sc::ClothCore::getContactOffset() const +{ + return mContactOffset; +} + +void Sc::ClothCore::setRestOffset(PxReal offset) +{ + mRestOffset = offset; +} + +PxReal Sc::ClothCore::getRestOffset() const +{ + return mRestOffset; +} + +Sc::ClothSim* Sc::ClothCore::getSim() const +{ + return static_cast<ClothSim*>(Sc::ActorCore::getSim()); +} + +PxCloth* Sc::ClothCore::getPxCloth() +{ + return gOffsetTable.convertScCloth2Px(this); +} + +void Sc::ClothCore::onOriginShift(const PxVec3& shift) +{ + mLowLevelCloth->teleport(-shift); +} + +void Sc::ClothCore::switchCloth(cloth::Cloth* cl) +{ + cloth::Fabric* fabric = &mLowLevelCloth->getFabric(); + cloth::Factory::Platform platform = mLowLevelCloth->getFactory().getPlatform(); + + PX_DELETE(mLowLevelCloth); + mLowLevelCloth = cl; + + // delete fabric if referenced by no lowlevel Cloth or ClothFabricCore. + if (0 == fabric->getRefCount()) + { + if(platform != cloth::Factory::CPU) + mFabric->setLowLevelGpuFabric(NULL); + PX_DELETE(fabric); + } + + if(cl->getFactory().getPlatform() != cloth::Factory::CPU) + mFabric->setLowLevelGpuFabric(&cl->getFabric()); +} + +#endif // PX_USE_CLOTH_API diff --git a/PhysX_3.4/Source/SimulationController/src/cloth/ScClothFabricCore.cpp b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothFabricCore.cpp new file mode 100644 index 00000000..a195b337 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothFabricCore.cpp @@ -0,0 +1,432 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#include "ScClothFabricCore.h" +#if PX_USE_CLOTH_API + +using namespace physx; +using namespace cloth; + +#include "foundation/PxAssert.h" +#include "ScPhysics.h" +#include "Range.h" +#include "Factory.h" +#include "Fabric.h" +#include "GuSerialize.h" +#include "CmPhysXCommon.h" +#include "CmUtils.h" +#include "PsAlloca.h" +#include "PsFoundation.h" + +Sc::ClothFabricCore::ClothFabricCore(const PxEMPTY) + : mLowLevelGpuFabric(NULL), mPhaseTypes(PxEmpty) +{ +} + +Sc::ClothFabricCore::ClothFabricCore() : + mLowLevelFabric(NULL), mLowLevelGpuFabric(NULL) +{ +} + + +Sc::ClothFabricCore::~ClothFabricCore() +{ + if(mLowLevelFabric) + { + mLowLevelFabric->decRefCount(); + if (0 == mLowLevelFabric->getRefCount()) + PX_DELETE(mLowLevelFabric); + } +} + + +// PX_SERIALIZATION +void Sc::ClothFabricBulkData::exportExtraData(PxSerializationContext& context) +{ + Cm::exportArray(mPhases, context); + Cm::exportArray(mSets, context); + Cm::exportArray(mRestvalues, context); + Cm::exportArray(mIndices, context); + Cm::exportArray(mTetherAnchors, context); + Cm::exportArray(mTetherLengths, context); + Cm::exportArray(mTriangles, context); +} + +void Sc::ClothFabricBulkData::importExtraData(PxDeserializationContext& context) +{ + Cm::importArray(mPhases, context); + Cm::importArray(mSets, context); + Cm::importArray(mRestvalues, context); + Cm::importArray(mIndices, context); + Cm::importArray(mTetherAnchors, context); + Cm::importArray(mTetherLengths, context); + Cm::importArray(mTriangles, context); +} + +void Sc::ClothFabricCore::exportExtraData(PxSerializationContext& stream) +{ + Cm::exportArray(mPhaseTypes, stream); + + if(!mLowLevelFabric) + return; + + PX_ALLOCA(buf, ClothFabricBulkData, 1); + Cm::markSerializedMem(buf, sizeof(ClothFabricBulkData)); + ClothFabricBulkData* bulkData = PX_PLACEMENT_NEW(buf, ClothFabricBulkData); + + cloth::Factory& factory = Sc::Physics::getInstance().getLowLevelClothFactory(); + + bulkData->mNbParticles = mLowLevelFabric->getNumParticles(); + bulkData->mPhases.resize(mLowLevelFabric->getNumPhases()); + bulkData->mSets.resize(mLowLevelFabric->getNumSets()); + bulkData->mRestvalues.resize(mLowLevelFabric->getNumRestvalues()); + bulkData->mIndices.resize(mLowLevelFabric->getNumIndices()); + bulkData->mTetherAnchors.reserve(mLowLevelFabric->getNumTethers()); + bulkData->mTetherLengths.reserve(mLowLevelFabric->getNumTethers()); + bulkData->mTriangles.resize(mLowLevelFabric->getNumTriangles() * 3); + + factory.extractFabricData(*mLowLevelFabric, + cloth::Range<uint32_t>(bulkData->mPhases.begin(), bulkData->mPhases.end()), + Range<uint32_t>(bulkData->mSets.begin(), bulkData->mSets.end()), + Range<float>(bulkData->mRestvalues.begin(), bulkData->mRestvalues.end()), + Range<uint32_t>(bulkData->mIndices.begin(), bulkData->mIndices.end()), + Range<uint32_t>(bulkData->mTetherAnchors.begin(), bulkData->mTetherAnchors.end()), + Range<float>(bulkData->mTetherLengths.begin(), bulkData->mTetherLengths.end()), + Range<uint32_t>(bulkData->mTriangles.begin(), bulkData->mTriangles.end())); + + stream.writeData(bulkData, sizeof(ClothFabricBulkData)); + bulkData->exportExtraData(stream); + bulkData->~ClothFabricBulkData(); +} + + +void Sc::ClothFabricCore::importExtraData(PxDeserializationContext& context) +{ + Cm::importArray(mPhaseTypes, context); + + if(mLowLevelFabric) + { + ClothFabricBulkData* bulkData = context.readExtraData<ClothFabricBulkData>(); + bulkData->importExtraData(context); + + cloth::Factory& factory = Sc::Physics::getInstance().getLowLevelClothFactory(); + + mLowLevelFabric = factory.createFabric(bulkData->mNbParticles, + cloth::Range<const uint32_t>(bulkData->mPhases.begin(), bulkData->mPhases.end()), + cloth::Range<const uint32_t>(bulkData->mSets.begin(), bulkData->mSets.end()), + Range<const float>(bulkData->mRestvalues.begin(), bulkData->mRestvalues.end()), + Range<const uint32_t>(bulkData->mIndices.begin(), bulkData->mIndices.end()), + Range<const uint32_t>(bulkData->mTetherAnchors.begin(), bulkData->mTetherAnchors.end()), + Range<const float>(bulkData->mTetherLengths.begin(), bulkData->mTetherLengths.end()), + Range<const uint32_t>(bulkData->mTriangles.begin(), bulkData->mTriangles.end())); + + mLowLevelFabric->incRefCount(); // account for the user reference + } +} +//~PX_SERIALIZATION + +/** + Load cloth fabric data from the given stream. + + @param[in] stream input stream to load fabric data from + @return true if loading was successful + + @sa For cooker implementation, see ClothFabricBuilder.cpp in PhysXCooking/src + */ +bool Sc::ClothFabricCore::load(PxInputStream& stream) +{ + // Import header + PxU32 version; + + stream.read(&version, sizeof(PxU32)); + + // check if incompatible version is used. Version number changed + // from PX_PHYSICS_VERSION to ordinal number in 3.3.2. + // see ExtClothFabricCooker.cpp (PxFabricCookerImpl::save) + if (version != 0x030300 && version != 0x030301 && version != 1) + { + Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, + "Loading cloth fabric failed: mismatching version of cloth fabric stream."); + return false; + } + + PxClothFabricDesc desc; + + stream.read(&desc.nbParticles, sizeof(PxU32)); + stream.read(&desc.nbPhases, sizeof(PxU32)); + stream.read(&desc.nbSets, sizeof(PxU32)); + stream.read(&desc.nbTethers, sizeof(PxU32)); + + Ps::Array<PxClothFabricPhase> phases(desc.nbPhases); + PX_ASSERT(sizeof(PxClothFabricPhaseType::Enum) == sizeof(PxU32)); + stream.read(phases.begin(), desc.nbPhases * sizeof(PxClothFabricPhase)); + desc.phases = phases.begin(); + + Ps::Array<PxU32> sets(desc.nbSets); + stream.read(sets.begin(), desc.nbSets * sizeof(PxU32)); + desc.sets = sets.begin(); + + PxU32 nbRestvalues = sets.back(); + Ps::Array<PxReal> restvalues(nbRestvalues); + stream.read(restvalues.begin(), nbRestvalues * sizeof(PxReal)); + desc.restvalues = restvalues.begin(); + + PxU32 nbParticleIndices = nbRestvalues * 2; + Ps::Array<PxU32> indices(nbParticleIndices); + stream.read(indices.begin(), nbParticleIndices * sizeof(PxU32)); + desc.indices = indices.begin(); + + Ps::Array<PxU32> tetherAnchors(desc.nbTethers); + stream.read(tetherAnchors.begin(), desc.nbTethers * sizeof(PxU32)); + desc.tetherAnchors = tetherAnchors.begin(); + + Ps::Array<PxReal> tetherLengths(desc.nbTethers); + stream.read(tetherLengths.begin(), desc.nbTethers * sizeof(PxReal)); + desc.tetherLengths = tetherLengths.begin(); + + return load(desc); +} + +bool Sc::ClothFabricCore::load(const PxClothFabricDesc& desc) +{ + PX_ASSERT( desc.isValid() ); + + // allocate array + //!!!CL could be optimized by creating a single buffer that can hold all data. Would have to sacrifice the PxArrays but they don't + // seem very useful in this case anyway because it is mostly const data. + + mPhaseTypes.resize(desc.nbPhases); + Ps::Array<PxU32> llphases(desc.nbPhases); + Ps::Array<PxU32> offsets(desc.nbPhases); + + for(PxU32 i=0; i<desc.nbPhases; ++i) + { + if (desc.phases[i].phaseType == PxClothFabricPhaseType::eINVALID || + desc.phases[i].phaseType >= PxClothFabricPhaseType::eCOUNT) + { + Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, + "createClothFabric() failed, invalid phase type specified"); + + return false; + } + + mPhaseTypes[i] = desc.phases[i].phaseType; + llphases[i] = desc.phases[i].setIndex; + } + + cloth::Factory& factory = Sc::Physics::getInstance().getLowLevelClothFactory(); + + PxU32 nbConstraints = desc.sets[desc.nbSets-1]; + + mLowLevelFabric = factory.createFabric(desc.nbParticles, + cloth::Range<const uint32_t>(llphases.begin(), llphases.end()), + cloth::Range<const uint32_t>(desc.sets, desc.sets + desc.nbSets), + cloth::Range<const float>(desc.restvalues, desc.restvalues + nbConstraints), + cloth::Range<const uint32_t>(desc.indices, desc.indices + 2*nbConstraints), + cloth::Range<const uint32_t>(desc.tetherAnchors, desc.tetherAnchors + desc.nbTethers), + cloth::Range<const float>(desc.tetherLengths, desc.tetherLengths + desc.nbTethers), + cloth::Range<const uint32_t>(desc.triangles, desc.triangles + 3 * desc.nbTriangles)); + + mLowLevelFabric->incRefCount(); // account for the user reference + + return true; +} + +/** + returns number of particles + */ +PxU32 Sc::ClothFabricCore::getNbParticles() const +{ + return mLowLevelFabric->getNumParticles(); +} + +PxU32 Sc::ClothFabricCore::getNbPhases() const +{ + return mLowLevelFabric->getNumPhases(); +} + +/** + This function returns number of sets + @return number of phases + */ +PxU32 Sc::ClothFabricCore::getNbSets() const +{ + return mLowLevelFabric->getNumSets(); +} + +/** + get total number of particle (vertex) indices in the fabric array. + */ +PxU32 Sc::ClothFabricCore::getNbParticleIndices() const +{ + return mLowLevelFabric->getNumIndices(); +} + +/** + get total number of rest length array + */ +PxU32 Sc::ClothFabricCore::getNbRestvalues() const +{ + return mLowLevelFabric->getNumRestvalues(); +} + +PxU32 Sc::ClothFabricCore::getNbTethers() const +{ + return mLowLevelFabric->getNumTethers(); +} + +PxU32 Sc::ClothFabricCore::getPhases(PxClothFabricPhase* userPhaseBuffer, PxU32 bufferSize) const +{ + // calculate buffer size + PxU32 nbPhases = getNbPhases(); + if (bufferSize < nbPhases) + return 0; + + shdfnd::Array<PxU32> phases(nbPhases); + + cloth::Factory& factory = Sc::Physics::getInstance().getLowLevelClothFactory(); + + factory.extractFabricData(*mLowLevelFabric, + cloth::Range<uint32_t>(phases.begin(), phases.end()), + Range<uint32_t>(), Range<float>(), Range<uint32_t>(), + Range<uint32_t>(), Range<float>(), Range<uint32_t>()); + + for(PxU32 i=0; i<nbPhases; ++i) + { + userPhaseBuffer[i].setIndex = phases[i]; + userPhaseBuffer[i].phaseType = mPhaseTypes[i]; + } + + return nbPhases; +} + +PxU32 Sc::ClothFabricCore::getRestvalues(PxReal* userRestvalueBuffer, PxU32 bufferSize) const +{ + // calculate buffer size + PxU32 nbRestvalues = getNbRestvalues(); + if (bufferSize < nbRestvalues) + return 0; + + cloth::Factory& factory = Sc::Physics::getInstance().getLowLevelClothFactory(); + + factory.extractFabricData(*mLowLevelFabric, + cloth::Range<uint32_t>(), cloth::Range<uint32_t>(), + Range<float>(userRestvalueBuffer, userRestvalueBuffer + nbRestvalues), + Range<uint32_t>(), Range<uint32_t>(), Range<float>(), Range<uint32_t>()); + + return nbRestvalues; +} + +PxU32 Sc::ClothFabricCore::getSets(PxU32* userSetBuffer, PxU32 bufferSize) const +{ + // calculate buffer size + const PxU32 nbSets = getNbSets(); + if (bufferSize < nbSets) + return 0; + + cloth::Factory& factory = Sc::Physics::getInstance().getLowLevelClothFactory(); + + factory.extractFabricData(*mLowLevelFabric, + cloth::Range<uint32_t>(), Range<uint32_t>(userSetBuffer, userSetBuffer + nbSets), + Range<float>(), Range<uint32_t>(), Range<uint32_t>(), Range<float>(), Range<uint32_t>()); + + return nbSets; +} + +PxU32 Sc::ClothFabricCore::getParticleIndices(PxU32* userParticleIndexBuffer, PxU32 bufferSize) const +{ + // calculate buffer size + const PxU32 nbParticleIndices = getNbParticleIndices(); + if (bufferSize < nbParticleIndices) + return 0; + + cloth::Factory& factory = Sc::Physics::getInstance().getLowLevelClothFactory(); + + factory.extractFabricData(*mLowLevelFabric, + cloth::Range<uint32_t>(), cloth::Range<uint32_t>(), Range<float>(), + Range<uint32_t>(userParticleIndexBuffer, userParticleIndexBuffer + nbParticleIndices), + Range<uint32_t>(), Range<float>(), Range<uint32_t>()); + + return nbParticleIndices; +} + +PxU32 Sc::ClothFabricCore::getTetherAnchors(PxU32* userAnchorBuffer, PxU32 bufferSize) const +{ + // calculate buffer size + const PxU32 nbTethers = getNbTethers(); + if (bufferSize < nbTethers) + return 0; + + cloth::Factory& factory = Sc::Physics::getInstance().getLowLevelClothFactory(); + + factory.extractFabricData(*mLowLevelFabric, + cloth::Range<uint32_t>(), cloth::Range<uint32_t>(), + Range<float>(), Range<uint32_t>(), + Range<uint32_t>(userAnchorBuffer, userAnchorBuffer + nbTethers), Range<float>(), Range<uint32_t>()); + + return nbTethers; +} + +PxU32 Sc::ClothFabricCore::getTetherLengths(PxReal* userLengthBuffer, PxU32 bufferSize) const +{ + // calculate buffer size + const PxU32 nbTethers = getNbTethers(); + if (bufferSize < nbTethers) + return 0; + + cloth::Factory& factory = Sc::Physics::getInstance().getLowLevelClothFactory(); + + factory.extractFabricData(*mLowLevelFabric, + cloth::Range<uint32_t>(), cloth::Range<uint32_t>(), + Range<float>(), Range<uint32_t>(), Range<uint32_t>(), + Range<float>(userLengthBuffer, userLengthBuffer + nbTethers), Range<uint32_t>()); + + return nbTethers; +} + +/** + scale the rest length of constraints by given value. + + @param[in] scale The scale factor (each rest length is multiplied by this value) + */ +void Sc::ClothFabricCore::scaleRestlengths(PxReal scale) +{ + mLowLevelFabric->scaleRestvalues(scale); + mLowLevelFabric->scaleTetherLengths(scale); + + if(mLowLevelGpuFabric) + { + mLowLevelGpuFabric->scaleRestvalues(scale); + mLowLevelGpuFabric->scaleTetherLengths(scale); + } +} + + +#endif // PX_USE_CLOTH_API diff --git a/PhysX_3.4/Source/SimulationController/src/cloth/ScClothShape.cpp b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothShape.cpp new file mode 100644 index 00000000..1d89d13f --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothShape.cpp @@ -0,0 +1,125 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#include "ScClothShape.h" +#if PX_USE_CLOTH_API + +#include "ScNPhaseCore.h" +#include "ScScene.h" + +#include "ScClothSim.h" +#include "PxsContext.h" +#include "BpSimpleAABBManager.h" +#include "ScSqBoundsManager.h" + +using namespace physx; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +Sc::ClothShape::ClothShape(ClothSim& cloth) : + ElementSim(cloth, ElementType::eCLOTH), + mClothCore(cloth.getCore()), + mHasCollision(mClothCore.getClothFlags() & PxClothFlag::eSCENE_COLLISION) +{ + if (mHasCollision) + createLowLevelVolume(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +Sc::ClothShape::~ClothShape() +{ + if (isInBroadPhase()) + destroyLowLevelVolume(); + + PX_ASSERT(!isInBroadPhase()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void Sc::ClothShape::getFilterInfo(PxFilterObjectAttributes& filterAttr, PxFilterData& filterData) const +{ + filterAttr = 0; + ElementSim::setFilterObjectAttributeType(filterAttr, PxFilterObjectType::eCLOTH); + filterData = mClothCore.getSimulationFilterData(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void Sc::ClothShape::updateBoundsInAABBMgr() +{ + if(~mClothCore.getClothFlags() & PxClothFlag::eSCENE_COLLISION) + { + if(mHasCollision) + { + destroyLowLevelVolume(); + mHasCollision = false; + } + return; + } + + if(!mHasCollision) + { + createLowLevelVolume(); + mHasCollision = true; + } + + Scene& scene = getScene(); + + PxBounds3 worldBounds = mClothCore.getWorldBounds(); + worldBounds.fattenSafe(mClothCore.getContactOffset()); // fatten for fast moving colliders + scene.getBoundsArray().setBounds(worldBounds, getElementID()); + scene.getAABBManager()->getChangedAABBMgActorHandleMap().growAndSet(getElementID()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void Sc::ClothShape::createLowLevelVolume() +{ + PX_ASSERT(getWorldBounds().isFinite()); + getScene().getBoundsArray().setBounds(getWorldBounds(), getElementID()); + addToAABBMgr(0, Bp::FilterGroup::eCLOTH_NO_PARTICLE_INTERACTION, false); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void Sc::ClothShape::destroyLowLevelVolume() +{ + if (!isInBroadPhase()) + return; + + Sc::Scene& scene = getScene(); + PxsContactManagerOutputIterator outputs = scene.getLowLevelContext()->getNphaseImplementationContext()->getContactManagerOutputs(); + scene.getNPhaseCore()->onVolumeRemoved(this, 0, outputs, scene.getPublicFlags() & PxSceneFlag::eADAPTIVE_FORCE); + removeFromAABBMgr(); +} + + +#endif // PX_USE_CLOTH_API diff --git a/PhysX_3.4/Source/SimulationController/src/cloth/ScClothShape.h b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothShape.h new file mode 100644 index 00000000..fc3e3735 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothShape.h @@ -0,0 +1,78 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#ifndef PX_PHYSICS_CLOTHSHAPE +#define PX_PHYSICS_CLOTHSHAPE + +#include "CmPhysXCommon.h" +#include "PxPhysXConfig.h" +#if PX_USE_CLOTH_API + +#include "ScElementSim.h" +#include "ScClothCore.h" + +namespace physx +{ +namespace Sc +{ + /** + A collision detection primitive for cloth. + */ + class ClothShape : public ElementSim + { + ClothShape &operator=(const ClothShape &); + public: + ClothShape(ClothSim& cloth); + ~ClothShape(); + + // ElementSim implementation + virtual void getFilterInfo(PxFilterObjectAttributes& filterAttr, PxFilterData& filterData) const; + // ~ElementSim + + public: + PX_INLINE PxBounds3 getWorldBounds() const { return mClothCore.getWorldBounds(); } + PX_INLINE ClothSim& getClothSim() const { return *mClothCore.getSim(); } + + void updateBoundsInAABBMgr(); + + void createLowLevelVolume(); + void destroyLowLevelVolume(); + private: + ClothCore& mClothCore; + bool mHasCollision; + }; + +} // namespace Sc + +} + +#endif // PX_USE_CLOTH_API + +#endif diff --git a/PhysX_3.4/Source/SimulationController/src/cloth/ScClothSim.cpp b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothSim.cpp new file mode 100644 index 00000000..0306f2cc --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothSim.cpp @@ -0,0 +1,894 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#include "ScClothSim.h" +#if PX_USE_CLOTH_API + +#include "PxClothParticleData.h" +#include "PxConvexMesh.h" +#include "PxTriangleMesh.h" +#include "PxHeightField.h" +#include "PxHeightFieldSample.h" + +#include "ScPhysics.h" +#include "ScScene.h" +#include "ScClothCore.h" +#include "ScShapeSim.h" + +#include "CmScaling.h" + +#include "Types.h" +#include "Range.h" +#include "Factory.h" +#include "Cloth.h" + +#include "GuIntersectionTriangleBox.h" +#include "ScNPhaseCore.h" +#include "PsFoundation.h" + +using namespace physx; + +namespace +{ + template <typename D, typename S> + PX_FORCE_INLINE cloth::Range<D> createRange(S begin, PxU32 size) + { + D* start = reinterpret_cast<D*>(begin); + D* end = start + size; + + return cloth::Range<D>(start, end); + } +} + +Sc::ClothSim::ClothSim(Scene& scene, ClothCore& core) : + ActorSim(scene, core), + mClothShape(*this), + mNumSpheres(0), + mNumCapsules(0), + mNumPlanes(0), + mNumBoxes(0), + mNumConvexes(0), + mNumMeshes(0), + mNumHeightfields(0), + mNumConvexPlanes(0) +{ + startStep(); // sync lowlevel gravity to prevent waking up on simulate() +} + + +Sc::ClothSim::~ClothSim() +{ + getCore().setSim(NULL); +} + + +Sc::ClothCore& Sc::ClothSim::getCore() const +{ + return static_cast<ClothCore&>(getActorCore()); +} + +void Sc::ClothSim::updateBounds() +{ + mClothShape.updateBoundsInAABBMgr(); +} + +void Sc::ClothSim::startStep() +{ + updateRigidBodyPositions(); + + // update total external acceleration in LL + PxVec3 externalAcceleration = getCore().getExternalAcceleration(); + if ((getActorCore().getActorFlags() & PxActorFlag::eDISABLE_GRAVITY) == false) + externalAcceleration += getScene().getGravity(); + getCore().getLowLevelCloth()->setGravity(externalAcceleration); +} + + +void Sc::ClothSim::reinsert() +{ + Sc::Scene& scene = getScene(); + Sc::ClothCore& core = getCore(); + + scene.removeCloth(core); + scene.addCloth(core); +} + +bool Sc::ClothSim::addCollisionShape(const ShapeSim* shape) +{ + switch (shape->getGeometryType()) + { + case PxGeometryType::eSPHERE: + return addCollisionSphere(shape); + case PxGeometryType::ePLANE: + return addCollisionPlane(shape); + case PxGeometryType::eCAPSULE: + return addCollisionCapsule(shape); + case PxGeometryType::eBOX: + return addCollisionBox(shape); + case PxGeometryType::eCONVEXMESH: + return addCollisionConvex(shape); + case PxGeometryType::eTRIANGLEMESH: + return addCollisionMesh(shape); + case PxGeometryType::eHEIGHTFIELD: + return addCollisionHeightfield(shape); + case PxGeometryType::eGEOMETRY_COUNT: + case PxGeometryType::eINVALID: + break; + } + return false; +} + +void Sc::ClothSim::removeCollisionShape(const ShapeSim* shape) +{ + switch (shape->getGeometryType()) + { + case PxGeometryType::eSPHERE: + removeCollisionSphere(shape); + break; + case PxGeometryType::ePLANE: + removeCollisionPlane(shape); + break; + case PxGeometryType::eCAPSULE: + removeCollisionCapsule(shape); + break; + case PxGeometryType::eBOX: + removeCollisionBox(shape); + break; + case PxGeometryType::eCONVEXMESH: + removeCollisionConvex(shape); + break; + case PxGeometryType::eTRIANGLEMESH: + removeCollisionMesh(shape); + break; + case PxGeometryType::eHEIGHTFIELD: + removeCollisionHeightfield(shape); + break; + case PxGeometryType::eGEOMETRY_COUNT: + case PxGeometryType::eINVALID: + break; + } +} + +bool Sc::ClothSim::addCollisionSphere(const ShapeSim* shape) +{ + PxU32 startIndex = 0; + +#if PX_DEBUG + const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex; + for (PxU32 index = 0; index<mNumSpheres; ++index) + PX_ASSERT(shapeIt[index] != shape); +#endif + + ClothCore& core = getCore(); + + PxU32 sphereIndex = core.mNumUserSpheres + mNumSpheres; + if(sphereIndex >= 32) + { + Ps::getFoundation().error(PX_WARN, "Dropping collision sphere due to 32 sphere limit"); + return false; + } + + // current position here is before simulation + const PxSphereGeometry& geometry = static_cast<const PxSphereGeometry&>(shape->getCore().getGeometry()); + + PX_ALIGN(16, PxTransform globalPose); + shape->getAbsPoseAligned(&globalPose); + + PxTransform trafo = core.getGlobalPose().transformInv(globalPose); + PxVec3 center = trafo.p; + PxVec4 sphere(center, geometry.radius); + + core.getLowLevelCloth()->setSpheres(createRange<const PxVec4>(&sphere, 1), sphereIndex, sphereIndex); + + insertShapeSim(startIndex + mNumSpheres++, shape); + return true; +} + +void Sc::ClothSim::removeCollisionSphere(const ShapeSim* shape) +{ + ClothCore& core = getCore(); + + PxU32 startIndex = 0; + const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex; + for (PxU32 index = 0; index<mNumSpheres; ++index) + { + if (shapeIt[index] == shape) + { + mShapeSims.remove(startIndex + index); + --mNumSpheres; + PxU32 sphereIndex = core.mNumUserSpheres + index; + core.getLowLevelCloth()->setSpheres(cloth::Range<const PxVec4>(), sphereIndex, sphereIndex+1); + break; + } + } +} + +bool Sc::ClothSim::addCollisionCapsule( const ShapeSim* shape ) +{ + PxU32 startIndex = mNumSpheres; + +#if PX_DEBUG + const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex; + for (PxU32 index = 0; index<mNumCapsules; ++index) + PX_ASSERT(shapeIt[index] != shape); +#endif + + ClothCore& core = getCore(); + + PxU32 capsuleIndex = core.mNumUserCapsules + mNumCapsules; + if(capsuleIndex >= 32) + { + Ps::getFoundation().error(PX_WARN, "Dropping collision capsule due to 32 capsule limit"); + return false; + } + + PxU32 sphereIndex = core.mNumUserSpheres + mNumSpheres + 2*mNumCapsules; + if(sphereIndex >= 32) + { + Ps::getFoundation().error(PX_WARN, "Dropping collision capsule due to 32 sphere limit"); + return false; + } + + // current position here is before simulation + const PxCapsuleGeometry& geometry = static_cast<const PxCapsuleGeometry&>(shape->getCore().getGeometry()); + + PX_ALIGN(16, PxTransform globalPose); + shape->getAbsPoseAligned(&globalPose); + + PxTransform trafo = core.getGlobalPose().transformInv(globalPose); + PxVec3 center = trafo.p; + PxVec3 direction = trafo.q.rotate(PxVec3(geometry.halfHeight, 0, 0)); + PxReal radius = geometry.radius; + PxVec4 spheres[2] = { PxVec4(center-direction, radius), PxVec4(center+direction, radius) } ; + + core.getLowLevelCloth()->setSpheres(createRange<const PxVec4>(&spheres, 2), sphereIndex, sphereIndex); + PxU32 indices[2] = { sphereIndex, sphereIndex+1 }; + core.getLowLevelCloth()->setCapsules(createRange<PxU32>(indices, 2), capsuleIndex, capsuleIndex); + + insertShapeSim(startIndex + mNumCapsules++, shape); + return true; +} + +void Sc::ClothSim::removeCollisionCapsule( const ShapeSim* shape ) +{ + ClothCore& core = getCore(); + + PxU32 startIndex = mNumSpheres; + const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex; + for (PxU32 index = 0; index<mNumCapsules; ++index) + { + if (shapeIt[index] == shape) + { + mShapeSims.remove(startIndex + index); + --mNumCapsules; + PxU32 sphereIndex = core.mNumUserSpheres + mNumSpheres + 2*index; + core.getLowLevelCloth()->setSpheres(cloth::Range<const PxVec4>(), sphereIndex, sphereIndex+2); + // capsule is being removed automatically + break; + } + } +} + +bool Sc::ClothSim::addCollisionPlane( const ShapeSim* shape ) +{ + PxU32 startIndex = mNumSpheres + mNumCapsules; + +#if PX_DEBUG + const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex; + for (PxU32 index = 0; index<mNumPlanes; ++index) + PX_ASSERT(shapeIt[index] != shape); +#endif + + ClothCore& core = getCore(); + + PxU32 planeIndex = core.mNumUserPlanes + mNumPlanes; + if(planeIndex >= 32) + { + Ps::getFoundation().error(PX_WARN, "Dropping collision plane due to 32 plane limit"); + return false; + } + + // current position here is before simulation + PX_ALIGN(16, PxTransform globalPose); + shape->getAbsPoseAligned(&globalPose); + + PxTransform trafo = core.getGlobalPose().transformInv(globalPose); + PxPlane plane = PxPlaneEquationFromTransform(trafo); + + const PxVec4* data = reinterpret_cast<const PxVec4*>(&plane); + core.getLowLevelCloth()->setPlanes(createRange<const PxVec4>(data, 1), planeIndex, planeIndex); + PxU32 convexIndex = core.mNumUserConvexes + mNumPlanes; + PxU32 convexMask = PxU32(0x1 << planeIndex); + core.getLowLevelCloth()->setConvexes(createRange<const PxU32>(&convexMask, 1), convexIndex, convexIndex); + + insertShapeSim(startIndex + mNumPlanes++, shape); + return true; +} + +void Sc::ClothSim::removeCollisionPlane( const ShapeSim* shape ) +{ + ClothCore& core = getCore(); + + PxU32 startIndex = mNumSpheres + mNumCapsules; + const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex; + for (PxU32 index = 0; index<mNumPlanes; ++index) + { + if (shapeIt[index] == shape) + { + mShapeSims.remove(startIndex + index); + --mNumPlanes; + PxU32 planeIndex = core.mNumUserPlanes + index; + core.getLowLevelCloth()->setPlanes(cloth::Range<const PxVec4>(), planeIndex, planeIndex+1); + // convex is being removed automatically + break; + } + } +} + +bool Sc::ClothSim::addCollisionBox( const ShapeSim* shape ) +{ + PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes; + +#if PX_DEBUG + const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex; + for (PxU32 index = 0; index<mNumBoxes; ++index) + PX_ASSERT(shapeIt[index] != shape); +#endif + + ClothCore& core = getCore(); + + PxU32 planeIndex = core.mNumUserPlanes + mNumPlanes + 6*mNumBoxes; + if(planeIndex+6 > 32) + { + Ps::getFoundation().error(PX_WARN, "Dropping collision box due to 32 plane limit"); + return false; + } + + // current position here is before simulation + const PxBoxGeometry& geometry = static_cast<const PxBoxGeometry&>(shape->getCore().getGeometry()); + PX_ALIGN(16, PxTransform globalPose); + shape->getAbsPoseAligned(&globalPose); + PxTransform trafo = core.getGlobalPose().transformInv(globalPose); + PxVec3 halfExtents = geometry.halfExtents; + PxPlane planes[6] = { + trafo.transform(PxPlane(PxVec3( 1.f, 0, 0), -halfExtents.x)), + trafo.transform(PxPlane(PxVec3(-1.f, 0, 0), -halfExtents.x)), + trafo.transform(PxPlane(PxVec3( 0, 1.f, 0), -halfExtents.y)), + trafo.transform(PxPlane(PxVec3( 0, -1.f, 0), -halfExtents.y)), + trafo.transform(PxPlane(PxVec3( 0, 0, 1.f), -halfExtents.z)), + trafo.transform(PxPlane(PxVec3( 0, 0, -1.f), -halfExtents.z)), + }; + + core.getLowLevelCloth()->setPlanes(createRange<const PxVec4>(&planes, 6), planeIndex, planeIndex); + PxU32 convexIndex = core.mNumUserConvexes + mNumPlanes + mNumBoxes; + PxU32 convexMask = PxU32(0x3f << planeIndex); + core.getLowLevelCloth()->setConvexes(createRange<const PxU32>(&convexMask, 1), convexIndex, convexIndex); + + insertShapeSim(startIndex + mNumBoxes++, shape); + return true; +} + +void Sc::ClothSim::removeCollisionBox( const ShapeSim* shape ) +{ + ClothCore& core = getCore(); + + PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes; + const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex; + for (PxU32 index = 0; index<mNumBoxes; ++index) + { + if (shapeIt[index] == shape) + { + mShapeSims.remove(startIndex + index); + --mNumBoxes; + PxU32 planeIndex = core.mNumUserPlanes + mNumPlanes + 6*index; + core.getLowLevelCloth()->setPlanes(cloth::Range<const PxVec4>(), planeIndex, planeIndex+6); + // convex is being removed automatically + break; + } + } +} + +bool Sc::ClothSim::addCollisionConvex( const ShapeSim* shape ) +{ + PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes + mNumBoxes; + +#if PX_DEBUG + const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex; + for (PxU32 index = 0; index<mNumConvexes; ++index) + PX_ASSERT(shapeIt[index] != shape); +#endif + + ClothCore& core = getCore(); + + const PxConvexMeshGeometry& geometry = static_cast<const PxConvexMeshGeometry&>(shape->getCore().getGeometry()); + PxU32 numPlanes = geometry.convexMesh->getNbPolygons(); + + PxU32 planeIndex = core.mNumUserPlanes + mNumPlanes + 6*mNumBoxes + mNumConvexPlanes; + if(planeIndex+numPlanes > 32) + { + Ps::getFoundation().error(PX_WARN, "Dropping collision convex due to 32 plane limit"); + return false; + } + + // current position here is before simulation + PX_ALIGN(16, PxTransform globalPose); + shape->getAbsPoseAligned(&globalPose); + Cm::Matrix34 trafo = core.getGlobalPose().transformInv(globalPose) * geometry.scale; + Ps::Array<PxPlane> planes; + planes.reserve(numPlanes); + + for(PxU32 i=0; i<numPlanes; ++i) + { + PxHullPolygon polygon; + geometry.convexMesh->getPolygonData(i, polygon); + PxVec3 normal = trafo.rotate(reinterpret_cast<const PxVec3&>(polygon.mPlane)); + planes.pushBack(PxPlane(normal, polygon.mPlane[3] - trafo.p.dot(normal))); + } + + core.getLowLevelCloth()->setPlanes(createRange<const PxVec4>(planes.begin(), numPlanes), planeIndex, planeIndex); + PxU32 convexIndex = core.mNumUserConvexes + mNumPlanes + mNumBoxes + mNumConvexes; + PxU32 convexMask = PxU32(((1 << numPlanes) - 1) << planeIndex); + core.getLowLevelCloth()->setConvexes(createRange<const PxU32>(&convexMask, 1), convexIndex, convexIndex); + + mNumConvexPlanes += numPlanes; + insertShapeSim(startIndex + mNumConvexes++, shape); + return true; +} + +void Sc::ClothSim::removeCollisionConvex( const ShapeSim* shape ) +{ + ClothCore& core = getCore(); + + PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes + mNumBoxes; + const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex; + PxU32 planeIndex = core.mNumUserPlanes + mNumPlanes + 6*mNumBoxes; + for (PxU32 index = 0; index<mNumConvexes; ++index) + { + const PxConvexMeshGeometry& geometry = static_cast<const PxConvexMeshGeometry&>(shapeIt[index]->getCore().getGeometry()); + PxU32 numPlanes = geometry.convexMesh->getNbPolygons(); + if (shapeIt[index] == shape) + { + mShapeSims.remove(startIndex + index); + --mNumConvexes; + core.getLowLevelCloth()->setPlanes(cloth::Range<const PxVec4>(), planeIndex, planeIndex+numPlanes); + mNumConvexPlanes -= numPlanes; + // convex is being removed automatically + break; + } + planeIndex += numPlanes; + } +} + +namespace +{ + template <typename IndexT> + void gatherMeshVertices(const PxTriangleMesh& mesh, Ps::Array<PxVec3>& vertices, bool flipNormal) + { + PxU32 numTriangles = mesh.getNbTriangles(); + const IndexT* indices = reinterpret_cast<const IndexT*>(mesh.getTriangles()); + const PxVec3* meshVertices = mesh.getVertices(); + for(PxU32 i=0; i<numTriangles; ++i) + { + const PxI32 winding = flipNormal ? 1 : 0; + vertices.pushBack(meshVertices[indices[i*3+0]]); + vertices.pushBack(meshVertices[indices[i*3+1 + winding]]); + vertices.pushBack(meshVertices[indices[i*3+2 - winding]]); + } + } + + void offsetTriangles(PxVec3* it, PxVec3* end, PxReal offset) + { + for(; it < end; it += 3) + { + PxVec3 v0 = it[0]; + PxVec3 v1 = it[1]; + PxVec3 v2 = it[2]; + + PxVec3 n = (v1-v0).cross(v2-v0).getNormalized() * offset; + + it[0] = v0 + n; + it[1] = v1 + n; + it[2] = v2 + n; + } + } + + void transform(const Cm::Matrix34& trafo, PxVec3* first, PxVec3* last) + { + for(; first < last; ++first) + *first = trafo.transform(*first); + } +} + +bool Sc::ClothSim::addCollisionMesh( const ShapeSim* shape ) +{ + PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes + mNumBoxes + mNumConvexes; + +#if PX_DEBUG + const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex; + for (PxU32 index = 0; index<mNumMeshes; ++index) + PX_ASSERT(shapeIt[index] != shape); +#endif + + ClothCore& core = getCore(); + + // current position here is before simulation + const PxTriangleMeshGeometry& geometry = static_cast<const PxTriangleMeshGeometry&>(shape->getCore().getGeometry()); + PX_ALIGN(16, PxTransform globalPose); + shape->getAbsPoseAligned(&globalPose); + Cm::Matrix34 trafo = core.getGlobalPose().transformInv(globalPose) * geometry.scale; + insertShapeSim(startIndex + mNumMeshes++, shape); + mStartShapeTrafos.pushBack(trafo); + return true; +} + +void Sc::ClothSim::removeCollisionMesh( const ShapeSim* shape ) +{ + PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes + mNumBoxes + mNumConvexes; + const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex; + for (PxU32 index = 0; index<mNumMeshes; ++index) + { + if (shapeIt[index] == shape) + { + mShapeSims.remove(startIndex + index); + mStartShapeTrafos.remove(index); + --mNumMeshes; + break; + } + } +} + +namespace +{ + void gatherHeightfieldSamples(const PxHeightField& hf, Ps::Array<PxVec3>& vertices, Ps::Array<PxHeightFieldSample>& samples) + { + const PxU32 numCols = hf.getNbColumns(); + const PxU32 numRows = hf.getNbRows(); + const PxU32 numVertices = numRows * numCols; + + samples.resize(numVertices); + hf.saveCells(samples.begin(), numVertices * sizeof(PxHeightFieldSample)); + + vertices.reserve(numVertices); + for(PxU32 i = 0; i < numRows; ++i) + { + for(PxU32 j = 0; j < numCols; ++j) + { + vertices.pushBack(PxVec3(PxReal(i), PxReal(samples[j + (i*numCols)].height), PxReal(j))); + } + } + } + + void tessellateHeightfield(const PxHeightField& hf, const PxVec3* vertices, + const PxHeightFieldSample* samples, Ps::Array<PxVec3>& triangles) + { + const PxU32 numCols = hf.getNbColumns(); + const PxU32 numRows = hf.getNbRows(); + const PxU32 numTriangles = (numRows-1) * (numCols-1) * 2; + + triangles.reserve(triangles.size() + numTriangles*3); + for(PxU32 i = 0; i < (numCols - 1); ++i) + { + for(PxU32 j = 0; j < (numRows - 1); ++j) + { + PxU8 tessFlag = samples[i+j*numCols].tessFlag(); + + // i2--i3 + // | | + // i0--i1 + PxU32 i0 = i * numRows + j; + PxU32 i1 = i * numRows + j + 1; + PxU32 i2 = (i+1) * numRows + j; + PxU32 i3 = (i+1) * numRows + j+1; + + // this is really a corner vertex index, not triangle index + PxU32 mat0 = hf.getTriangleMaterialIndex((j*numCols+i)*2); + if(mat0 != PxHeightFieldMaterial::eHOLE) + { + triangles.pushBack(vertices[i2]); + triangles.pushBack(vertices[i0]); + triangles.pushBack(vertices[tessFlag ? i3 : i1]); + } + + PxU32 mat1 = hf.getTriangleMaterialIndex((j*numCols+i)*2+1); + if(mat1 != PxHeightFieldMaterial::eHOLE) + { + triangles.pushBack(vertices[i1]); + triangles.pushBack(vertices[i3]); + triangles.pushBack(vertices[tessFlag ? i0 : i2]); + } + + // we don't handle holes yet (number of triangles < expected) + PX_ASSERT(mat0 != PxHeightFieldMaterial::eHOLE); + PX_ASSERT(mat1 != PxHeightFieldMaterial::eHOLE); + } + } + } +} + + +bool Sc::ClothSim::addCollisionHeightfield( const ShapeSim* shape ) +{ + PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes + mNumBoxes + mNumConvexes + mNumMeshes; + +#if PX_DEBUG + const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex; + for (PxU32 index = 0; index<mNumHeightfields; ++index) + PX_ASSERT(shapeIt[index] != shape); +#endif + + ClothCore& core = getCore(); + + // current position here is before simulation + const PxHeightFieldGeometry& geometry = static_cast<const PxHeightFieldGeometry&>(shape->getCore().getGeometry()); + PX_ALIGN(16, PxTransform globalPose); + shape->getAbsPoseAligned(&globalPose); + Cm::Matrix34 trafo(core.getGlobalPose().transformInv(globalPose)); + + trafo.m.column0 *= geometry.rowScale; + trafo.m.column1 *= geometry.heightScale; + trafo.m.column2 *= geometry.columnScale; + + insertShapeSim(startIndex + mNumHeightfields++, shape); + mStartShapeTrafos.pushBack(trafo); + return true; +} + +void Sc::ClothSim::removeCollisionHeightfield( const ShapeSim* shape ) +{ + PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes + mNumBoxes + mNumConvexes + mNumMeshes; + const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex; + for (PxU32 index = 0; index<mNumHeightfields; ++index) + { + if (shapeIt[index] == shape) + { + mShapeSims.remove(startIndex + index); + mStartShapeTrafos.remove(mNumMeshes + index); + --mNumHeightfields; + break; + } + } +} + +void Sc::ClothSim::updateRigidBodyPositions() +{ + ClothCore& core = getCore(); + + if(!(core.getClothFlags() & PxClothFlag::eSCENE_COLLISION)) + { + PX_ASSERT(0 == mNumSpheres + mNumCapsules + mNumPlanes + + mNumBoxes + mNumConvexes + mNumMeshes + mNumHeightfields); + return; + } + + PxReal restOffset = core.getRestOffset(); + + const ShapeSim* const* shapeIt = mShapeSims.begin(); + + Ps::Array<PxVec4> spheres; + for (PxU32 i=0; i<mNumSpheres; ++i, ++shapeIt) + { + // current position here is after simulation + const ShapeSim* shape = *shapeIt; + const PxSphereGeometry& geometry = static_cast<const PxSphereGeometry&>(shape->getCore().getGeometry()); + PX_ALIGN(16, PxTransform globalPose); + shape->getAbsPoseAligned(&globalPose); + PxVec3 p = core.getGlobalPose().transformInv(globalPose.p); + spheres.pushBack(PxVec4(p, geometry.radius + restOffset)); + } + + for (PxU32 i=0; i<mNumCapsules; ++i, ++shapeIt) + { + const ShapeSim* shape = *shapeIt; + const PxCapsuleGeometry& geometry = static_cast<const PxCapsuleGeometry&>(shape->getCore().getGeometry()); + PX_ALIGN(16, PxTransform globalPose); + shape->getAbsPoseAligned(&globalPose); + PxTransform trafo = core.getGlobalPose().transformInv(globalPose); + PxVec3 center = trafo.p; + PxVec3 direction = trafo.q.rotate(PxVec3(geometry.halfHeight, 0, 0)); + PxReal radius = geometry.radius + restOffset; + spheres.pushBack(PxVec4(center-direction, radius)); + spheres.pushBack(PxVec4(center+direction, radius)); + } + + PxU32 sphereIndex = core.mNumUserSpheres, numSpheres = spheres.size(); + core.getLowLevelCloth()->setSpheres(createRange<const PxVec4>(spheres.begin(), numSpheres), sphereIndex, sphereIndex+numSpheres); + + Ps::Array<PxPlane> planes; + for (PxU32 i = 0; i<mNumPlanes; ++i, ++shapeIt) + { + const ShapeSim* shape = *shapeIt; + PX_ALIGN(16, PxTransform globalPose); + shape->getAbsPoseAligned(&globalPose); + PxTransform trafo = core.getGlobalPose().transformInv(globalPose); + PxPlane plane = PxPlaneEquationFromTransform(trafo); + plane.d -= restOffset; + planes.pushBack(plane); + } + + for (PxU32 i = 0; i<mNumBoxes; ++i, ++shapeIt) + { + const ShapeSim* shape = *shapeIt; + const PxBoxGeometry& geometry = static_cast<const PxBoxGeometry&>(shape->getCore().getGeometry()); + PX_ALIGN(16, PxTransform globalPose); + shape->getAbsPoseAligned(&globalPose); + PxTransform trafo = core.getGlobalPose().transformInv(globalPose); + PxVec3 halfExtents = geometry.halfExtents + PxVec3(restOffset); + planes.pushBack(trafo.transform(PxPlane(PxVec3( 1.f, 0, 0), -halfExtents.x))); + planes.pushBack(trafo.transform(PxPlane(PxVec3(-1.f, 0, 0), -halfExtents.x))); + planes.pushBack(trafo.transform(PxPlane(PxVec3( 0, 1.f, 0), -halfExtents.y))); + planes.pushBack(trafo.transform(PxPlane(PxVec3( 0, -1.f, 0), -halfExtents.y))); + planes.pushBack(trafo.transform(PxPlane(PxVec3( 0, 0, 1.f), -halfExtents.z))); + planes.pushBack(trafo.transform(PxPlane(PxVec3( 0, 0, -1.f), -halfExtents.z))); + } + + for (PxU32 j= 0; j<mNumConvexes; ++j, ++shapeIt) + { + const ShapeSim* shape = *shapeIt; + const PxConvexMeshGeometry& geometry = static_cast<const PxConvexMeshGeometry&>(shape->getCore().getGeometry()); + PX_ALIGN(16, PxTransform globalPose); + shape->getAbsPoseAligned(&globalPose); + Cm::Matrix34 trafo = core.getGlobalPose().transformInv(globalPose) * geometry.scale; + PxU32 numPlanes = geometry.convexMesh->getNbPolygons(); + for(PxU32 i=0; i<numPlanes; ++i) + { + PxHullPolygon polygon; + geometry.convexMesh->getPolygonData(i, polygon); + PxVec3 normal = trafo.rotate(reinterpret_cast<const PxVec3&>(polygon.mPlane)); + planes.pushBack(PxPlane(normal, polygon.mPlane[3] - trafo.p.dot(normal) - restOffset)); + } + } + + PxU32 planeIndex = core.mNumUserPlanes, numPlanes = planes.size(); + core.getLowLevelCloth()->setPlanes(createRange<const PxVec4>(planes.begin(), numPlanes), planeIndex, planeIndex+numPlanes); + + Ps::Array<PxVec3> curTriangles, prevTriangles; + for (PxU32 i = 0; i<mNumMeshes; ++i, ++shapeIt) + { + const ShapeSim* shape = *shapeIt; + const PxTriangleMeshGeometry& geometry = static_cast<const PxTriangleMeshGeometry&>(shape->getCore().getGeometry()); + PxTransform clothPose = core.getGlobalPose(); + PX_ALIGN(16, PxTransform meshPose); + shape->getAbsPoseAligned(&meshPose); + Cm::Matrix34 trafo = clothPose.transformInv(meshPose) * geometry.scale; + + PxU32 start = curTriangles.size(); + if(geometry.triangleMesh->getTriangleMeshFlags() & PxTriangleMeshFlag::e16_BIT_INDICES) + gatherMeshVertices<PxU16>(*geometry.triangleMesh, curTriangles, geometry.scale.hasNegativeDeterminant()); + else + gatherMeshVertices<PxU32>(*geometry.triangleMesh, curTriangles, geometry.scale.hasNegativeDeterminant()); + + Cm::Matrix34 startTrafo = mStartShapeTrafos[i]; + mStartShapeTrafos[i] = trafo; + for(PxU32 j=start, n=curTriangles.size(); j<n; ++j) + prevTriangles.pushBack(startTrafo.transform(curTriangles[j])); + + transform(trafo, curTriangles.begin() + start, curTriangles.end()); + } + + Ps::Array<PxVec3> vertices; + Ps::Array<PxHeightFieldSample> samples; + for (PxU32 i = 0; i<mNumHeightfields; ++i, ++shapeIt) + { + const ShapeSim* shape = *shapeIt; + const PxHeightFieldGeometry& geometry = static_cast<const PxHeightFieldGeometry&>(shape->getCore().getGeometry()); + PxTransform clothPose = core.getGlobalPose(); + PX_ALIGN(16, PxTransform heightfieldPose); + shape->getAbsPoseAligned(&heightfieldPose); + Cm::Matrix34 trafo = Cm::Matrix34(clothPose.transformInv(heightfieldPose)); + + trafo.m.column0 *= geometry.rowScale; + trafo.m.column1 *= geometry.heightScale; + trafo.m.column2 *= geometry.columnScale; + + gatherHeightfieldSamples(*geometry.heightField, vertices, samples); + + PxU32 start = curTriangles.size(); + tessellateHeightfield(*geometry.heightField, vertices.begin(), samples.begin(), curTriangles); + + Cm::Matrix34 startTrafo = mStartShapeTrafos[mNumMeshes + i]; + mStartShapeTrafos[mNumMeshes + i] = trafo; + for(PxU32 j=start, n=curTriangles.size(); j<n; ++j) + prevTriangles.pushBack(startTrafo.transform(curTriangles[j])); + + transform(trafo, curTriangles.begin() + start, curTriangles.end()); + + vertices.resize(0); + samples.resize(0); + } + + // cull triangles that don't intersect the cloth bounding box + PxVec3 bboxCenter = core.getLowLevelCloth()->getBoundingBoxCenter(); + PxVec3 bboxScale = core.getLowLevelCloth()->getBoundingBoxScale() + PxVec3(core.getContactOffset()); + PxU32 trianglesSize = curTriangles.size(), numVertices = 0; + for(PxU32 i=0; i<trianglesSize; i+=3) + { + // PT: TODO: change the code so that we can safely call the (faster) intersectTriangleBox() function + if (Gu::intersectTriangleBox_ReferenceCode(bboxCenter, bboxScale, curTriangles[i], curTriangles[i+1], curTriangles[i+2]) || + Gu::intersectTriangleBox_ReferenceCode(bboxCenter, bboxScale, prevTriangles[i], prevTriangles[i+1], prevTriangles[i+2])) + { + curTriangles[numVertices+0] = curTriangles[i+0]; + curTriangles[numVertices+1] = curTriangles[i+1]; + curTriangles[numVertices+2] = curTriangles[i+2]; + + prevTriangles[numVertices+0] = prevTriangles[i+0]; + prevTriangles[numVertices+1] = prevTriangles[i+1]; + prevTriangles[numVertices+2] = prevTriangles[i+2]; + + numVertices += 3; + } + } + + cloth::Range<PxVec3> prevRange(prevTriangles.begin(), prevTriangles.begin() + numVertices); + cloth::Range<PxVec3> curRange(curTriangles.begin(), curTriangles.begin() + numVertices); + + offsetTriangles(prevRange.begin(), prevRange.end(), restOffset); + offsetTriangles(curRange.begin(), curRange.end(), restOffset); + + core.getLowLevelCloth()->setTriangles(prevRange, curRange, core.mNumUserTriangles); + + PX_ASSERT(shapeIt == mShapeSims.end()); +} + +void Sc::ClothSim::clearCollisionShapes() +{ + ClothCore& core = getCore(); + cloth::Cloth* lowLevelCloth = core.getLowLevelCloth(); + + lowLevelCloth->setSpheres(cloth::Range<const PxVec4>(), core.mNumUserSpheres, lowLevelCloth->getNumSpheres()); + lowLevelCloth->setPlanes(cloth::Range<const PxVec4>(), core.mNumUserPlanes, lowLevelCloth->getNumPlanes()); + lowLevelCloth->setTriangles(cloth::Range<const PxVec3>(), core.mNumUserTriangles, lowLevelCloth->getNumTriangles()); + + mNumSpheres = 0; + mNumCapsules = 0; + mNumPlanes = 0; + mNumBoxes = 0; + mNumConvexes = 0; + mNumMeshes = 0; + mNumHeightfields = 0; + mNumConvexPlanes = 0; + + NPhaseCore* narrowPhase = getScene().getNPhaseCore(); + for(PxU32 i=0, n=mShapeSims.size(); i<n; ++i) + narrowPhase->removeClothOverlap(this, mShapeSims[i]); + + mShapeSims.resize(0); +} + +void physx::Sc::ClothSim::insertShapeSim( PxU32 index, const ShapeSim* shapeSim) +{ + mShapeSims.pushBack(0); + + for(PxU32 i = mShapeSims.size(); --i > index; ) + mShapeSims[i] = mShapeSims[i-1]; + + mShapeSims[index] = shapeSim; +} + +#endif // PX_USE_CLOTH_API diff --git a/PhysX_3.4/Source/SimulationController/src/cloth/ScClothSim.h b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothSim.h new file mode 100644 index 00000000..aa4cae21 --- /dev/null +++ b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothSim.h @@ -0,0 +1,123 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved. +// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. +// Copyright (c) 2001-2004 NovodeX AG. All rights reserved. + + +#ifndef PX_PHYSICS_SCP_CLOTH_SIM +#define PX_PHYSICS_SCP_CLOTH_SIM + +#include "CmPhysXCommon.h" +#include "PxPhysXConfig.h" +#if PX_USE_CLOTH_API + +#include "CmMatrix34.h" +#include "ScClothShape.h" + +namespace physx +{ + +#if PX_SUPPORT_GPU_PHYSX + struct PxClothCollisionSphere; +#endif + +namespace Sc +{ + class ClothCore; + class ShapeSim; + + class ClothSim : public ActorSim + { + public: + + ClothSim(Scene&, ClothCore&); + ~ClothSim(); + + //--------------------------------------------------------------------------------- + // Actor implementation + //--------------------------------------------------------------------------------- + public: + ClothCore& getCore() const; + + void updateBounds(); + void startStep(); + void reinsert(); + + bool addCollisionShape(const ShapeSim* shape); + void removeCollisionShape(const ShapeSim* shape); + + bool addCollisionSphere(const ShapeSim* shape); + void removeCollisionSphere(const ShapeSim* shape); + + bool addCollisionCapsule(const ShapeSim* shape); + void removeCollisionCapsule(const ShapeSim* shape); + + bool addCollisionPlane(const ShapeSim* shape); + void removeCollisionPlane(const ShapeSim* shape); + + bool addCollisionBox(const ShapeSim* shape); + void removeCollisionBox(const ShapeSim* shape); + + bool addCollisionConvex(const ShapeSim* shape); + void removeCollisionConvex(const ShapeSim* shape); + + bool addCollisionMesh(const ShapeSim* shape); + void removeCollisionMesh(const ShapeSim* shape); + + bool addCollisionHeightfield(const ShapeSim* shape); + void removeCollisionHeightfield(const ShapeSim* shape); + + void updateRigidBodyPositions(); + void clearCollisionShapes(); + + private: + void insertShapeSim(PxU32, const ShapeSim*); + ClothSim &operator=(const ClothSim &); + + private: + ClothShape mClothShape; + + PxU32 mNumSpheres; + PxU32 mNumCapsules; + PxU32 mNumPlanes; + PxU32 mNumBoxes; + PxU32 mNumConvexes; + PxU32 mNumMeshes; + PxU32 mNumHeightfields; + PxU32 mNumConvexPlanes; + + shdfnd::Array<const ShapeSim*> mShapeSims; + shdfnd::Array<Cm::Matrix34> mStartShapeTrafos; + + }; + +} // namespace Sc +} + +#endif // PX_PHYSICS_SCP_CLOTH_SIM + +#endif |