// 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-2020 NVIDIA Corporation. All rights reserved. // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. // Copyright (c) 2001-2004 NovodeX AG. All rights reserved. #pragma once #include "NvCloth/Cloth.h" #include "NvCloth/Fabric.h" #include #include #include "IndexPair.h" #include "MovingAverage.h" #include "NvCloth/ps/PsMathUtils.h" #include namespace nv { namespace cloth { template class ClothTraits { }; // SwCloth or CuCloth aggregate implementing the Cloth interface // Member specializations are implemented in Sw/CuCloth.cpp template class ClothImpl : public Cloth { ClothImpl(const ClothImpl&); public: ClothImpl() {} typedef T ClothType; typedef typename ClothTraits::FactoryType FactoryType; typedef typename ClothTraits::FabricType FabricType; typedef typename ClothTraits::ContextLockType ContextLockType; ClothImpl& operator = (const ClothImpl&); ClothType* getChildCloth() { return static_cast(this); } ClothType const* getChildCloth() const { return static_cast(this); } virtual Fabric& getFabric() const; virtual Factory& getFactory() const; virtual void setTranslation(const physx::PxVec3& trans); virtual void setRotation(const physx::PxQuat& rot); virtual const physx::PxVec3& getTranslation() const; virtual const physx::PxQuat& getRotation() const; virtual void clearInertia(); virtual void teleport(const physx::PxVec3& delta); virtual void teleportToLocation(const physx::PxVec3& translation, const physx::PxQuat& rotation); virtual void ignoreVelocityDiscontinuity(); virtual float getPreviousIterationDt() const; virtual void setGravity(const physx::PxVec3& gravity); virtual physx::PxVec3 getGravity() const; virtual void setDamping(const physx::PxVec3& damping); virtual physx::PxVec3 getDamping() const; virtual void setLinearDrag(const physx::PxVec3& drag); virtual physx::PxVec3 getLinearDrag() const; virtual void setAngularDrag(const physx::PxVec3& drag); virtual physx::PxVec3 getAngularDrag() const; virtual void setLinearInertia(const physx::PxVec3& inertia); virtual physx::PxVec3 getLinearInertia() const; virtual void setAngularInertia(const physx::PxVec3& inertia); virtual physx::PxVec3 getAngularInertia() const; virtual void setCentrifugalInertia(const physx::PxVec3& inertia); virtual physx::PxVec3 getCentrifugalInertia() const; virtual void setSolverFrequency(float frequency); virtual float getSolverFrequency() const; virtual void setStiffnessFrequency(float frequency); virtual float getStiffnessFrequency() const; virtual void setAcceleationFilterWidth(uint32_t); virtual uint32_t getAccelerationFilterWidth() const; virtual void setSpheres(Range, uint32_t first, uint32_t last); virtual void setSpheres(Range startSpheres, Range targetSpheres); virtual uint32_t getNumSpheres() const; virtual void setCapsules(Range, uint32_t first, uint32_t last); virtual uint32_t getNumCapsules() const; virtual void setPlanes(Range, uint32_t first, uint32_t last); virtual void setPlanes(Range startPlanes, Range targetPlanes); virtual uint32_t getNumPlanes() const; virtual void setConvexes(Range, uint32_t first, uint32_t last); virtual uint32_t getNumConvexes() const; virtual void setTriangles(Range, uint32_t first, uint32_t last); virtual void setTriangles(Range, Range, uint32_t first); virtual uint32_t getNumTriangles() const; virtual bool isContinuousCollisionEnabled() const; virtual void enableContinuousCollision(bool); virtual float getCollisionMassScale() const; virtual void setCollisionMassScale(float); virtual void setFriction(float friction); virtual float getFriction() const; virtual uint32_t getNumVirtualParticleWeights() const; virtual void setTetherConstraintScale(float scale); virtual float getTetherConstraintScale() const; virtual void setTetherConstraintStiffness(float stiffness); virtual float getTetherConstraintStiffness() const; virtual Range getMotionConstraints(); virtual void clearMotionConstraints(); virtual uint32_t getNumMotionConstraints() const; virtual void setMotionConstraintScaleBias(float scale, float bias); virtual float getMotionConstraintScale() const; virtual float getMotionConstraintBias() const; virtual void setMotionConstraintStiffness(float stiffness); virtual float getMotionConstraintStiffness() const; virtual Range getSeparationConstraints(); virtual void clearSeparationConstraints(); virtual uint32_t getNumSeparationConstraints() const; virtual void clearInterpolation(); virtual uint32_t getNumParticleAccelerations() const; virtual void setWindVelocity(physx::PxVec3); virtual physx::PxVec3 getWindVelocity() const; virtual void setDragCoefficient(float); virtual float getDragCoefficient() const; virtual void setLiftCoefficient(float); virtual float getLiftCoefficient() const; virtual void setFluidDensity(float); virtual float getFluidDensity() const; virtual void setSelfCollisionDistance(float); virtual float getSelfCollisionDistance() const; virtual void setSelfCollisionStiffness(float); virtual float getSelfCollisionStiffness() const; virtual uint32_t getNumSelfCollisionIndices() const; virtual void setRestPositions(Range); virtual uint32_t getNumRestPositions() const; virtual const physx::PxVec3& getBoundingBoxCenter() const; virtual const physx::PxVec3& getBoundingBoxScale() const; virtual void setSleepThreshold(float); virtual float getSleepThreshold() const; virtual void setSleepTestInterval(uint32_t); virtual uint32_t getSleepTestInterval() const; virtual void setSleepAfterCount(uint32_t); virtual uint32_t getSleepAfterCount() const; virtual uint32_t getSleepPassCount() const; virtual bool isAsleep() const; virtual void putToSleep(); virtual bool isSleeping() const; virtual void wakeUp(); virtual void setUserData(void*); virtual void* getUserData() const; // helper function template MappedRange getMappedParticles(U* data) const; public: //Fields shared between all cloth classes physx::PxVec3 mParticleBoundsCenter; physx::PxVec3 mParticleBoundsHalfExtent; physx::PxVec3 mGravity; physx::PxVec3 mLogDamping; physx::PxVec3 mLinearLogDrag; physx::PxVec3 mAngularLogDrag; physx::PxVec3 mLinearInertia; physx::PxVec3 mAngularInertia; physx::PxVec3 mCentrifugalInertia; float mSolverFrequency; float mStiffnessFrequency; physx::PxTransform mTargetMotion; physx::PxTransform mCurrentMotion; physx::PxVec3 mLinearVelocity; physx::PxVec3 mAngularVelocity; bool mIgnoreVelocityDiscontinuityNextFrame; float mPrevIterDt; MovingAverage mIterDtAvg; // wind physx::PxVec3 mWind; float mDragLogCoefficient; float mLiftLogCoefficient; float mFluidDensity; // sleeping uint32_t mSleepTestInterval; // how often to test for movement uint32_t mSleepAfterCount; // number of tests to pass before sleep float mSleepThreshold; // max movement delta to pass test uint32_t mSleepPassCounter; // how many tests passed uint32_t mSleepTestCounter; // how many iterations since tested }; template inline Fabric& ClothImpl::getFabric() const { return getChildCloth()->mFabric; } template inline Factory& ClothImpl::getFactory() const { return getChildCloth()->mFactory; } template inline void ClothImpl::setTranslation(const physx::PxVec3& trans) { physx::PxVec3 t = reinterpret_cast(trans); if (t == mTargetMotion.p) return; mTargetMotion.p = t; wakeUp(); } template inline void ClothImpl::setRotation(const physx::PxQuat& q) { if ((q - mTargetMotion.q).magnitudeSquared() == 0.0f) return; mTargetMotion.q = q; wakeUp(); } template inline const physx::PxVec3& ClothImpl::getTranslation() const { return mTargetMotion.p; } template inline const physx::PxQuat& ClothImpl::getRotation() const { return mTargetMotion.q; } template inline void ClothImpl::clearInertia() { mCurrentMotion = mTargetMotion; mLinearVelocity = physx::PxVec3(0.0); mAngularVelocity = physx::PxVec3(0.0); wakeUp(); } // Fixed 4505:local function has been removed template inline void ClothImpl::teleport(const physx::PxVec3& delta) { mCurrentMotion.p += delta; mTargetMotion.p += delta; } template inline void ClothImpl::teleportToLocation(const physx::PxVec3& translation, const physx::PxQuat& rotation) { mCurrentMotion.p = translation; mCurrentMotion.q = rotation; mTargetMotion.p = translation; mTargetMotion.q = rotation; } template inline void ClothImpl::ignoreVelocityDiscontinuity() { mIgnoreVelocityDiscontinuityNextFrame = true; } template inline float ClothImpl::getPreviousIterationDt() const { return mPrevIterDt; } template inline void ClothImpl::setGravity(const physx::PxVec3& gravity) { physx::PxVec3 value = gravity; if (value == mGravity) return; mGravity = value; wakeUp(); } template inline physx::PxVec3 ClothImpl::getGravity() const { return mGravity; } inline float safeLog2(float x) { NV_CLOTH_ASSERT_WITH_MESSAGE("safeLog2",x >= 0.0f); return x > 0 ? ps::log2(x) : -FLT_MAX_EXP; } inline physx::PxVec3 safeLog2(const physx::PxVec3& v) { return physx::PxVec3( safeLog2(v.x), safeLog2(v.y), safeLog2(v.z) ); } inline float safeExp2(float x) { if (x <= -FLT_MAX_EXP) return 0.0f; else return ps::exp2(x); } inline physx::PxVec3 safeExp2(const physx::PxVec3& v) { return physx::PxVec3( safeExp2(v.x), safeExp2(v.y), safeExp2(v.z) ); } template inline void ClothImpl::setDamping(const physx::PxVec3& damping) { physx::PxVec3 value = safeLog2(physx::PxVec3(1.f) - damping); if (value == mLogDamping) return; mLogDamping = value; wakeUp(); } template inline physx::PxVec3 ClothImpl::getDamping() const { return physx::PxVec3(1.f) - safeExp2(mLogDamping); } template inline void ClothImpl::setLinearDrag(const physx::PxVec3& drag) { physx::PxVec3 value = safeLog2(physx::PxVec3(1.f) - drag); if (value == mLinearLogDrag) return; mLinearLogDrag = value; wakeUp(); } template inline physx::PxVec3 ClothImpl::getLinearDrag() const { return physx::PxVec3(1.f) - safeExp2(mLinearLogDrag); } template inline void ClothImpl::setAngularDrag(const physx::PxVec3& drag) { physx::PxVec3 value = safeLog2(physx::PxVec3(1.f) - drag); if (value == mAngularLogDrag) return; mAngularLogDrag = value; wakeUp(); } template inline physx::PxVec3 ClothImpl::getAngularDrag() const { return physx::PxVec3(1.f) - safeExp2(mAngularLogDrag); } template inline void ClothImpl::setLinearInertia(const physx::PxVec3& inertia) { physx::PxVec3 value = inertia; if (value == mLinearInertia) return; mLinearInertia = value; wakeUp(); } template inline physx::PxVec3 ClothImpl::getLinearInertia() const { return mLinearInertia; } template inline void ClothImpl::setAngularInertia(const physx::PxVec3& inertia) { physx::PxVec3 value = inertia; if (value == mAngularInertia) return; mAngularInertia = value; wakeUp(); } template inline physx::PxVec3 ClothImpl::getAngularInertia() const { return mAngularInertia; } template inline void ClothImpl::setCentrifugalInertia(const physx::PxVec3& inertia) { physx::PxVec3 value = inertia; if (value == mCentrifugalInertia) return; mCentrifugalInertia = value; wakeUp(); } template inline physx::PxVec3 ClothImpl::getCentrifugalInertia() const { return mCentrifugalInertia; } template inline void ClothImpl::setSolverFrequency(float frequency) { if (frequency == mSolverFrequency) return; mSolverFrequency = frequency; getChildCloth()->mClothCostDirty = true; mIterDtAvg.reset(); wakeUp(); } template inline float ClothImpl::getSolverFrequency() const { return mSolverFrequency; } template inline void ClothImpl::setStiffnessFrequency(float frequency) { if (frequency == mStiffnessFrequency) return; mStiffnessFrequency = frequency; wakeUp(); } template inline float ClothImpl::getStiffnessFrequency() const { return mStiffnessFrequency; } template inline void ClothImpl::setAcceleationFilterWidth(uint32_t n) { mIterDtAvg.resize(n); } template inline uint32_t ClothImpl::getAccelerationFilterWidth() const { return mIterDtAvg.size(); } // move a subarray template void move(Iter it, uint32_t first, uint32_t last, uint32_t result) { if (result > first) { result += last - first; while (first < last) it[--result] = it[--last]; } else { while (first < last) it[result++] = it[first++]; } } // update capsule index inline bool updateIndex(uint32_t& index, uint32_t first, int32_t delta) { return index >= first && int32_t(index += delta) < int32_t(first); } template inline void ClothImpl::setSpheres(Range spheres, uint32_t first, uint32_t last) { uint32_t oldSize = uint32_t(getChildCloth()->mStartCollisionSpheres.size()); uint32_t newSize = uint32_t(spheres.size()) + oldSize - last + first; NV_CLOTH_ASSERT(newSize <= 32); NV_CLOTH_ASSERT(first <= oldSize); NV_CLOTH_ASSERT(last <= oldSize); #if PX_DEBUG for (const physx::PxVec4* it = spheres.begin(); it < spheres.end(); ++it) NV_CLOTH_ASSERT(it->w >= 0.0f); #endif if (!oldSize && !newSize) return; if (!oldSize) { ContextLockType contextLock(getChildCloth()->mFactory); getChildCloth()->mStartCollisionSpheres.assign(spheres.begin(), spheres.end()); getChildCloth()->notifyChanged(); } else { if (std::max(oldSize, newSize) > std::min(getChildCloth()->mStartCollisionSpheres.capacity(), getChildCloth()->mTargetCollisionSpheres.capacity())) { ContextLockType contextLock(getChildCloth()->mFactory); getChildCloth()->mStartCollisionSpheres.reserve(newSize); getChildCloth()->mTargetCollisionSpheres.reserve(std::max(oldSize, newSize)); } typename T::MappedVec4fVectorType start = getChildCloth()->mStartCollisionSpheres; typename T::MappedVec4fVectorType target = getChildCloth()->mTargetCollisionSpheres; // fill target from start for (uint32_t i = uint32_t(target.size()); i < oldSize; ++i) target.pushBack(start[i]); // resize to larger of oldSize and newSize start.resize(std::max(oldSize, newSize), physx::PxVec4(0.0f)); target.resize(std::max(oldSize, newSize), physx::PxVec4(0.0f)); if (int32_t delta = int32_t(newSize - oldSize)) { // move past-range elements to new place move(start.begin(), last, oldSize, last + delta); move(target.begin(), last, oldSize, last + delta); // fill new elements from spheres for (uint32_t i = last; i < last + delta; ++i) start[i] = spheres[i - first]; // adjust capsule indices typename T::MappedIndexVectorType indices = getChildCloth()->mCapsuleIndices; Vector::Type::Iterator cIt, cEnd = indices.end(); for (cIt = indices.begin(); cIt != cEnd;) { bool removed = false; removed |= updateIndex(cIt->first, last + std::min(0, delta), int32_t(delta)); removed |= updateIndex(cIt->second, last + std::min(0, delta), int32_t(delta)); if (!removed) ++cIt; else { indices.replaceWithLast(cIt); cEnd = indices.end(); } } start.resize(newSize); target.resize(newSize); getChildCloth()->notifyChanged(); } // fill target elements with spheres for (uint32_t i = 0; i < spheres.size(); ++i) target[first + i] = spheres[i]; } getChildCloth()->wakeUp(); } template inline void ClothImpl::setSpheres(Range startSpheres, Range targetSpheres) { NV_CLOTH_ASSERT(startSpheres.size() == targetSpheres.size()); //Clamp ranges to the first 32 spheres startSpheres = Range(startSpheres.begin(), std::min(startSpheres.end(), startSpheres.begin() + 32)); targetSpheres = Range(targetSpheres.begin(), std::min(targetSpheres.end(), targetSpheres.begin() + 32)); uint32_t oldSize = uint32_t(getChildCloth()->mStartCollisionSpheres.size()); uint32_t newSize = uint32_t(startSpheres.size()); if(newSize > std::min(getChildCloth()->mStartCollisionSpheres.capacity(), getChildCloth()->mTargetCollisionSpheres.capacity())) { //context lock only if we are growing the array ContextLockType contextLock(getChildCloth()->mFactory); getChildCloth()->mStartCollisionSpheres.assign(startSpheres.begin(), startSpheres.end()); getChildCloth()->mTargetCollisionSpheres.assign(targetSpheres.begin(), targetSpheres.end()); getChildCloth()->notifyChanged(); } else { getChildCloth()->mStartCollisionSpheres.assign(startSpheres.begin(), startSpheres.end()); getChildCloth()->mTargetCollisionSpheres.assign(targetSpheres.begin(), targetSpheres.end()); if(newSize - oldSize) //notify only if the size changed getChildCloth()->notifyChanged(); } wakeUp(); } template inline uint32_t ClothImpl::getNumSpheres() const { return uint32_t(getChildCloth()->mStartCollisionSpheres.size()); } // Fixed 4505:local function has been removed template inline void ClothImpl::setCapsules(Range capsules, uint32_t first, uint32_t last) { const IndexPair* srcIndices = reinterpret_cast(capsules.begin()); const uint32_t srcIndicesSize = uint32_t(capsules.size() / 2); uint32_t oldSize = uint32_t(getChildCloth()->mCapsuleIndices.size()); uint32_t newSize = srcIndicesSize + oldSize - last + first; NV_CLOTH_ASSERT(newSize <= 32); NV_CLOTH_ASSERT(first <= oldSize); NV_CLOTH_ASSERT(last <= oldSize); if (getChildCloth()->mCapsuleIndices.capacity() < newSize) { ContextLockType contextLock(getChildCloth()->mFactory); getChildCloth()->mCapsuleIndices.reserve(newSize); } // resize to larger of oldSize and newSize getChildCloth()->mCapsuleIndices.resize(std::max(oldSize, newSize)); typename T::MappedIndexVectorType dstIndices = getChildCloth()->mCapsuleIndices; if (uint32_t delta = newSize - oldSize) { // move past-range elements to new place move(dstIndices.begin(), last, oldSize, last + delta); // fill new elements from capsules for (uint32_t i = last; i < last + delta; ++i) dstIndices[i] = srcIndices[i - first]; dstIndices.resize(newSize); getChildCloth()->notifyChanged(); } // fill existing elements from capsules for (uint32_t i = 0; i < srcIndicesSize; ++i) dstIndices[first + i] = srcIndices[i]; getChildCloth()->wakeUp(); } template inline uint32_t ClothImpl::getNumCapsules() const { return uint32_t(getChildCloth()->mCapsuleIndices.size()); } template inline void ClothImpl::setPlanes(Range planes, uint32_t first, uint32_t last) { uint32_t oldSize = uint32_t(getChildCloth()->mStartCollisionPlanes.size()); uint32_t newSize = uint32_t(planes.size()) + oldSize - last + first; NV_CLOTH_ASSERT(newSize <= 32); NV_CLOTH_ASSERT(first <= oldSize); NV_CLOTH_ASSERT(last <= oldSize); #if PX_DEBUG || PX_CHECKED int logCount = 0; for (int i = 0; i(planes.size()); i++) { if (fabsf(planes[i].getXYZ().magnitudeSquared() - 1.0f) > 0.01f) { if (logCount == 0) NV_CLOTH_LOG_INVALID_PARAMETER("The plane normals passed to Cloth::setPlanes are not normalized. First error encounterd at plane %d (%f, %f, %f, %f)", i, static_cast(planes[i].x), static_cast(planes[i].y), static_cast(planes[i].z), static_cast(planes[i].w)); logCount++; } } if (logCount>1) { NV_CLOTH_LOG_INVALID_PARAMETER("This error was encountered %d more times.", logCount-1); } #endif if (!oldSize && !newSize) return; if (!oldSize) { ContextLockType contextLock(getChildCloth()->mFactory); getChildCloth()->mStartCollisionPlanes.assign(planes.begin(), planes.end()); getChildCloth()->notifyChanged(); } else { if (std::max(oldSize, newSize) > std::min(getChildCloth()->mStartCollisionPlanes.capacity(), getChildCloth()->mTargetCollisionPlanes.capacity())) { ContextLockType contextLock(getChildCloth()->mFactory); getChildCloth()->mStartCollisionPlanes.reserve(newSize); getChildCloth()->mTargetCollisionPlanes.reserve(std::max(oldSize, newSize)); } typename T::MappedVec4fVectorType start = getChildCloth()->mStartCollisionPlanes; typename T::MappedVec4fVectorType target = getChildCloth()->mTargetCollisionPlanes; // fill target from start for (uint32_t i = target.size(); i < oldSize; ++i) target.pushBack(start[i]); // resize to larger of oldSize and newSize start.resize(std::max(oldSize, newSize), physx::PxVec4(0.0f)); target.resize(std::max(oldSize, newSize), physx::PxVec4(0.0f)); if (int32_t delta = int32_t(newSize - oldSize)) { // move past-range elements to new place move(start.begin(), last, oldSize, last + delta); move(target.begin(), last, oldSize, last + delta); // fill new elements from planes for (uint32_t i = last; i < last + delta; ++i) start[i] = planes[i - first]; // adjust convex indices uint32_t mask = (uint32_t(1) << (last + std::min(delta, 0))) - 1; typename T::MappedMaskVectorType masks = getChildCloth()->mConvexMasks; Vector::Type::Iterator cIt, cEnd = masks.end(); for (cIt = masks.begin(); cIt != cEnd;) { uint32_t convex = (*cIt & mask); if (delta < 0) convex |= *cIt >> -delta & ~mask; else convex |= (*cIt & ~mask) << delta; if (convex) *cIt++ = convex; else { masks.replaceWithLast(cIt); cEnd = masks.end(); } } start.resize(newSize); target.resize(newSize); getChildCloth()->notifyChanged(); } // fill target elements with planes for (uint32_t i = 0; i < planes.size(); ++i) target[first + i] = planes[i]; } wakeUp(); } template inline void ClothImpl::setPlanes(Range startPlanes, Range targetPlanes) { NV_CLOTH_ASSERT(startPlanes.size() == targetPlanes.size()); //Clamp ranges to the first 32 planes startPlanes = Range(startPlanes.begin(), std::min(startPlanes.end(), startPlanes.begin() + 32)); targetPlanes = Range(targetPlanes.begin(), std::min(targetPlanes.end(), targetPlanes.begin() + 32)); uint32_t oldSize = uint32_t(getChildCloth()->mStartCollisionPlanes.size()); uint32_t newSize = uint32_t(startPlanes.size()); if(newSize > std::min(getChildCloth()->mStartCollisionPlanes.capacity(), getChildCloth()->mTargetCollisionPlanes.capacity())) { //context lock only if we are growing the array ContextLockType contextLock(getChildCloth()->mFactory); getChildCloth()->mStartCollisionPlanes.assign(startPlanes.begin(), startPlanes.end()); getChildCloth()->mTargetCollisionPlanes.assign(targetPlanes.begin(), targetPlanes.end()); getChildCloth()->notifyChanged(); } else { getChildCloth()->mStartCollisionPlanes.assign(startPlanes.begin(), startPlanes.end()); getChildCloth()->mTargetCollisionPlanes.assign(targetPlanes.begin(), targetPlanes.end()); if(newSize - oldSize) //notify only if the size changed getChildCloth()->notifyChanged(); } wakeUp(); } template inline uint32_t ClothImpl::getNumPlanes() const { return uint32_t(getChildCloth()->mStartCollisionPlanes.size()); } template inline void ClothImpl::setConvexes(Range convexMasks, uint32_t first, uint32_t last) { uint32_t oldSize = uint32_t(getChildCloth()->mConvexMasks.size()); uint32_t newSize = uint32_t(convexMasks.size()) + oldSize - last + first; NV_CLOTH_ASSERT(newSize <= 32); NV_CLOTH_ASSERT(first <= oldSize); NV_CLOTH_ASSERT(last <= oldSize); #if PX_DEBUG || PX_CHECKED for (int i = 0; i(convexMasks.size()); i++) { if (convexMasks[i] == 0) { NV_CLOTH_LOG_INVALID_PARAMETER("Cloth::setConvexes expects bit masks of the form (1<mConvexMasks.capacity() < newSize) { ContextLockType contextLock(getChildCloth()->mFactory); getChildCloth()->mConvexMasks.reserve(newSize); } // resize to larger of oldSize and newSize getChildCloth()->mConvexMasks.resize(std::max(oldSize, newSize)); if (uint32_t delta = newSize - oldSize) { typename T::MappedMaskVectorType masks = getChildCloth()->mConvexMasks; // move past-range elements to new place move(masks.begin(), last, oldSize, last + delta); // fill new elements from capsules for (uint32_t i = last; i < last + delta; ++i) masks[i] = convexMasks[i - first]; masks.resize(newSize); getChildCloth()->notifyChanged(); } wakeUp(); } template inline uint32_t ClothImpl::getNumConvexes() const { return uint32_t(getChildCloth()->mConvexMasks.size()); } template inline void ClothImpl::setTriangles(Range triangles, uint32_t first, uint32_t last) { // convert from triangle to vertex count first *= 3; last *= 3; triangles = getChildCloth()->clampTriangleCount(triangles, last - first); NV_CLOTH_ASSERT(0 == triangles.size() % 3); uint32_t oldSize = uint32_t(getChildCloth()->mStartCollisionTriangles.size()); uint32_t newSize = uint32_t(triangles.size()) + oldSize - last + first; NV_CLOTH_ASSERT(first <= oldSize); NV_CLOTH_ASSERT(last <= oldSize); if (!oldSize && !newSize) return; if (!oldSize) { ContextLockType contextLock(getChildCloth()->mFactory); getChildCloth()->mStartCollisionTriangles.assign(triangles.begin(), triangles.end()); getChildCloth()->notifyChanged(); } else { if (std::max(oldSize, newSize) > std::min(getChildCloth()->mStartCollisionTriangles.capacity(), getChildCloth()->mTargetCollisionTriangles.capacity())) { ContextLockType contextLock(getChildCloth()->mFactory); getChildCloth()->mStartCollisionTriangles.reserve(newSize); getChildCloth()->mTargetCollisionTriangles.reserve(std::max(oldSize, newSize)); } typename T::MappedVec3fVectorType start = getChildCloth()->mStartCollisionTriangles; typename T::MappedVec3fVectorType target = getChildCloth()->mTargetCollisionTriangles; // fill target from start for (uint32_t i = target.size(); i < oldSize; ++i) target.pushBack(start[i]); // resize to larger of oldSize and newSize start.resize(std::max(oldSize, newSize), physx::PxVec3(0.0f)); target.resize(std::max(oldSize, newSize), physx::PxVec3(0.0f)); if (int32_t delta = int32_t(newSize - oldSize)) { // move past-range elements to new place move(start.begin(), last, oldSize, last + delta); move(target.begin(), last, oldSize, last + delta); // fill new elements from triangles for (uint32_t i = last; i < last + delta; ++i) start[i] = triangles[i - first]; start.resize(newSize); target.resize(newSize); getChildCloth()->notifyChanged(); } ////////////////////// // if (std::max(oldSize, newSize) > // std::min(getChildCloth()->mStartCollisionTriangles.capacity(), getChildCloth()->mTargetCollisionTriangles.capacity())) // { // ContextLockType contextLock(getChildCloth()->mFactory); // getChildCloth()->mStartCollisionTriangles.reserve(newSize); // getChildCloth()->mTargetCollisionTriangles.reserve(std::max(oldSize, newSize)); // } // // // fill target from start // for (uint32_t i = getChildCloth()->mTargetCollisionTriangles.size(); i < oldSize; ++i) // getChildCloth()->mTargetCollisionTriangles.pushBack(getChildCloth()->mStartCollisionTriangles[i]); // // // resize to larger of oldSize and newSize // getChildCloth()->mStartCollisionTriangles.resize(std::max(oldSize, newSize)); // getChildCloth()->mTargetCollisionTriangles.resize(std::max(oldSize, newSize)); // // if (uint32_t delta = newSize - oldSize) // { // // move past-range elements to new place // move(getChildCloth()->mStartCollisionTriangles.begin(), last, oldSize, last + delta); // move(getChildCloth()->mTargetCollisionTriangles.begin(), last, oldSize, last + delta); // // // fill new elements from triangles // for (uint32_t i = last; i < last + delta; ++i) // getChildCloth()->mStartCollisionTriangles[i] = triangles[i - first]; // // getChildCloth()->mStartCollisionTriangles.resize(newSize); // getChildCloth()->mTargetCollisionTriangles.resize(newSize); // // notifyChanged(); // } // fill target elements with triangles // for (uint32_t i = 0; i < triangles.size(); ++i) // getChildCloth()->mTargetCollisionTriangles[first + i] = triangles[i]; // fill target elements with triangles for (uint32_t i = 0; i < triangles.size(); ++i) target[first + i] = triangles[i]; } wakeUp(); } template inline void ClothImpl::setTriangles(Range startTriangles, Range targetTriangles, uint32_t first) { NV_CLOTH_ASSERT(startTriangles.size() == targetTriangles.size()); // convert from triangle to vertex count first *= 3; uint32_t last = uint32_t(getChildCloth()->mStartCollisionTriangles.size()); startTriangles = getChildCloth()->clampTriangleCount(startTriangles, last - first); targetTriangles = getChildCloth()->clampTriangleCount(targetTriangles, last - first); uint32_t oldSize = uint32_t(getChildCloth()->mStartCollisionTriangles.size()); uint32_t newSize = uint32_t(startTriangles.size()) + oldSize - last + first; NV_CLOTH_ASSERT(first <= oldSize); NV_CLOTH_ASSERT(last == oldSize); // this path only supports replacing the tail if (!oldSize && !newSize) return; if (newSize > std::min(getChildCloth()->mStartCollisionTriangles.capacity(), getChildCloth()->mTargetCollisionTriangles.capacity())) { ContextLockType contextLock(getChildCloth()->mFactory); getChildCloth()->mStartCollisionTriangles.assign(startTriangles.begin(), startTriangles.end()); getChildCloth()->mTargetCollisionTriangles.assign(targetTriangles.begin(), targetTriangles.end()); getChildCloth()->notifyChanged(); } else { uint32_t retainSize = oldSize - last + first; getChildCloth()->mStartCollisionTriangles.resize(retainSize); getChildCloth()->mTargetCollisionTriangles.resize(retainSize); getChildCloth()->mStartCollisionTriangles.assign(startTriangles.begin(), startTriangles.end()); getChildCloth()->mTargetCollisionTriangles.assign(targetTriangles.begin(), targetTriangles.end()); if (newSize - oldSize) getChildCloth()->notifyChanged(); } wakeUp(); } template inline uint32_t ClothImpl::getNumTriangles() const { return uint32_t(getChildCloth()->mStartCollisionTriangles.size()) / 3; } template inline bool ClothImpl::isContinuousCollisionEnabled() const { return getChildCloth()->mEnableContinuousCollision; } template inline void ClothImpl::enableContinuousCollision(bool enable) { if (enable == getChildCloth()->mEnableContinuousCollision) return; getChildCloth()->mEnableContinuousCollision = enable; getChildCloth()->notifyChanged(); wakeUp(); } template inline float ClothImpl::getCollisionMassScale() const { return getChildCloth()->mCollisionMassScale; } template inline void ClothImpl::setCollisionMassScale(float scale) { if (scale == getChildCloth()->mCollisionMassScale) return; getChildCloth()->mCollisionMassScale = scale; getChildCloth()->notifyChanged(); wakeUp(); } template inline void ClothImpl::setFriction(float friction) { getChildCloth()->mFriction = friction; getChildCloth()->notifyChanged(); } template inline float ClothImpl::getFriction() const { return getChildCloth()->mFriction; } template inline uint32_t ClothImpl::getNumVirtualParticleWeights() const { return uint32_t(getChildCloth()->mVirtualParticleWeights.size()); } template inline void ClothImpl::setTetherConstraintScale(float scale) { if (scale == getChildCloth()->mTetherConstraintScale) return; getChildCloth()->mTetherConstraintScale = scale; getChildCloth()->notifyChanged(); wakeUp(); } template inline float ClothImpl::getTetherConstraintScale() const { return getChildCloth()->mTetherConstraintScale; } template inline void ClothImpl::setTetherConstraintStiffness(float stiffness) { float value = safeLog2(1 - stiffness); if (value == getChildCloth()->mTetherConstraintLogStiffness) return; getChildCloth()->mTetherConstraintLogStiffness = value; getChildCloth()->notifyChanged(); wakeUp(); } template inline float ClothImpl::getTetherConstraintStiffness() const { return 1.f - safeExp2(getChildCloth()->mTetherConstraintLogStiffness); } template inline Range ClothImpl::getMotionConstraints() { wakeUp(); return getChildCloth()->push(getChildCloth()->mMotionConstraints); } template inline void ClothImpl::clearMotionConstraints() { getChildCloth()->clear(getChildCloth()->mMotionConstraints); wakeUp(); } template inline uint32_t ClothImpl::getNumMotionConstraints() const { return uint32_t(getChildCloth()->mMotionConstraints.mStart.size()); } template inline void ClothImpl::setMotionConstraintScaleBias(float scale, float bias) { if (scale == getChildCloth()->mMotionConstraintScale && bias == getChildCloth()->mMotionConstraintBias) return; getChildCloth()->mMotionConstraintScale = scale; getChildCloth()->mMotionConstraintBias = bias; getChildCloth()->notifyChanged(); wakeUp(); } template inline float ClothImpl::getMotionConstraintScale() const { return getChildCloth()->mMotionConstraintScale; } template inline float ClothImpl::getMotionConstraintBias() const { return getChildCloth()->mMotionConstraintBias; } template inline void ClothImpl::setMotionConstraintStiffness(float stiffness) { float value = safeLog2(1 - stiffness); if (value == getChildCloth()->mMotionConstraintLogStiffness) return; getChildCloth()->mMotionConstraintLogStiffness = value; getChildCloth()->notifyChanged(); wakeUp(); } template inline float ClothImpl::getMotionConstraintStiffness() const { return 1.f - safeExp2(getChildCloth()->mMotionConstraintLogStiffness); } template inline Range ClothImpl::getSeparationConstraints() { wakeUp(); return getChildCloth()->push(getChildCloth()->mSeparationConstraints); } template inline void ClothImpl::clearSeparationConstraints() { getChildCloth()->clear(getChildCloth()->mSeparationConstraints); wakeUp(); } template inline void ClothImpl::clearInterpolation() { if (!getChildCloth()->mTargetCollisionSpheres.empty()) { ContextLockType contextLock(getChildCloth()->mFactory); ps::swap(getChildCloth()->mStartCollisionSpheres, getChildCloth()->mTargetCollisionSpheres); getChildCloth()->mTargetCollisionSpheres.resize(0); } getChildCloth()->mMotionConstraints.pop(); getChildCloth()->mSeparationConstraints.pop(); wakeUp(); } template inline uint32_t ClothImpl::getNumSeparationConstraints() const { return uint32_t(getChildCloth()->mSeparationConstraints.mStart.size()); } template inline uint32_t ClothImpl::getNumParticleAccelerations() const { return uint32_t(getChildCloth()->mParticleAccelerations.size()); } template inline void ClothImpl::setWindVelocity(physx::PxVec3 wind) { if (wind == mWind) return; mWind = wind; getChildCloth()->notifyChanged(); wakeUp(); } template inline physx::PxVec3 ClothImpl::getWindVelocity() const { return mWind; } template inline void ClothImpl::setDragCoefficient(float coefficient) { NV_CLOTH_ASSERT(coefficient <= 1.f); float value = safeLog2(1.f - coefficient); if (value == mDragLogCoefficient) return; mDragLogCoefficient = value; getChildCloth()->notifyChanged(); wakeUp(); } template inline float ClothImpl::getDragCoefficient() const { return 1.f - safeExp2(mDragLogCoefficient); } template inline void ClothImpl::setLiftCoefficient(float coefficient) { NV_CLOTH_ASSERT(coefficient <= 1.f); float value = safeLog2(1.f - coefficient); if (value == mLiftLogCoefficient) return; mLiftLogCoefficient = value; getChildCloth()->notifyChanged(); wakeUp(); } template inline float ClothImpl::getLiftCoefficient() const { return 1.f - safeExp2(mLiftLogCoefficient); } template inline void ClothImpl::setFluidDensity(float fluidDensity) { NV_CLOTH_ASSERT(fluidDensity > 0.f); if (fluidDensity == mFluidDensity) return; mFluidDensity = fluidDensity; getChildCloth()->notifyChanged(); wakeUp(); } template inline float ClothImpl::getFluidDensity() const { return mFluidDensity; } template inline uint32_t ClothImpl::getNumSelfCollisionIndices() const { return uint32_t(getChildCloth()->mSelfCollisionIndices.size()); } // Fixed 4505:local function has been removed template inline void ClothImpl::setRestPositions(Range restPositions) { NV_CLOTH_ASSERT(restPositions.empty() || restPositions.size() == getNumParticles()); ContextLockType contextLock(getChildCloth()->mFactory); getChildCloth()->mRestPositions.assign(restPositions.begin(), restPositions.end()); wakeUp(); } template inline uint32_t ClothImpl::getNumRestPositions() const { return uint32_t(getChildCloth()->mRestPositions.size()); } template inline void ClothImpl::setSelfCollisionDistance(float distance) { if (distance == getChildCloth()->mSelfCollisionDistance) return; getChildCloth()->mSelfCollisionDistance = distance; getChildCloth()->notifyChanged(); wakeUp(); } template inline float ClothImpl::getSelfCollisionDistance() const { return getChildCloth()->mSelfCollisionDistance; } template inline void ClothImpl::setSelfCollisionStiffness(float stiffness) { NV_CLOTH_ASSERT(stiffness <= 1.0f); float value = safeLog2(1 - stiffness); if (value == getChildCloth()->mSelfCollisionLogStiffness) return; getChildCloth()->mSelfCollisionLogStiffness = value; getChildCloth()->notifyChanged(); wakeUp(); } template inline float ClothImpl::getSelfCollisionStiffness() const { return 1.f - safeExp2(getChildCloth()->mSelfCollisionLogStiffness); } template inline const physx::PxVec3& ClothImpl::getBoundingBoxCenter() const { return getChildCloth()->mParticleBoundsCenter; } template inline const physx::PxVec3& ClothImpl::getBoundingBoxScale() const { return getChildCloth()->mParticleBoundsHalfExtent; } template inline void ClothImpl::setSleepThreshold(float threshold) { if (threshold == mSleepThreshold) return; mSleepThreshold = threshold; getChildCloth()->notifyChanged(); wakeUp(); } template inline float ClothImpl::getSleepThreshold() const { return mSleepThreshold; } template inline void ClothImpl::setSleepTestInterval(uint32_t interval) { if (interval == mSleepTestInterval) return; mSleepTestInterval = interval; getChildCloth()->notifyChanged(); wakeUp(); } template inline uint32_t ClothImpl::getSleepTestInterval() const { return mSleepTestInterval; } template inline void ClothImpl::setSleepAfterCount(uint32_t afterCount) { if (afterCount == mSleepAfterCount) return; mSleepAfterCount = afterCount; getChildCloth()->notifyChanged(); wakeUp(); } template inline uint32_t ClothImpl::getSleepAfterCount() const { return mSleepAfterCount; } template inline uint32_t ClothImpl::getSleepPassCount() const { return mSleepPassCounter; } template inline bool ClothImpl::isAsleep() const { return isSleeping(); } template inline void ClothImpl::putToSleep() { mSleepPassCounter = mSleepAfterCount; } template inline bool ClothImpl::isSleeping() const { return mSleepPassCounter >= mSleepAfterCount; } template inline void ClothImpl::wakeUp() { mSleepPassCounter = 0; } template inline void ClothImpl::setUserData(void* data) { getChildCloth()->mUserData = data; } template inline void* ClothImpl::getUserData() const { return getChildCloth()->mUserData; } template template inline MappedRange ClothImpl::getMappedParticles(U* data) const { return MappedRange(data, data + getNumParticles(), *this, &Cloth::lockParticles, &Cloth::unlockParticles); } } // namespace cloth } // namespace nv