aboutsummaryrefslogtreecommitdiff
path: root/NvCloth/Tools/AuthoringLibrary/src
diff options
context:
space:
mode:
authorMarijn Tamis <[email protected]>2018-09-12 14:12:47 +0200
committerMarijn Tamis <[email protected]>2018-09-12 14:12:47 +0200
commit7bceea80d4a04649f495f4f4331d7e3bdcdb05ca (patch)
tree824767cccf7b516a8c0b32467c6314eaa802f58d /NvCloth/Tools/AuthoringLibrary/src
parentAdded missing GenerateProjectsIOS.sh file (diff)
downloadnvcloth-7bceea80d4a04649f495f4f4331d7e3bdcdb05ca.tar.xz
nvcloth-7bceea80d4a04649f495f4f4331d7e3bdcdb05ca.zip
1.1.5 Release (24934621)
Diffstat (limited to 'NvCloth/Tools/AuthoringLibrary/src')
-rw-r--r--NvCloth/Tools/AuthoringLibrary/src/CollisionVisualization.cpp432
-rw-r--r--NvCloth/Tools/AuthoringLibrary/src/DebugVisualization.cpp323
-rw-r--r--NvCloth/Tools/AuthoringLibrary/src/Parameters.cpp247
3 files changed, 1002 insertions, 0 deletions
diff --git a/NvCloth/Tools/AuthoringLibrary/src/CollisionVisualization.cpp b/NvCloth/Tools/AuthoringLibrary/src/CollisionVisualization.cpp
new file mode 100644
index 0000000..ceee90f
--- /dev/null
+++ b/NvCloth/Tools/AuthoringLibrary/src/CollisionVisualization.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-2017 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 "NvClothAuthoringLibrary/CollisionVisualization.h"
+#include "NvCloth/Cloth.h"
+#include "NvCloth/Fabric.h"
+#include "NvCloth/Factory.h"
+#include <assert.h>
+#include <algorithm>
+#include "NvCloth/Allocator.h"
+#include "NvCloth/Callbacks.h"
+
+namespace nv
+{
+namespace cloth
+{
+namespace collisionVisualization
+{
+
+SimpleMesh::SimpleMesh()
+ :
+mPositions(nullptr),
+mNormals(nullptr),
+mUvs(nullptr),
+mIndices(nullptr),
+mVertexCount(0),
+mIndexCount(0)
+{
+
+}
+SimpleMesh::~SimpleMesh()
+{
+ auto& allocator = *GetNvClothAllocator();
+ allocator.deallocate(mPositions);
+ allocator.deallocate(mNormals);
+ allocator.deallocate(mUvs);
+ allocator.deallocate(mIndices);
+}
+void SimpleMesh::initialize(int vertexCount, int indexCount)
+{
+ mVertexCount = vertexCount;
+ mIndexCount = indexCount;
+
+ auto& allocator = *GetNvClothAllocator();
+
+ mPositions = static_cast<physx::PxVec3*>(
+ allocator.allocate(sizeof(physx::PxVec3)*vertexCount, "nv::cloth::collisionVisualization::SimpleMesh::mPositions", __FILE__, __LINE__)
+ );
+ mNormals = static_cast<physx::PxVec3*>(
+ allocator.allocate(sizeof(physx::PxVec3)*vertexCount, "nv::cloth::collisionVisualization::SimpleMesh::mNormals", __FILE__, __LINE__)
+ );
+ mUvs = static_cast<physx::PxVec2*>(
+ allocator.allocate(sizeof(physx::PxVec2)*vertexCount, "nv::cloth::collisionVisualization::SimpleMesh::mUvs", __FILE__, __LINE__)
+ );
+ mIndices = static_cast<unsigned int*>(
+ allocator.allocate(sizeof(unsigned int)*indexCount, "nv::cloth::collisionVisualization::SimpleMesh::mIndices", __FILE__, __LINE__)
+ );
+}
+
+void getSphereMemorySize(int segmentsX, int segmentsY, int* outVertexCount, int* outIndexCount)
+{
+ const int xSegments = segmentsX;
+ const int ySegments = segmentsY;
+
+ *outVertexCount = 1 + (xSegments * (ySegments - 1)) + 1;
+ *outIndexCount = xSegments * 3 + 6 * (xSegments * (ySegments - 2)) + xSegments * 3;
+}
+
+void generateSphere(int segmentsX, int segmentY, physx::PxMat44 transform,
+ physx::PxStrideIterator<unsigned int> outIndices, int indexOffset,
+ physx::PxStrideIterator<physx::PxVec3> outPositions, physx::PxStrideIterator<physx::PxVec3> outNormals, physx::PxStrideIterator<physx::PxVec2> outUvs)
+{
+ const int xSegments = segmentsX;
+ const int ySegments = segmentY;
+
+ physx::PxStrideIterator<physx::PxVec3> vertexIteratorPos = outPositions;
+ physx::PxStrideIterator<physx::PxVec3> vertexIteratorNormal = outNormals;
+ physx::PxStrideIterator<physx::PxVec2> vertexIteratorUv = outUvs;
+
+ {
+ //bottom
+ physx::PxVec3 pos = physx::PxVec3(0.0f, -1.0f, 0.0f);
+ *vertexIteratorPos++ = transform.transform(pos);
+ if(outNormals.ptr()) *vertexIteratorNormal++ = transform.rotate(physx::PxVec4(pos, 0.0f)).getXYZ();
+ if(outUvs.ptr()) *vertexIteratorUv++ = physx::PxVec2(0.0f, 0.0f);
+ }
+
+ //middle
+ for(int y = 1; y < ySegments; y++)
+ {
+ for(int x = 0; x < xSegments; x++)
+ {
+ float xf = (float)x / (xSegments - 1.0f);
+ float yaw = xf*physx::PxTwoPi;
+ float yf = (float)y / (ySegments);
+ float pitch = (yf - 0.5f)*physx::PxPi;
+
+ physx::PxVec3 pos = physx::PxVec3(cos(yaw)*cos(pitch), sin(pitch), sin(yaw)*cos(pitch));;
+ *vertexIteratorPos++ = transform.transform(pos);
+ if(outNormals.ptr()) *vertexIteratorNormal++ = transform.rotate(physx::PxVec4(pos, 0.0f)).getXYZ();
+ if(outUvs.ptr()) *vertexIteratorUv++ = physx::PxVec2(xf, yf);
+ }
+ }
+
+ {
+ //top
+ physx::PxVec3 pos = physx::PxVec3(0.0f, 1.0f, 0.0f);
+ *vertexIteratorPos++ = transform.transform(pos);
+ if(outNormals.ptr()) *vertexIteratorNormal++ = transform.rotate(physx::PxVec4(pos, 0.0f)).getXYZ();
+ if(outUvs.ptr()) *vertexIteratorUv++ = physx::PxVec2(0.0f, 0.0f);
+ }
+
+ physx::PxStrideIterator<unsigned int> indexIterator = outIndices;
+
+ //bottom cap
+ for(int x = 0; x < xSegments; x++)
+ {
+ *indexIterator++ = indexOffset;
+ *indexIterator++ = 1 + x + indexOffset;
+ *indexIterator++ = 1 + (x + 1) % xSegments + indexOffset;
+ }
+
+ const auto RingVertex = [xSegments, ySegments](int x, int y)
+ {
+ return 1 + y*xSegments + x%xSegments;
+ };
+
+ //middle
+ for(int y = 0; y < ySegments - 2; y++)
+ {
+ for(int x = 0; x < xSegments; x++)
+ {
+ *indexIterator++ = RingVertex(x, y) + indexOffset;
+ *indexIterator++ = RingVertex(x + 1, y) + indexOffset;
+ *indexIterator++ = RingVertex(x, y + 1) + indexOffset;
+
+ *indexIterator++ = RingVertex(x + 1, y) + indexOffset;
+ *indexIterator++ = RingVertex(x + 1, y + 1) + indexOffset;
+ *indexIterator++ = RingVertex(x, y + 1) + indexOffset;
+ }
+ }
+
+ int numVertices = vertexIteratorPos - outPositions;
+
+ //bottom cap
+ for(int x = 0; x < xSegments; x++)
+ {
+ *indexIterator++ = numVertices - 1 + indexOffset;
+ *indexIterator++ = RingVertex(x, ySegments - 2) + indexOffset;
+ *indexIterator++ = RingVertex(x + 1, ySegments - 2) + indexOffset;
+ }
+}
+
+void getCylinderMemorySize(int segmentsX, int segmentsY, int* outVertexCount, int* outIndexCount)
+{
+ const int xSegments = segmentsX;
+ const int ySegments = segmentsY;
+
+ *outVertexCount = xSegments * (ySegments + 1);
+ *outIndexCount = xSegments * ySegments * 6;
+}
+
+
+
+
+void generateCylinder(int segmentsX, int segmentsY, physx::PxMat44 transform,
+ physx::PxStrideIterator<unsigned int> outIndices, int indexOffset,
+ physx::PxStrideIterator<physx::PxVec3> outPositions, physx::PxStrideIterator<physx::PxVec3> outNormals, physx::PxStrideIterator<physx::PxVec2> outUvs)
+{
+ const int xSegments = segmentsX;
+ const int ySegments = segmentsY;
+
+ physx::PxStrideIterator<physx::PxVec3> vertexIteratorPos = outPositions;
+ physx::PxStrideIterator<physx::PxVec3> vertexIteratorNormal = outNormals;
+ physx::PxStrideIterator<physx::PxVec2> vertexIteratorUv = outUvs;
+
+ //middle
+ for(int y = 0; y < ySegments + 1; y++)
+ {
+ for(int x = 0; x < xSegments; x++)
+ {
+ float xf = (float)x / (xSegments - 1.0f);
+ float yaw = xf*physx::PxTwoPi;
+ float yf = (float)y / (ySegments) * 2.0f - 1.0f;
+
+ physx::PxVec3 pos = physx::PxVec3(cos(yaw), yf, sin(yaw));
+ *vertexIteratorPos++ = transform.transform(pos);
+ if(outNormals.ptr()) *vertexIteratorNormal++ = transform.rotate(physx::PxVec4(physx::PxVec3(cos(yaw), 0.0f, sin(yaw)), 0.0f)).getXYZ();
+ if(outUvs.ptr()) *vertexIteratorUv++ = physx::PxVec2(xf, yf);
+ }
+ }
+
+ physx::PxStrideIterator<unsigned int> indexIterator = outIndices;
+
+
+ const auto RingVertex = [xSegments, ySegments](int x, int y)
+ {
+ return y*xSegments + x%xSegments;
+ };
+
+ //middle
+ for(int y = 0; y < ySegments; y++)
+ {
+ for(int x = 0; x < xSegments; x++)
+ {
+ *indexIterator++ = RingVertex(x, y) + indexOffset;
+ *indexIterator++ = RingVertex(x + 1, y) + indexOffset;
+ *indexIterator++ = RingVertex(x, y + 1) + indexOffset;
+
+ *indexIterator++ = RingVertex(x + 1, y) + indexOffset;
+ *indexIterator++ = RingVertex(x + 1, y + 1) + indexOffset;
+ *indexIterator++ = RingVertex(x, y + 1) + indexOffset;
+ }
+ }
+}
+
+void getCollisionCapsuleMemorySize(int sphereCount, int indexCount, SimpleMesh const& cachedSphere, SimpleMesh const& cachedCylinder, int* outVertexCount, int* outIndexCount)
+{
+ *outVertexCount = cachedSphere.mVertexCount*sphereCount + cachedCylinder.mVertexCount*(indexCount / 2);
+ *outIndexCount = cachedSphere.mIndexCount*sphereCount + cachedCylinder.mIndexCount*(indexCount / 2);
+}
+
+namespace
+{
+ /** returns two vectors in b and c so that [a b c] form a basis.
+ * a needs to be a unit vector.
+ */
+ inline void computeBasis(const physx::PxVec3& a, physx::PxVec3* b, physx::PxVec3* c)
+ {
+ if(fabsf(a.x) >= 0.57735f)
+ *b = physx::PxVec3(a.y, -a.x, 0.0f);
+ else
+ *b = physx::PxVec3(0.0f, a.z, -a.y);
+
+ *b = b->getNormalized();
+ *c = a.cross(*b);
+ }
+
+ physx::PxVec3 IntersectSpheres(float* circleRadius, physx::PxVec3 aCenter, float aRadius, physx::PxVec3 bCenter, float bRadius)
+ {
+ //Intersect spheres in 2d (http://paulbourke.net/geometry/circlesphere/ Intersection of two circles)
+ float d = (aCenter - bCenter).magnitude();
+ float a = (aRadius*aRadius - bRadius*bRadius + d*d) / (2.0f*d);
+ float h = sqrtf(aRadius*aRadius - a*a);
+ physx::PxVec3 P3 = aCenter + a * (bCenter - aCenter) / d;
+ if(circleRadius) *circleRadius = h;
+ return P3;
+ }
+}
+
+void generateCollisionCapsules(physx::PxVec4 const* spheres, int sphereCount, uint32_t const* indices, int indexCount, float grow,
+ SimpleMesh const& cachedSphere, SimpleMesh const& cachedCylinder,
+ physx::PxStrideIterator<unsigned int> outIndices, int indexOffset,
+ physx::PxStrideIterator<physx::PxVec3> outPositions, physx::PxStrideIterator<physx::PxVec3> outNormals, physx::PxStrideIterator<physx::PxVec2> outUvs)
+{
+ physx::PxStrideIterator<physx::PxVec3> vertexIteratorPos = outPositions;
+ physx::PxStrideIterator<physx::PxVec3> vertexIteratorNormal = outNormals;
+ physx::PxStrideIterator<physx::PxVec2> vertexIteratorUv = outUvs;
+
+ physx::PxStrideIterator<unsigned int> indexIterator = outIndices;
+
+ int nextVertex = 0;
+ int nextIndex = 0;
+ for(int i = 0; i < sphereCount; i++)
+ {
+ int baseIndex = nextVertex;
+ physx::PxMat44 transform =
+ physx::PxMat44(physx::PxMat33(physx::PxIdentity), spheres[i].getXYZ())
+ * physx::PxMat44(physx::PxVec4(spheres[i].w + grow, spheres[i].w + grow, spheres[i].w + grow, 1.0f));
+
+ for(int vi = 0; vi<cachedSphere.mVertexCount; vi++)
+ {
+ physx::PxVec3 pos = cachedSphere.mPositions[vi];
+ *vertexIteratorPos++ = transform.transform(pos);
+ if(outNormals.ptr()) *vertexIteratorNormal++ = transform.rotate(physx::PxVec4(cachedSphere.mNormals[vi], 0.0f)).getXYZ();
+ if(outUvs.ptr()) *vertexIteratorUv++ = cachedSphere.mUvs[vi];
+ }
+
+ for(int ii = 0; ii < cachedSphere.mIndexCount; ii++)
+ {
+ *indexIterator++ = cachedSphere.mIndices[ii] + baseIndex + indexOffset;
+ }
+ nextVertex += cachedSphere.mVertexCount;
+ }
+
+ for(int i = 0; i < indexCount; i += 2)
+ {
+ int baseIndex = nextVertex;
+
+ physx::PxVec3 spherePosA = spheres[indices[i]].getXYZ();
+ physx::PxVec3 spherePosB = spheres[indices[i + 1]].getXYZ();
+ float sphereRadiusA = spheres[indices[i]].w + grow;
+ float sphereRadiusB = spheres[indices[i + 1]].w + grow;
+
+ if(sphereRadiusA < sphereRadiusB)
+ {
+ std::swap(sphereRadiusA, sphereRadiusB);
+ std::swap(spherePosA, spherePosB);
+ }
+
+ {
+ //http://jwilson.coe.uga.edu/emt669/Student.Folders/Kertscher.Jeff/Essay.3/Tangents.html
+
+ //sphere a with smaller radius
+ float cRadius = sphereRadiusA - sphereRadiusB;
+ if(cRadius > 0.00001)
+ {
+ physx::PxVec3 basis[3];
+ basis[2] = spherePosB - spherePosA;
+ basis[2].normalize();
+ computeBasis(basis[2], &basis[0], &basis[1]);
+
+ physx::PxVec3 cCenter = spherePosA;
+
+ //sphere in between the a and b
+ physx::PxVec3 dCenter = (spherePosA + spherePosB)*0.5f;
+ float dRadius = (spherePosA - spherePosB).magnitude()*0.5f;
+
+ //intersection between c and d to get tangent point
+ float iRadius;
+ physx::PxVec3 iCenter = IntersectSpheres(&iRadius, dCenter, dRadius, cCenter, cRadius);
+ physx::PxVec3 iPoint = iCenter + basis[0] * iRadius; //tangent point on c
+ physx::PxVec3 offset = (iPoint - spherePosA).getNormalized(); //offset direction
+
+ physx::PxVec3 aPoint = spherePosA + offset*sphereRadiusA;
+ spherePosA = (aPoint - spherePosA).dot(basis[2])*basis[2] + spherePosA;
+ sphereRadiusA = (aPoint - spherePosA).magnitude();
+ physx::PxVec3 bPoint = spherePosB + offset*sphereRadiusB;
+ spherePosB = (bPoint - spherePosA).dot(basis[2])*basis[2] + spherePosA;
+ sphereRadiusB = (bPoint - spherePosB).magnitude();
+ }
+ }
+
+ float length = (spherePosB - spherePosA).magnitude();
+
+
+ physx::PxMat44 scaleA = physx::PxMat44(physx::PxVec4(sphereRadiusA, length / 2.0f, sphereRadiusA + grow, 1.0f));
+ physx::PxMat44 scaleB = physx::PxMat44(physx::PxVec4(sphereRadiusB, length / 2.0f, sphereRadiusB, 1.0f));
+
+ physx::PxQuat orientation;
+ {
+ physx::PxVec3 u = physx::PxVec3(0.0f, 1.0f, 0.0f);
+ physx::PxVec3 v = spherePosB - spherePosA;
+ v.normalize();
+
+ if(u.dot(v) < -0.9999 || u.dot(v) > 0.9999)
+ {
+ physx::PxVec3 orth, tmp;
+ computeBasis(u, &orth, &tmp);
+ orientation = physx::PxQuat(orth.x, orth.y, orth.z, 0.0f);
+ }
+ else
+ {
+ physx::PxVec3 half = u + v;
+ half.normalize();
+ physx::PxVec3 imaginary = u.cross(half);
+ orientation = physx::PxQuat(imaginary.x, imaginary.y, imaginary.z, u.dot(half));
+ }
+ }
+
+ physx::PxMat44 transform = physx::PxMat44(physx::PxTransform(spherePosA, orientation))*scaleA;
+
+ int firstRing = cachedCylinder.mVertexCount / 2;
+ for(int vi = 0; vi<firstRing; vi++)
+ {
+ physx::PxVec3 pos = cachedCylinder.mPositions[vi];
+ *vertexIteratorPos++ = transform.transform(pos);
+ if(outNormals.ptr()) *vertexIteratorNormal++ = transform.rotate(physx::PxVec4(cachedCylinder.mNormals[vi], 0.0f)).getXYZ();
+ if(outUvs.ptr()) *vertexIteratorUv++ = cachedCylinder.mUvs[vi];
+ }
+ transform = physx::PxMat44(physx::PxTransform(spherePosA, orientation))*scaleB;
+ for(int vi = firstRing; vi<cachedCylinder.mVertexCount; vi++)
+ {
+ physx::PxVec3 pos = cachedCylinder.mPositions[vi];
+ *vertexIteratorPos++ = transform.transform(pos);
+ if(outNormals.ptr()) *vertexIteratorNormal++ = transform.rotate(physx::PxVec4(cachedCylinder.mNormals[vi], 0.0f)).getXYZ();
+ if(outUvs.ptr()) *vertexIteratorUv++ = cachedCylinder.mUvs[vi];
+ }
+
+ nextVertex += cachedCylinder.mVertexCount;
+
+ for(int ii = 0; ii < cachedCylinder.mIndexCount; ii++)
+ {
+ *indexIterator++ = cachedCylinder.mIndices[ii] + baseIndex + indexOffset;
+ }
+ }
+}
+
+void getCollisionCapsuleSubmeshOffsets(int sphereCount, int indexCount, SimpleMesh const& cachedSphere, SimpleMesh const& cachedCylinder, physx::PxStrideIterator<unsigned int> submehsOffsets)
+{
+ int nextOffset = 0;
+ for(int i = 0; i < sphereCount; i++)
+ {
+ *submehsOffsets++ = nextOffset;
+ nextOffset += cachedSphere.mIndexCount;
+ }
+ for(int i = 0; i < indexCount; i+=2)
+ {
+ *submehsOffsets++ = nextOffset;
+ nextOffset += cachedCylinder.mIndexCount;
+ }
+}
+
+
+}
+}
+} \ No newline at end of file
diff --git a/NvCloth/Tools/AuthoringLibrary/src/DebugVisualization.cpp b/NvCloth/Tools/AuthoringLibrary/src/DebugVisualization.cpp
new file mode 100644
index 0000000..c7e4601
--- /dev/null
+++ b/NvCloth/Tools/AuthoringLibrary/src/DebugVisualization.cpp
@@ -0,0 +1,323 @@
+// 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-2017 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 "NvClothAuthoringLibrary/DebugVisualization.h"
+#include <foundation/PxMat44.h>
+#include "NvCloth/Cloth.h"
+#include "NvCloth/Fabric.h"
+#include "NvCloth/Factory.h"
+#include <assert.h>
+#include <algorithm>
+
+namespace nv
+{
+namespace cloth
+{
+namespace debugVisualization
+{
+
+void VisualizeDistanceConstraints(Cloth* cloth_, AddLineCallback addLineCallback)
+{
+ nv::cloth::Cloth& cloth = *cloth_;
+ if(cloth.getNumMotionConstraints() == 0)
+ return;
+
+ nv::cloth::Factory& factory = cloth.getFactory();
+
+ nv::cloth::MappedRange<physx::PxVec4> particles = cloth.getCurrentParticles();
+ std::vector<physx::PxVec4> motionConstraints;
+ motionConstraints.reserve(cloth.getNumMotionConstraints() * 2);
+ motionConstraints.resize(cloth.getNumMotionConstraints());
+ factory.extractMotionConstraints(cloth, nv::cloth::Range<physx::PxVec4>(&motionConstraints[0], &motionConstraints[0] + motionConstraints.size()));
+ motionConstraints.resize(cloth.getNumMotionConstraints() * 2);
+
+ nv::cloth::MappedRange<physx::PxVec4> positions = cloth.getCurrentParticles();
+
+ assert(positions.size() == cloth.getNumMotionConstraints());
+
+
+ //Set to 1 to color code lines based on distance constraint length (as % of max constraint distance in cloth)
+ //Set to 0 to color code lines based on how close the particle is to the distance constraint (as % of max distance per constraint)
+#define SHOW_DISTANCE_COLOR 0
+#if SHOW_DISTANCE_COLOR
+ float maxDist = 0.0f;
+ for(int i = (int)(motionConstraints.size() >> 1) - 1; i >= 0; i--)
+ {
+ maxDist = max(maxDist, motionConstraints[i].w);
+ }
+#endif
+
+ for(int i = ((int)motionConstraints.size() >> 1) - 1; i >= 0; i--)
+ {
+ float l = motionConstraints[i].w;
+ physx::PxVec3 a = motionConstraints[i].getXYZ();
+ physx::PxVec3 b = positions[i].getXYZ();
+ physx::PxVec3 d = b - a;
+ float currentDist = d.magnitude();
+ if(d.magnitudeSquared() < 0.00001f)
+ {
+ d = physx::PxVec3(0.0f, 0.0f, 1.0f);
+ }
+ else
+ {
+ d.normalize();
+ }
+
+#if SHOW_DISTANCE_COLOR
+ physx::PxVec4 color(0.0f, 1.0f-std::max(0.0f, std::min(1.0f, (l / maxDist))), 0.0f, 1.0f);
+#else
+ physx::PxVec4 color(0.0f, 1.0f-std::max(0.0f,std::min(1.0f, (currentDist / l))), 0.0f, 1.0f);
+#endif
+
+ addLineCallback(a, color, b, color);
+ }
+}
+
+void VisualizeTethers(Cloth* cloth_, AddLineCallback addLineCallback)
+{
+ nv::cloth::Cloth& cloth = *cloth_;
+ nv::cloth::Fabric& fabric = cloth.getFabric();
+ if(fabric.getNumTethers() == 0)
+ return;
+
+ nv::cloth::Factory& factory = cloth.getFactory();
+ nv::cloth::MappedRange<physx::PxVec4> particles = cloth.getCurrentParticles();
+
+ std::vector<float> tetherLengths;
+ tetherLengths.resize(fabric.getNumTethers());
+ std::vector<uint32_t> anchors;
+ anchors.resize(fabric.getNumTethers());
+
+ factory.extractFabricData(fabric, nv::cloth::Range<uint32_t>(0, 0), nv::cloth::Range<uint32_t>(0, 0), nv::cloth::Range<float>(0, 0), nv::cloth::Range<float>(0, 0), nv::cloth::Range<uint32_t>(0, 0),
+ nv::cloth::Range<uint32_t>(&anchors[0], &anchors[0] + anchors.size()), nv::cloth::Range<float>(&tetherLengths[0], &tetherLengths[0] + tetherLengths.size()), nv::cloth::Range<uint32_t>(0, 0));
+
+ int particleCount = fabric.getNumParticles();
+
+ for(int i = 0; i < (int)anchors.size(); i++)
+ {
+ float lengthDiff = (particles[anchors[i]].getXYZ() - particles[i%particleCount].getXYZ()).magnitude() - tetherLengths[i];
+ physx::PxVec4 color = lengthDiff > 0.0f ? physx::PxVec4(1.0f, 0.0, 0.0, 1.0f) : physx::PxVec4(1.0f, 0.0, 1.0, 1.0f);
+ addLineCallback(particles[anchors[i]].getXYZ(), color, particles[i%particleCount].getXYZ(), color);
+ }
+}
+
+void VisualizeConstraints(Cloth* cloth_, AddLineCallback addLineCallback, int visiblePhaseRangeBegin, int visiblePhaseRangeEnd)
+{
+ nv::cloth::Cloth& cloth = *cloth_;
+ nv::cloth::Fabric& fabric = cloth.getFabric();
+ if(fabric.getNumIndices() == 0)
+ return;
+
+ nv::cloth::Factory& factory = cloth.getFactory();
+
+ nv::cloth::MappedRange<physx::PxVec4> particles = cloth.getCurrentParticles();
+
+ if(visiblePhaseRangeBegin >= visiblePhaseRangeEnd)
+ {
+ //then simply render all constraints in one go
+ std::vector<uint32_t> indices;
+ indices.resize(fabric.getNumIndices());
+
+ factory.extractFabricData(fabric, nv::cloth::Range<uint32_t>(0, 0), nv::cloth::Range<uint32_t>(0, 0), nv::cloth::Range<float>(0, 0), nv::cloth::Range<float>(0, 0), nv::cloth::Range<uint32_t>(&indices[0], &indices[0] + indices.size()),
+ nv::cloth::Range<uint32_t>(0, 0), nv::cloth::Range<float>(0, 0), nv::cloth::Range<uint32_t>(0, 0));
+
+ physx::PxVec4 color(0.098, 0.098, 0.6, 1.0f);
+
+ for(int i = 1; i < (int)indices.size(); i += 2)
+ {
+ addLineCallback(particles[indices[i]].getXYZ(), color, particles[indices[i - 1]].getXYZ(), color);
+ }
+ }
+ else
+ {
+ //otherwise we render individual phases
+ std::vector<uint32_t> indices;
+ indices.resize(fabric.getNumIndices());
+ std::vector<uint32_t> phases;
+ phases.resize(fabric.getNumPhases());
+ std::vector<uint32_t> sets;
+ sets.resize(fabric.getNumSets());
+
+ factory.extractFabricData(fabric, nv::cloth::Range<uint32_t>(&phases[0], &phases[0] + phases.size()), nv::cloth::Range<uint32_t>(&sets[0], &sets[0] + sets.size()), nv::cloth::Range<float>(0, 0), nv::cloth::Range<float>(0, 0), nv::cloth::Range<uint32_t>(&indices[0], &indices[0] + indices.size()),
+ nv::cloth::Range<uint32_t>(0, 0), nv::cloth::Range<float>(0, 0), nv::cloth::Range<uint32_t>(0, 0));
+
+ uint32_t* iIt = &indices[0];
+ for(int phaseIndex = 0; phaseIndex < (int)fabric.getNumPhases(); phaseIndex++)
+ {
+ uint32_t* sIt = &sets[phases[phaseIndex]];
+ uint32_t* iEnd = &indices[0] + (sIt[0] * 2);
+ uint32_t* iStart = iIt;
+
+ if(!(phaseIndex >= visiblePhaseRangeBegin && phaseIndex < visiblePhaseRangeEnd))
+ {
+ iIt = iEnd;
+ continue;
+ }
+
+ for(iIt; iIt < iEnd; iIt += 2)
+ {
+ float c = (float)(iIt - iStart) / (float)(iEnd - iStart);
+
+ physx::PxVec4 colorTable[3]
+ {
+ physx::PxVec4(1.0f, 0.0f, 0.0f, 1.0f),
+ physx::PxVec4(0.0f, 1.0f, 0.0f, 1.0f),
+ physx::PxVec4(0.0f, 0.0f, 1.0f, 1.0f)
+ };
+
+ physx::PxVec4 shiftTable[3]
+ {
+ physx::PxVec4(0.0f, 1.0f, 0.0f, 0.0f),
+ physx::PxVec4(1.0f, 0.0f, 0.0f, 0.0f),
+ physx::PxVec4(0.0f, 0.0f, 1.0f, 0.0f)
+ };
+
+ physx::PxVec4 color = colorTable[phaseIndex % 3] + shiftTable[phaseIndex % 3] * c;
+
+ addLineCallback(particles[*iIt].getXYZ(), color, particles[*(iIt + 1)].getXYZ(), color);
+ }
+ }
+ }
+}
+
+void VisualizeConstraintStiffness(Cloth* cloth_, AddLineCallback addLineCallback)
+{
+ nv::cloth::Cloth& cloth = *cloth_;
+ nv::cloth::Fabric& fabric = cloth.getFabric();
+ if(fabric.getNumIndices() == 0)
+ return;
+
+ if(!fabric.getNumStiffnessValues())
+ return;
+
+ nv::cloth::Factory& factory = cloth.getFactory();
+
+ nv::cloth::MappedRange<physx::PxVec4> particles = cloth.getCurrentParticles();
+
+ std::vector<uint32_t> indices;
+ indices.resize(fabric.getNumIndices());
+ std::vector<float> stiffness;
+ stiffness.resize(fabric.getNumRestvalues());
+
+ factory.extractFabricData(fabric, nv::cloth::Range<uint32_t>(0, 0), nv::cloth::Range<uint32_t>(0, 0), nv::cloth::Range<float>(0, 0), nv::cloth::Range<float>(&stiffness[0], &stiffness[0] + stiffness.size()), nv::cloth::Range<uint32_t>(&indices[0], &indices[0] + indices.size()),
+ nv::cloth::Range<uint32_t>(0, 0), nv::cloth::Range<float>(0, 0), nv::cloth::Range<uint32_t>(0, 0));
+
+ for(int i = 1; i < (int)indices.size(); i += 2)
+ {
+ float c = 1.0f - exp2f(stiffness[i >> 1]);
+
+ physx::PxVec4 color(0.8f * (1.0f - c), c * 0.8f, 0.0f, 1.0f);
+ addLineCallback(particles[indices[i - 1]].getXYZ(), color, particles[indices[i]].getXYZ(), color);
+ }
+}
+
+void VisualizeConstraintError(Cloth* cloth_, AddLineCallback addLineCallback)
+{
+ nv::cloth::Cloth& cloth = *cloth_;
+ nv::cloth::Fabric& fabric = cloth.getFabric();
+ if(fabric.getNumRestvalues() == 0) { return; }
+ nv::cloth::Factory& factory = cloth.getFactory();
+
+ nv::cloth::MappedRange<physx::PxVec4> particles = cloth.getCurrentParticles();
+
+ std::vector<uint32_t> indices;
+ indices.resize(fabric.getNumIndices());
+ std::vector<float> restLengths;
+ restLengths.resize(fabric.getNumRestvalues());
+
+ factory.extractFabricData(fabric, nv::cloth::Range<uint32_t>(0, 0), nv::cloth::Range<uint32_t>(0, 0), nv::cloth::Range<float>(&restLengths[0], &restLengths[0] + restLengths.size()), nv::cloth::Range<float>(0, 0), nv::cloth::Range<uint32_t>(&indices[0], &indices[0] + indices.size()),
+ nv::cloth::Range<uint32_t>(0, 0), nv::cloth::Range<float>(0, 0), nv::cloth::Range<uint32_t>(0, 0));
+
+ for(int i = 0; i < (int)indices.size(); i += 2)
+ {
+ physx::PxVec4 p0 = particles[indices[i]];
+ physx::PxVec4 p1 = particles[indices[i + 1]];
+ float restLength = restLengths[i >> 1];
+ float length = (p0 - p1).magnitude();
+ const float scale = 2.0f;
+ float error = (length / restLength * 0.5f - 0.5f) * scale + 0.5f;
+ error = std::max(0.0f, std::min(1.0f, error));
+ physx::PxVec4 color(error * 0.8f, 1.0f - error*0.8f, 0.0f, 1.0f);
+ addLineCallback(p0.getXYZ(), color, p1.getXYZ(), color);
+ }
+}
+
+void VisualizePositionDelta(Cloth* cloth_, AddLineCallback addLineCallback, float lengthScale)
+{
+ nv::cloth::Cloth& cloth = *cloth_;
+
+ nv::cloth::MappedRange<physx::PxVec4> particles1 = cloth.getCurrentParticles();
+ nv::cloth::MappedRange<physx::PxVec4> particles0 = cloth.getPreviousParticles();
+
+ //scale so that the solver frequency doesn't affect the position delta length assuming 60fps
+ float iterationsPerFrame = std::max(1, int(1.0f / 60.0f * cloth.getSolverFrequency() + 0.5f));
+
+ physx::PxVec4 color(0.0f, 1.0f, 1.0f, 1.0f);
+
+ for(int i = 0; i < (int)particles1.size(); i++)
+ {
+ addLineCallback(particles1[i].getXYZ(), color, particles1[i].getXYZ() + (particles1[i] - particles0[i]).getXYZ()*iterationsPerFrame * lengthScale, color);
+ }
+}
+
+void VisualizeBoundingBox(Cloth* cloth_, AddLineCallback addLineCallback)
+{
+ nv::cloth::Cloth& cloth = *cloth_;
+
+ physx::PxVec3 c = cloth.getBoundingBoxCenter();
+ physx::PxVec3 d = cloth.getBoundingBoxScale();
+ physx::PxVec3 dx = physx::PxVec3(d.x, 0.0f, 0.0f);
+ physx::PxVec3 dy = physx::PxVec3(0.0f, d.y, 0.0f);
+ physx::PxVec3 dz = physx::PxVec3(0.0f, 0.0f, d.z);
+
+ physx::PxVec4 color(1.0f, 1.0f, 0.0f, 1.0f);
+
+ addLineCallback(c + dy + dz - dx, color, c + dy + dz + dx, color);
+ addLineCallback(c + dy - dz - dx, color, c + dy - dz + dx, color);
+ addLineCallback(c - dy + dz - dx, color, c - dy + dz + dx, color);
+ addLineCallback(c - dy - dz - dx, color, c - dy - dz + dx, color);
+ addLineCallback(c + dy + dx - dz, color, c + dy + dx + dz, color);
+ addLineCallback(c + dy - dx - dz, color, c + dy - dx + dz, color);
+ addLineCallback(c - dy + dx - dz, color, c - dy + dx + dz, color);
+ addLineCallback(c - dy - dx - dz, color, c - dy - dx + dz, color);
+ addLineCallback(c + dz + dx - dy, color, c + dz + dx + dy, color);
+ addLineCallback(c + dz - dx - dy, color, c + dz - dx + dy, color);
+ addLineCallback(c - dz + dx - dy, color, c - dz + dx + dy, color);
+ addLineCallback(c - dz - dx - dy, color, c - dz - dx + dy, color);
+
+ color = physx::PxVec4(0.467f, 0.467f, 0.0f, 1.0f);
+
+ addLineCallback(c + dy + dz + dx, color, c - dy - dz - dx, color);
+ addLineCallback(c + dy + dz - dx, color, c - dy - dz + dx, color);
+ addLineCallback(c - dy + dz + dx, color, c + dy - dz - dx, color);
+ addLineCallback(c - dy + dz - dx, color, c + dy - dz + dx, color);
+}
+
+}
+}
+} \ No newline at end of file
diff --git a/NvCloth/Tools/AuthoringLibrary/src/Parameters.cpp b/NvCloth/Tools/AuthoringLibrary/src/Parameters.cpp
new file mode 100644
index 0000000..69dbcdc
--- /dev/null
+++ b/NvCloth/Tools/AuthoringLibrary/src/Parameters.cpp
@@ -0,0 +1,247 @@
+// 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-2017 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 "NvClothAuthoringLibrary/Parameters.h"
+
+namespace nv
+{
+namespace cloth
+{
+namespace authoring
+{
+
+Parameter InitParameter(ParameterType type, int catagoryId, const char* name, const char* description, void* set, void* get)
+{
+ Parameter p;
+ static int nextId = 0;
+ p.mCatagoryId = catagoryId;
+ p.mParameterId = nextId++;
+ p.mName = name;
+ p.mDescription = description;
+ p.mType = type;
+ p.SetFunctionPointer = set;
+ p.GetFunctionPointer = get;
+ p.mHardMinLimit = false;
+ p.mHardMaxLimit = false;
+ return p;
+}
+
+Parameter InitParameter(int catagoryId, const char* name, const char* description, SetFloatParamType set, GetFloatParamType get, float minV, float maxV, bool hardMin = false, bool hardMax = false)
+{
+ Parameter p = InitParameter(ParameterType::FLOAT, catagoryId, name, description, set, get);
+ p.mMinFloat = minV;
+ p.mMaxFloat = maxV;
+ p.mHardMinLimit = hardMin;
+ p.mHardMaxLimit = hardMax;
+ return p;
+}
+
+Parameter InitParameter(int catagoryId, const char* name, const char* description, SetVec3ParamType set, GetVec3ParamType get, physx::PxVec3 minV, physx::PxVec3 maxV, ParameterType parameterType = ParameterType::VEC3, bool hardMin = false, bool hardMax = false)
+{
+ Parameter p = InitParameter(parameterType, catagoryId, name, description, set, get);
+ p.mMinVec3 = minV;
+ p.mMaxVec3 = maxV;
+ p.mHardMaxLimit = hardMax;
+ p.mHardMinLimit = hardMin;
+ return p;
+}
+
+static const char* sParameterCatagories[] =
+{
+ /* 0 */ "Basics",
+ /* 1 */ "Air simulation",
+ /* 2 */ "Local space simulation",
+ /* 3 */ "Tethers",
+ /* 4 */ "Collision",
+ /* 5 */ "Misc",
+ /* 6 */ "Airmeshes"
+ /* 7 */
+ /* 8 */
+};
+
+static Parameter sParameterList[] =
+{
+ InitParameter(0, "Damping", "",
+ [](Cloth* cloth, physx::PxVec3 value) {cloth->setDamping(value); },
+ [](Cloth* cloth) {return cloth->getDamping(); },
+ physx::PxVec3(0.0f), physx::PxVec3(1.0f),
+ ParameterType::VEC3_SLIDER1MAX, true, true
+ ),
+ InitParameter(0, "Gravity", "",
+ [](Cloth* cloth, physx::PxVec3 value) {cloth->setGravity(value); },
+ [](Cloth* cloth) {return cloth->getGravity(); },
+ physx::PxVec3(-50.0f,-50.0f,-50.0f), physx::PxVec3(50.0f,50.0f,50.0f)
+ ),
+ InitParameter(0, "Solver frequency", "Number of solver iterations per second",
+ [](Cloth* cloth, float value) {cloth->setSolverFrequency(value); },
+ [](Cloth* cloth) {return cloth->getSolverFrequency(); },
+ 0.0f, 600.0f, true, false
+ ),
+
+ InitParameter(1, "Drag coefficient", "For the advanced wind model (non zero enables this feature which is expensive)",
+ [](Cloth* cloth, float value) {cloth->setDragCoefficient(value); },
+ [](Cloth* cloth) {return cloth->getDragCoefficient(); },
+ 0.0f, 1.0f, true, true
+ ),
+ InitParameter(1, "Lift coefficient", "For the advanced wind model (non zero enables this feature which is expensive)",
+ [](Cloth* cloth, float value) {cloth->setLiftCoefficient(value); },
+ [](Cloth* cloth) {return cloth->getLiftCoefficient(); },
+ 0.0f, 1.0f, true, true
+ ),
+ InitParameter(1, "Fluid density", "For the advanced wind model, can be used to",
+ [](Cloth* cloth, float value) {cloth->setLiftCoefficient(value); },
+ [](Cloth* cloth) {return cloth->getLiftCoefficient(); },
+ 0.0f, 10.0f, true, false
+ ),
+
+ InitParameter(2, "Linear inertia", "Amount of linear force from moving the local space to be applied",
+ [](Cloth* cloth, physx::PxVec3 value) {cloth->setLinearInertia(value); },
+ [](Cloth* cloth) {return cloth->getLinearInertia(); },
+ physx::PxVec3(0.0f), physx::PxVec3(1.0f),
+ ParameterType::VEC3_SLIDER1MAX
+ ),
+ InitParameter(2, "Angular inertia", "Amount of angular force from moving the local space to be applied",
+ [](Cloth* cloth, physx::PxVec3 value) {cloth->setAngularInertia(value); },
+ [](Cloth* cloth) {return cloth->getAngularInertia(); },
+ physx::PxVec3(0.0f), physx::PxVec3(1.0f),
+ ParameterType::VEC3_SLIDER1MAX
+ ),
+ InitParameter(2, "Centrifugal inertia", "Amount of centrifugal force from moving the local space to be applied",
+ [](Cloth* cloth, physx::PxVec3 value) {cloth->setCentrifugalInertia(value); },
+ [](Cloth* cloth) {return cloth->getCentrifugalInertia(); },
+ physx::PxVec3(0.0f), physx::PxVec3(1.0f),
+ ParameterType::VEC3_SLIDER1MAX
+ ),
+ InitParameter(2, "Linear drag", "Amount of drag form moving the local space to be applied",
+ [](Cloth* cloth, physx::PxVec3 value) {cloth->setLinearDrag(value); },
+ [](Cloth* cloth) {return cloth->getLinearDrag(); },
+ physx::PxVec3(0.0f), physx::PxVec3(1.0f),
+ ParameterType::VEC3_SLIDER1MAX, true, true
+ ),
+ InitParameter(2, "Angular drag", "Amount of drag form moving the local space to be applied",
+ [](Cloth* cloth, physx::PxVec3 value) {cloth->setAngularDrag(value); },
+ [](Cloth* cloth) {return cloth->getAngularDrag(); },
+ physx::PxVec3(0.0f), physx::PxVec3(1.0f),
+ ParameterType::VEC3_SLIDER1MAX, true, true
+ ),
+
+ InitParameter(3, "Scale", "Scale factor for tether length",
+ [](Cloth* cloth, float value) {cloth->setTetherConstraintScale(value); },
+ [](Cloth* cloth) {return cloth->getTetherConstraintScale(); },
+ 0.0f, 4.0f, true, false
+ ),
+ InitParameter(3, "Stiffness", "",
+ [](Cloth* cloth, float value) {cloth->setTetherConstraintStiffness(value); },
+ [](Cloth* cloth) {return cloth->getTetherConstraintStiffness(); },
+ 0.0f, 1.0f, true, true
+ ),
+
+ InitParameter(4, "Friction", "Friction on collision contacts with collision shapes",
+ [](Cloth* cloth, float value) {cloth->setFriction(value); },
+ [](Cloth* cloth) {return cloth->getFriction(); },
+ 0.0f, 2.0f
+ ),
+
+ InitParameter(4, "Motion constraint scale", "Scale factor for the length of the motion/distance constraints",
+ [](Cloth* cloth, float value) {cloth->setMotionConstraintScaleBias(value,cloth->getMotionConstraintBias()); },
+ [](Cloth* cloth) {return cloth->getMotionConstraintScale(); },
+ 0.0f, 4.0f, true, false
+ ),
+ InitParameter(4, "Motion constraint bias", "Additional length for the length of the motion/distance constraints",
+ [](Cloth* cloth, float value) {cloth->setMotionConstraintScaleBias(cloth->getMotionConstraintScale(), value); },
+ [](Cloth* cloth) {return cloth->getMotionConstraintBias(); },
+ 0.0f, 8.0f, false, false
+ ),
+ InitParameter(4, "Motion constraint stiffness", "How hard the constraint is enforced",
+ [](Cloth* cloth, float value) {cloth->setMotionConstraintStiffness(value); },
+ [](Cloth* cloth) {return cloth->getMotionConstraintStiffness(); },
+ 0.0f, 1.0f, true, true
+ ),
+
+ InitParameter(4, "Self collision radius", "Min distance between two particles within this cloth (expensive when set > 0)",
+ [](Cloth* cloth, float value) {cloth->setSelfCollisionDistance(value); },
+ [](Cloth* cloth) {return cloth->getSelfCollisionDistance(); },
+ 0.0f, 1.0f, true, false
+ ),
+ InitParameter(4, "Self collision stiffness", "How hard the constraint is enforced",
+ [](Cloth* cloth, float value) {cloth->setSelfCollisionStiffness(value); },
+ [](Cloth* cloth) {return cloth->getSelfCollisionStiffness(); },
+ 0.0f, 1.0f, true, true
+ ),
+
+ InitParameter(5, "Sleep threshold", "Maximum movement allowed for cloth to go to sleep",
+ [](Cloth* cloth, float value) {cloth->setSleepThreshold(value); },
+ [](Cloth* cloth) {return cloth->getSleepThreshold(); },
+ 0.0f, 1.0f
+ ),
+ InitParameter(5, "Stiffness frequency", "",
+ [](Cloth* cloth, float value) {cloth->setStiffnessFrequency(value); },
+ [](Cloth* cloth) {return cloth->getStiffnessFrequency(); },
+ 0.0f, 100.0f, true, false
+ ),
+
+/*
+ InitParameter(6, "Rest volume scale", "",
+ [](Cloth* cloth, float value) {cloth->setRestVolumesScale(value); },
+ [](Cloth* cloth) {return cloth->getRestVolumesScale(); },
+ 0.0f, 10.0f
+ ),
+ InitParameter(6, "Compression stiffness", "",
+ [](Cloth* cloth, float value) {cloth->setCompressionStiffness(value); },
+ [](Cloth* cloth) {return cloth->getCompressionStiffness(); },
+ 0.0f, 1.0f
+ ),
+ InitParameter(6, "Expansion stiffness", "",
+ [](Cloth* cloth, float value) {cloth->setExpansionStiffness(value); },
+ [](Cloth* cloth) {return cloth->getExpansionStiffness(); },
+ 0.0f, 1.0f
+ ),
+*/
+};
+
+int GetClothNumParameters()
+{
+ return (sizeof(sParameterList) / sizeof(Parameter));
+}
+Parameter const& GetClothParameterInfo(int id)
+{
+ return sParameterList[id];
+}
+
+int GetClothNumParameterCatagories()
+{
+ return (sizeof(sParameterCatagories) / sizeof(const char*));
+}
+const char* GetClothParameterCatagorieInfo(int id)
+{
+ return sParameterCatagories[id];
+}
+
+}
+}
+} \ No newline at end of file