aboutsummaryrefslogtreecommitdiff
path: root/extensions/flexExtCloth.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/flexExtCloth.cpp')
-rw-r--r--extensions/flexExtCloth.cpp343
1 files changed, 343 insertions, 0 deletions
diff --git a/extensions/flexExtCloth.cpp b/extensions/flexExtCloth.cpp
new file mode 100644
index 0000000..096299f
--- /dev/null
+++ b/extensions/flexExtCloth.cpp
@@ -0,0 +1,343 @@
+// 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) 2013-2017 NVIDIA Corporation. All rights reserved.
+
+#include "../include/NvFlexExt.h"
+
+#include "../core/cloth.h"
+
+namespace
+{
+ struct Key
+ {
+ Key(int i, float d) : index(i), depth(d) {}
+
+ int index;
+ float depth;
+
+ bool operator < (const Key& rhs) const { return depth < rhs.depth; }
+ };
+}
+
+int NvFlexExtCreateWeldedMeshIndices(const float* vertices, int numVertices, int* uniqueIndices, int* originalToUniqueMap, float threshold)
+{
+ memset(originalToUniqueMap, -1, numVertices*sizeof(int));
+
+ const Vec3* positions = (const Vec3*)vertices;
+
+ // use a sweep and prune style search to accelerate neighbor finding
+ std::vector<Key> keys;
+ for (int i=0; i < numVertices; i++)
+ keys.push_back(Key(i, positions[i].z));
+
+ std::sort(keys.begin(), keys.end());
+
+ int uniqueCount = 0;
+
+ // sweep keys to find matching verts
+ for (int i=0; i < numVertices; ++i)
+ {
+ // we are a duplicate, skip
+ if (originalToUniqueMap[keys[i].index] != -1)
+ continue;
+
+ // scan forward until no vertex can be closer than threshold
+ for (int j=i+1; j < numVertices && (keys[j].depth-keys[i].depth) <= threshold; ++j)
+ {
+ float distance = Length(Vector3(positions[keys[i].index])-Vector3(positions[keys[j].index]));
+
+ if (distance <= threshold)
+ originalToUniqueMap[keys[j].index] = uniqueCount;
+ }
+
+ originalToUniqueMap[keys[i].index] = uniqueCount;
+
+ uniqueIndices[uniqueCount++] = keys[i].index;
+ }
+
+ return uniqueCount;
+}
+
+NvFlexExtAsset* NvFlexExtCreateClothFromMesh(const float* particles, int numVertices, const int* indices, int numTriangles, float stretchStiffness, float bendStiffness, float tetherStiffness, float tetherGive, float pressure)
+{
+ NvFlexExtAsset* asset = new NvFlexExtAsset();
+ memset(asset, 0, sizeof(*asset));
+
+ asset->particles = new float[numVertices*4];
+ memcpy(asset->particles, particles, numVertices*sizeof(float)*4);
+
+ asset->triangleIndices = new int[numTriangles*3];
+ memcpy(asset->triangleIndices, indices, numTriangles*3*sizeof(int));
+
+ asset->numParticles = numVertices;
+ asset->maxParticles = numVertices;
+
+ asset->numTriangles = numTriangles;
+
+ // create cloth mesh
+ ClothMesh cloth((Vec4*)particles, numVertices, indices, numTriangles*3, stretchStiffness, bendStiffness, true);
+
+ if (cloth.mValid)
+ {
+ // create tethers
+ if (tetherStiffness > 0.0f)
+ {
+ std::vector<int> anchors;
+ anchors.reserve(numVertices);
+
+ // find anchors
+ for (int i=0; i < numVertices; ++i)
+ {
+ Vec4& particle = ((Vec4*)particles)[i];
+
+ if (particle.w == 0.0f)
+ anchors.push_back(i);
+ }
+
+ if (anchors.size())
+ {
+ // create tethers
+ for (int i=0; i < numVertices; ++i)
+ {
+ Vec4& particle = ((Vec4*)particles)[i];
+ if (particle.w == 0.0f)
+ continue;
+
+ float minSqrDist = FLT_MAX;
+ int minIndex = -1;
+
+ // find the closest attachment point
+ for (int a=0; a < int(anchors.size()); ++a)
+ {
+ Vec4& attachment = ((Vec4*)particles)[anchors[a]];
+
+ float distSqr = LengthSq(Vec3(particle)-Vec3(attachment));
+ if (distSqr < minSqrDist)
+ {
+ minSqrDist = distSqr;
+ minIndex = anchors[a];
+ }
+ }
+
+ // add a tether
+ if (minIndex != -1)
+ {
+ cloth.mConstraintIndices.push_back(i);
+ cloth.mConstraintIndices.push_back(minIndex);
+ cloth.mConstraintRestLengths.push_back(sqrtf(minSqrDist)*(1.0f + tetherGive));
+
+ // negative stiffness indicates tether (unilateral constraint)
+ cloth.mConstraintCoefficients.push_back(-tetherStiffness);
+ }
+ }
+ }
+ }
+
+ const int numSprings = int(cloth.mConstraintCoefficients.size());
+
+ asset->springIndices = new int[numSprings*2];
+ asset->springCoefficients = new float[numSprings];
+ asset->springRestLengths = new float[numSprings];
+ asset->numSprings = numSprings;
+
+ for (int i=0; i < numSprings; ++i)
+ {
+ asset->springIndices[i*2+0] = cloth.mConstraintIndices[i*2+0];
+ asset->springIndices[i*2+1] = cloth.mConstraintIndices[i*2+1];
+ asset->springRestLengths[i] = cloth.mConstraintRestLengths[i];
+ asset->springCoefficients[i] = cloth.mConstraintCoefficients[i];
+ }
+
+ if (pressure > 0.0f)
+ {
+ asset->inflatable = true;
+ asset->inflatableVolume = cloth.mRestVolume;
+ asset->inflatableStiffness = cloth.mConstraintScale;
+ asset->inflatablePressure = pressure;
+ }
+ }
+ else
+ {
+ NvFlexExtDestroyAsset(asset);
+ return NULL;
+ }
+
+ return asset;
+}
+
+struct FlexExtTearingClothAsset : public NvFlexExtAsset
+{
+ ClothMesh* mMesh;
+};
+
+NvFlexExtAsset* NvFlexExtCreateTearingClothFromMesh(const float* particles, int numParticles, int maxParticles, const int* indices, int numTriangles, float stretchStiffness, float bendStiffness, float pressure)
+{
+ FlexExtTearingClothAsset* asset = new FlexExtTearingClothAsset();
+ memset(asset, 0, sizeof(*asset));
+
+ asset->particles = new float[maxParticles*4];
+ memcpy(asset->particles, particles, numParticles*sizeof(float)*4);
+
+ asset->triangleIndices = new int[numTriangles*3];
+ memcpy(asset->triangleIndices, indices, numTriangles*3*sizeof(int));
+
+ asset->numParticles = numParticles;
+ asset->maxParticles = maxParticles;
+
+ asset->numTriangles = numTriangles;
+
+ // create and store cloth mesh
+ asset->mMesh = new ClothMesh((Vec4*)particles, numParticles, indices, numTriangles*3, stretchStiffness, bendStiffness, true);
+
+ ClothMesh& cloth = *asset->mMesh;
+
+ if (cloth.mValid)
+ {
+ const int numSprings = int(cloth.mConstraintCoefficients.size());
+
+ // asset references cloth mesh memory directly
+ asset->springIndices = &cloth.mConstraintIndices[0];
+ asset->springCoefficients = &cloth.mConstraintCoefficients[0];
+ asset->springRestLengths = &cloth.mConstraintRestLengths[0];
+ asset->numSprings = numSprings;
+
+ if (pressure > 0.0f)
+ {
+ asset->inflatable = true;
+ asset->inflatableVolume = cloth.mRestVolume;
+ asset->inflatableStiffness = cloth.mConstraintScale;
+ asset->inflatablePressure = pressure;
+ }
+ }
+ else
+ {
+ NvFlexExtDestroyAsset(asset);
+ return NULL;
+ }
+
+ return asset;
+
+}
+
+void NvFlexExtDestroyTearingCloth(NvFlexExtAsset* asset)
+{
+ FlexExtTearingClothAsset* tearable = (FlexExtTearingClothAsset*)asset;
+
+ delete[] asset->particles;
+ delete[] asset->triangleIndices;
+
+ delete tearable->mMesh;
+ delete tearable;
+}
+
+void NvFlexExtTearClothMesh(NvFlexExtAsset* asset, float maxStrain, int maxSplits, NvFlexExtTearingParticleClone* particleCopies, int* numParticleCopies, int maxCopies, NvFlexExtTearingMeshEdit* triangleEdits, int* numTriangleEdits, int maxEdits)
+{
+ FlexExtTearingClothAsset* tearable = (FlexExtTearingClothAsset*)asset;
+
+ std::vector<ClothMesh::TriangleUpdate> edits;
+ std::vector<ClothMesh::VertexCopy> copies;
+
+ int splits = 0;
+
+ maxCopies = Min(maxCopies, tearable->maxParticles-tearable->numParticles);
+
+ // iterate over all edges and tear if beyond maximum strain
+ for (int i=0; i < tearable->numSprings && int(copies.size()) < maxCopies && splits < maxSplits; ++i)
+ {
+ int a = tearable->springIndices[i*2+0];
+ int b = tearable->springIndices[i*2+1];
+
+ Vec3 p = Vec3(&tearable->particles[a*4]);
+ Vec3 q = Vec3(&tearable->particles[b*4]);
+
+ // check strain and break if greater than max threshold
+ if (Length(p-q) > tearable->springRestLengths[i]*maxStrain)
+ {
+ // skip fixed particles
+ if (Vec4(&tearable->particles[a*4]).w == 0.0f)
+ continue;
+
+ if (Vec4(&tearable->particles[b*4]).w == 0.0f)
+ continue;
+
+ // choose vertex of edge to split
+ const int splitIndex = Randf() > 0.5f ? a : b;
+ const Vec3 splitPlane = Normalize(p-q); // todo: use plane perpendicular to normal and edge..
+
+ std::vector<int> adjacentTriangles;
+ std::vector<int> adjacentVertices;
+
+ const int newIndex = tearable->mMesh->SplitVertex((Vec4*)tearable->particles, splitIndex, splitPlane, adjacentTriangles, adjacentVertices, edits, copies, maxCopies-int(copies.size()));
+
+ if (newIndex != -1)
+ {
+ ++splits;
+
+ // separate each adjacent vertex if it is now singular
+ for (int s=0; s < int(adjacentVertices.size()); ++s)
+ {
+ const int adjacentVertex = adjacentVertices[s];
+
+ tearable->mMesh->SeparateVertex(adjacentVertex, edits, copies, maxCopies-int(copies.size()));
+ }
+
+ // also test the new vertex which can become singular
+ tearable->mMesh->SeparateVertex(newIndex, edits, copies, maxCopies-int(copies.size()));
+ }
+ }
+ }
+
+ // update asset particle count
+ tearable->numParticles = tearable->mMesh->mNumVertices;
+
+ // output copies
+ for (int c=0; c < int(copies.size()); ++c)
+ {
+ NvFlexExtTearingParticleClone clone;
+ clone.srcIndex = copies[c].srcIndex;
+ clone.destIndex = copies[c].destIndex;
+
+ particleCopies[c] = clone;
+ }
+
+ // output mesh edits, note that some edits will not be reported if edit buffer is not big enough
+ const int numEdits = Min(int(edits.size()), maxEdits);
+
+ for (int u=0; u < numEdits; ++u)
+ {
+ NvFlexExtTearingMeshEdit update;
+ update.triIndex = edits[u].triangle;
+ update.newParticleIndex = edits[u].vertex;
+
+ tearable->triangleIndices[update.triIndex] = update.newParticleIndex;
+
+ triangleEdits[u] = update;
+ }
+
+
+ *numTriangleEdits = numEdits;
+ *numParticleCopies = int(copies.size());
+}