aboutsummaryrefslogtreecommitdiff
path: root/NvCloth/samples/SampleBase/utils
diff options
context:
space:
mode:
authorMarijn Tamis <[email protected]>2017-04-28 14:19:07 +0200
committerMarijn Tamis <[email protected]>2017-04-28 14:19:07 +0200
commitb350eb5f4d44e8448115796144375d79438d74ae (patch)
tree8e102e8c28f45a1b87bd335ceee4f33c3d4ee7c2 /NvCloth/samples/SampleBase/utils
parentAdd visual samples. (diff)
downloadnvcloth-b350eb5f4d44e8448115796144375d79438d74ae.tar.xz
nvcloth-b350eb5f4d44e8448115796144375d79438d74ae.zip
NvCloth 1.1.0 Release. (22041545)
Diffstat (limited to 'NvCloth/samples/SampleBase/utils')
-rw-r--r--NvCloth/samples/SampleBase/utils/ClothMeshGenerator.cpp56
-rw-r--r--NvCloth/samples/SampleBase/utils/ClothMeshGenerator.h8
-rw-r--r--NvCloth/samples/SampleBase/utils/DebugLineRenderBuffer.cpp21
-rw-r--r--NvCloth/samples/SampleBase/utils/DebugLineRenderBuffer.h25
-rw-r--r--NvCloth/samples/SampleBase/utils/MeshGenerator.cpp545
-rw-r--r--NvCloth/samples/SampleBase/utils/MeshGenerator.h114
-rw-r--r--NvCloth/samples/SampleBase/utils/Utils.h26
7 files changed, 786 insertions, 9 deletions
diff --git a/NvCloth/samples/SampleBase/utils/ClothMeshGenerator.cpp b/NvCloth/samples/SampleBase/utils/ClothMeshGenerator.cpp
index d75bb25..49f9ada 100644
--- a/NvCloth/samples/SampleBase/utils/ClothMeshGenerator.cpp
+++ b/NvCloth/samples/SampleBase/utils/ClothMeshGenerator.cpp
@@ -17,9 +17,8 @@ void ClothMeshData::Clear()
mQuads.clear();
}
-void ClothMeshData::GeneratePlaneCloth(float width, float height, int segmentsX, int segmentsY, bool createQuads, physx::PxMat44 transform, bool alternatingDiagonals)
+void ClothMeshData::GeneratePlaneCloth(float width, float height, int segmentsX, int segmentsY, bool createQuads, physx::PxMat44 transform, bool alternatingDiagonals, int zigzag)
{
-
/*
GeneratePlaneCloth(x,y,2,2) generates:
@@ -61,14 +60,30 @@ GeneratePlaneCloth(x,y,2,2) generates:
{
for(int x = 0; x < segmentsX + 1; x++)
{
- mVertices[x + y * (segmentsX + 1)] = transform.transform(topLeft + physx::PxVec3( ((float)x / (float)segmentsX) * width,
- 0.f,
- ((float)y / (float)segmentsY) * height));
+ physx::PxVec3 pos;
+ switch(zigzag)
+ {
+ case 1:
+ pos = physx::PxVec3(((float)x / (float)segmentsX) * width,
+ sinf(y*0.5)/(float)segmentsY * height,
+ ((float)y / (float)segmentsY) * height);
+ break;
+ case 2:
+ pos = physx::PxVec3(((float)x / (float)segmentsX) * width,
+ ((float)(y&2) / (float)segmentsY) * height,
+ ((float)((y+1)&~1) / (float)segmentsY) * height);
+ default:
+ pos = physx::PxVec3(((float)x / (float)segmentsX) * width,
+ 0.f,
+ ((float)y / (float)segmentsY) * height);
+ }
+
+ mVertices[x + y * (segmentsX + 1)] = transform.transform(topLeft + pos);
+
mInvMasses[x + y * (segmentsX + 1)] = 1.0f;
- mMesh.vertices[x + y * (segmentsX + 1)].position = transform.transform(topLeft + physx::PxVec3(((float)x / (float)segmentsX) * width,
- 0.f,
- ((float)y / (float)segmentsY) * height));
+ mMesh.vertices[x + y * (segmentsX + 1)].position = transform.transform(topLeft + pos);
+
mMesh.vertices[x + y * (segmentsX + 1)].normal = transform.transform(physx::PxVec3(0.f, 1.f, 0.f));
mMesh.vertices[x + y * (segmentsX + 1)].uv = physx::PxVec2(uvOx + uvSx*(float)x / (float)segmentsX, uvOy + uvSy*(1.0f - (float)y / (float)segmentsY));
@@ -190,4 +205,29 @@ nv::cloth::ClothMeshDesc ClothMeshData::GetClothMeshDesc()
SimpleMesh ClothMeshData::GetRenderMesh()
{
return mMesh;
+}
+
+void ClothMeshData::Merge(const ClothMeshData& other)
+{
+ uint32_t firstVertex = (uint32_t)mVertices.size();
+ uint32_t firstTriangle = (uint32_t)mTriangles.size();
+ uint32_t firstQuad = (uint32_t)mQuads.size();
+
+ mVertices.insert(mVertices.end(), other.mVertices.begin(), other.mVertices.end());
+ mUvs.insert(mUvs.end(), other.mUvs.begin(), other.mUvs.end());
+ mInvMasses.insert(mInvMasses.end(), other.mInvMasses.begin(), other.mInvMasses.end());
+
+ mMesh.vertices.insert(mMesh.vertices.end(), mMesh.vertices.begin(), mMesh.vertices.end());
+
+ for(const auto& t : other.mTriangles)
+ {
+ mTriangles.push_back(t + firstVertex);
+ }
+ for(const auto& q : other.mQuads)
+ {
+ mQuads.push_back(q + firstVertex);
+ mMesh.indices.push_back(mQuads.back().a);
+ mMesh.indices.push_back(mQuads.back().b);
+ mMesh.indices.push_back(mQuads.back().c);
+ }
} \ No newline at end of file
diff --git a/NvCloth/samples/SampleBase/utils/ClothMeshGenerator.h b/NvCloth/samples/SampleBase/utils/ClothMeshGenerator.h
index 0f57230..d6cf0fd 100644
--- a/NvCloth/samples/SampleBase/utils/ClothMeshGenerator.h
+++ b/NvCloth/samples/SampleBase/utils/ClothMeshGenerator.h
@@ -24,6 +24,8 @@ struct ClothMeshData
Triangle(uint32_t _a, uint32_t _b, uint32_t _c) :
a(_a), b(_b), c(_c){}
uint32_t a, b, c;
+
+ Triangle operator+(uint32_t offset)const { return Triangle(a + offset, b + offset, c + offset); };
};
struct Quad
{
@@ -31,6 +33,8 @@ struct ClothMeshData
Quad(uint32_t _a, uint32_t _b, uint32_t _c, uint32_t _d) :
a(_a), b(_b), c(_c), d(_d){}
uint32_t a, b, c, d;
+
+ Quad operator+(uint32_t offset)const { return Quad(a + offset, b + offset, c + offset, d + offset); };
};
std::vector<physx::PxVec3> mVertices;
std::vector<physx::PxVec2> mUvs;
@@ -41,7 +45,7 @@ struct ClothMeshData
SimpleMesh mMesh;
void Clear();
- void GeneratePlaneCloth(float width, float height, int segmentsX, int segmentsY, bool createQuads = false, physx::PxMat44 transform = physx::PxIdentity, bool alternatingDiagonals = true);
+ void GeneratePlaneCloth(float width, float height, int segmentsX, int segmentsY, bool createQuads = false, physx::PxMat44 transform = physx::PxIdentity, bool alternatingDiagonals = true, int zigzag = 0);
void AttachClothPlaneByAngles(int segmentsX, int segmentsY, bool attachByWidth = true);
void AttachClothPlaneBySide(int segmentsX, int segmentsY, bool attachByWidth = true);
@@ -51,4 +55,6 @@ struct ClothMeshData
nv::cloth::ClothMeshDesc GetClothMeshDesc();
SimpleMesh GetRenderMesh();
+
+ void Merge(const ClothMeshData& other);
};
diff --git a/NvCloth/samples/SampleBase/utils/DebugLineRenderBuffer.cpp b/NvCloth/samples/SampleBase/utils/DebugLineRenderBuffer.cpp
new file mode 100644
index 0000000..72e60e8
--- /dev/null
+++ b/NvCloth/samples/SampleBase/utils/DebugLineRenderBuffer.cpp
@@ -0,0 +1,21 @@
+/*
+* Copyright (c) 2008-2017, NVIDIA CORPORATION. All rights reserved.
+*
+* NVIDIA CORPORATION and its licensors retain all intellectual property
+* and proprietary rights in and to this software, 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.
+*/
+
+#include "DebugLineRenderBuffer.h"
+
+void DebugLineRenderBuffer::addLine(physx::PxVec3 a, physx::PxVec3 b, unsigned int color)
+{
+ m_lines.push_back(PxDebugLine(a, b, color));
+}
+
+void DebugLineRenderBuffer::addLine(physx::PxMat44 t, physx::PxVec3 a, physx::PxVec3 b, unsigned int color)
+{
+ m_lines.push_back(PxDebugLine(t.transform(a), t.transform(b), color));
+} \ No newline at end of file
diff --git a/NvCloth/samples/SampleBase/utils/DebugLineRenderBuffer.h b/NvCloth/samples/SampleBase/utils/DebugLineRenderBuffer.h
new file mode 100644
index 0000000..ce800d5
--- /dev/null
+++ b/NvCloth/samples/SampleBase/utils/DebugLineRenderBuffer.h
@@ -0,0 +1,25 @@
+/*
+* Copyright (c) 2008-2017, NVIDIA CORPORATION. All rights reserved.
+*
+* NVIDIA CORPORATION and its licensors retain all intellectual property
+* and proprietary rights in and to this software, 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.
+*/
+
+#pragma once
+#include "DebugRenderBuffer.h"
+#include <foundation/PxVec3.h>
+#include <foundation/PxMat44.h>
+
+class DebugLineRenderBuffer : public DebugRenderBuffer
+{
+public:
+ void clear() { m_lines.clear(); }
+ void addLine(physx::PxVec3 a, physx::PxVec3 b, unsigned int color);
+ void addVector(physx::PxVec3 start, physx::PxVec3 vec, unsigned int color) { addLine(start, start + vec, color); }
+
+ void addLine(physx::PxMat44 t, physx::PxVec3 a, physx::PxVec3 b, unsigned int color);
+ void addVector(physx::PxMat44 t, physx::PxVec3 start, physx::PxVec3 vec, unsigned int color) { addLine(t, start, start + vec, color); }
+}; \ No newline at end of file
diff --git a/NvCloth/samples/SampleBase/utils/MeshGenerator.cpp b/NvCloth/samples/SampleBase/utils/MeshGenerator.cpp
new file mode 100644
index 0000000..857daed
--- /dev/null
+++ b/NvCloth/samples/SampleBase/utils/MeshGenerator.cpp
@@ -0,0 +1,545 @@
+
+
+#include "./MeshGenerator.h"
+#include <foundation/PxVec2.h>
+#include <utility>
+#include "utils/Utils.h"
+
+namespace MeshGenerator
+{
+
+void Polygon::triangulate(std::vector<Polygon>& out) const
+{
+ for(int i = 2; i < (int)mPoints.size(); i++)
+ {
+ out.push_back(Polygon(mPoints[0], mPoints[i - 1], mPoints[i]));
+ }
+}
+
+void Polygon::triangulate(std::vector<RenderVertex>& verts, std::vector<uint16_t>& indices) const
+{
+ physx::PxVec3 normal = calculateNormal();
+ for(int i = 2; i < (int)mPoints.size(); i++)
+ {
+ indices.push_back((uint16_t)verts.size());
+ verts.push_back(RenderVertex(mPoints[0].p,normal));
+ indices.push_back((uint16_t)verts.size());
+ verts.push_back(RenderVertex(mPoints[i - 1].p, normal));
+ indices.push_back((uint16_t)verts.size());
+ verts.push_back(RenderVertex(mPoints[i].p, normal));
+ }
+}
+
+void Polygon::triangulateWeld(std::vector<RenderVertex>& verts, std::vector<uint16_t>& indices) const
+{
+ auto addVertex = [&verts, &indices](RenderVertex v)
+ {
+ for(int i = 0; i < (int)verts.size(); i++)
+ {
+ if((verts[i].p - v.p).magnitudeSquared() < 0.001f)
+ {
+ return i;
+ }
+ }
+ verts.push_back(v);
+ return (uint16_t)verts.size()-1;
+ };
+
+ physx::PxVec3 weightedNormal = calculateNormal()*calculateArea();
+
+ for(int i = 2; i < (int)mPoints.size(); i++)
+ {
+ indices.push_back(addVertex(RenderVertex(mPoints[0].p, weightedNormal)));
+ indices.push_back(addVertex(RenderVertex(mPoints[i - 1].p, weightedNormal)));
+ indices.push_back(addVertex(RenderVertex(mPoints[i].p, weightedNormal)));
+ }
+}
+
+void Polygon::triangulateForCollision(std::vector<physx::PxVec3>& verts) const
+{
+ for(int i = 2; i < (int)mPoints.size(); i++)
+ {
+ verts.push_back(mPoints[0].p);
+ verts.push_back(mPoints[i - 1].p);
+ verts.push_back(mPoints[i].p);
+ }
+}
+
+physx::PxVec3 Polygon::calculateNormal() const
+{
+ physx::PxVec3 normal(0.0f, 0.0f, 0.0f);
+ for(int i = 2; i < (int)mPoints.size(); i++)
+ {
+ physx::PxVec3 p[3];
+ p[0] = mPoints[0].p;
+ p[1] = mPoints[i - 1].p;
+ p[2] = mPoints[i].p;
+ normal += (p[1] - p[0]).cross(p[2] - p[0]);
+ }
+ normal.normalize();
+ return normal;
+}
+
+float Polygon::calculateArea() const
+{
+ float doubleArea = 0.0f;
+ for(int i = 2; i < (int)mPoints.size(); i++)
+ {
+ physx::PxVec3 p[3];
+ p[0] = mPoints[0].p;
+ p[1] = mPoints[i - 1].p;
+ p[2] = mPoints[i].p;
+ doubleArea += (p[1] - p[0]).cross(p[2] - p[0]).magnitude();
+ }
+ return doubleArea*0.5f;
+}
+
+void Polygon::subdivideTriangle(std::vector<Polygon>& out) const
+{
+ if(!isTriangle())
+ return;
+
+ for(int i = 0; i < 3; i++)
+ {
+ out.push_back(Polygon(Point(mPoints[i].p), Point(0.5f*(mPoints[(i+1)%3].p + mPoints[i].p)), Point(0.5f*(mPoints[(i + 2) % 3].p + mPoints[i].p))));
+ }
+ out.push_back(Polygon(Point(0.5f*(mPoints[0].p + mPoints[1].p)), Point(0.5f*(mPoints[1].p + mPoints[2].p)), Point(0.5f*(mPoints[2].p + mPoints[0].p))));
+
+}
+
+float intersetcLinePlane(physx::PxVec3 a, physx::PxVec3 b, physx::PxVec4 plane)
+{
+ physx::PxVec3 planeNormal(plane.x, plane.y, plane.z);
+ float aprj = planeNormal.dot(a);
+ float bprj = planeNormal.dot(b);
+
+ return (-plane.w - aprj) / (bprj - aprj);
+}
+
+bool Polygon::pointPlaneSide(physx::PxVec3 p, physx::PxVec4 plane) const
+{
+ physx::PxVec3 planeNormal(plane.x, plane.y, plane.z);
+ return p.dot(planeNormal) + plane.w < 0;
+}
+
+void Polygon::clip(physx::PxVec4 plane, bool flip)
+{
+ if(mPoints.size() < 3)
+ return;
+
+ std::vector<Point> input = mPoints;
+ mPoints.clear();
+
+ Point S = input.back();
+ for(int pointIndex = 0; pointIndex < (int)input.size(); pointIndex++)
+ {
+ if(pointPlaneSide(input[pointIndex].p, plane) != flip)
+ {
+ if(pointPlaneSide(S.p, plane) == flip)
+ {
+ float w = intersetcLinePlane(S.p, input[pointIndex].p, plane);
+ mPoints.push_back(S * (1.0f - w) + input[pointIndex] * w);
+ }
+ mPoints.push_back(input[pointIndex]);
+ }
+ else if(pointPlaneSide(S.p, plane) != flip)
+ {
+ float w = intersetcLinePlane(S.p, input[pointIndex].p, plane);
+ mPoints.push_back(S * (1.0f - w) + input[pointIndex] * w);
+ }
+ S = input[pointIndex];
+ }
+}
+
+void Mesh::addConvexPolygon(physx::PxVec4 plane, physx::PxVec4* planes, uint32_t mask, bool flip)
+{
+ physx::PxVec3 t1, t2, normal;
+ normal.x = plane.x;
+ normal.y = plane.y;
+ normal.z = plane.z;
+ computeBasis(normal, &t1, &t2);
+ Polygon poly;
+ for(int i = 0; i < 4; i++)
+ {
+ float xTable[4] = {-1.0f, 1.0f, 1.0f, -1.0f};
+ float yTable[4] = {-1.0f, -1.0f, 1.0f, 1.0f};
+ poly.mPoints.push_back(normal*-plane.w + 200.0f*t1 * xTable[i] + 200.0f*t2 * yTable[i]);
+ //polyTexcoord.push_back(vec2(0.0f, 10.0f) * xTable[i] + vec2(10.0f, 0.0f) * yTable[i]);
+ }
+
+ for(int i = 0; i < 32; i++)
+ {
+ if((1 << i) & mask)
+ {
+ const physx::PxVec4 pl = planes[i];
+ poly.clip(pl, flip);
+ }
+ }
+
+ mPolygons.push_back(poly);
+}
+
+void Mesh::generateRenderBuffers(RenderVertex** vertices, uint16_t** indices, int* vertexCount, int* indexCount) const
+{
+ std::vector<RenderVertex> verts;
+ std::vector<uint16_t> inds;
+ verts.reserve(mPolygons.size()*3);
+ verts.reserve(inds.size()*3);
+
+ for(auto& p : mPolygons)
+ {
+ p.triangulate(verts, inds);
+ }
+
+ *vertices = new RenderVertex[verts.size()];
+ *indices = new uint16_t[inds.size()];
+
+ memcpy(*vertices, verts.data(), sizeof(RenderVertex)*verts.size());
+ memcpy(*indices, inds.data(), sizeof(uint16_t)*inds.size());
+ *vertexCount = (uint16_t)verts.size();
+ *indexCount = (uint16_t)inds.size();
+}
+
+void Mesh::generateSmoothRenderBuffers(RenderVertex** vertices, uint16_t** indices, int* vertexCount, int* indexCount) const
+{
+ std::vector<RenderVertex> verts;
+ std::vector<uint16_t> inds;
+ verts.reserve(mPolygons.size() * 3);
+ verts.reserve(inds.size() * 3);
+
+ for(auto& p : mPolygons)
+ {
+ p.triangulateWeld(verts, inds);
+ }
+
+ for(auto& v : verts)
+ {
+ v.n.normalize();
+ }
+
+ *vertices = new RenderVertex[verts.size()];
+ *indices = new uint16_t[inds.size()];
+
+ memcpy(*vertices, verts.data(), sizeof(RenderVertex)*verts.size());
+ memcpy(*indices, inds.data(), sizeof(uint16_t)*inds.size());
+ *vertexCount = (uint16_t)verts.size();
+ *indexCount = (uint16_t)inds.size();
+
+}
+
+int Mesh::generateTriangleList(physx::PxVec3** positions)
+{
+ std::vector<physx::PxVec3> verts;
+ verts.reserve(mPolygons.size() * 3);
+
+ for(auto& p : mPolygons)
+ {
+ p.triangulateForCollision(verts);
+ }
+
+ *positions = new physx::PxVec3[verts.size()];
+ memcpy(*positions, verts.data(), sizeof(physx::PxVec3)*verts.size());
+ return (int)verts.size();
+}
+
+void Mesh::applyTransfom(physx::PxMat44 transform)
+{
+ for(auto& trig : mPolygons)
+ for(auto& point : trig.mPoints)
+ {
+ point.p = transform.transform(point.p);
+ }
+}
+
+void Mesh::merge(const Mesh& mesh)
+{
+ mPolygons.insert(mPolygons.end(), mesh.mPolygons.begin(), mesh.mPolygons.end());
+}
+
+Mesh generateTetrahedron(float radius)
+{
+ Mesh mesh;
+ Point p[4];
+ for(int i = 0; i < 3; i++)
+ {
+ p[i] = Point(radius*physx::PxVec3(cosf((float)i / 3.0f*PxTwoPi), -sqrtf(2.0f / 3.0f)*0.5f*sqrtf(3), sinf((float)i / 3.0f*PxTwoPi)));
+ }
+ p[3] = Point(radius*physx::PxVec3(0, sqrtf(2.0f / 3.0f)*0.5f*sqrtf(3), 0));
+
+ mesh.mPolygons.push_back(Polygon(p[0], p[1], p[2]));
+ mesh.mPolygons.push_back(Polygon(p[3], p[1], p[0]));
+ mesh.mPolygons.push_back(Polygon(p[3], p[2], p[1]));
+ mesh.mPolygons.push_back(Polygon(p[3], p[0], p[2]));
+
+ return mesh;
+}
+
+Mesh generateIcosahedron(float radius, int subdivisions)
+{
+ Mesh mesh;
+ Point p[12];
+
+ //generate positions
+ float goldenRatio = (1.0f + sqrtf(5.0f)) * 0.5f;
+ float scale = radius / physx::PxVec2(goldenRatio, 1.0f).magnitude();
+ for(int j = 0; j < 3; j++)
+ for(int i = 0; i < 4; i++)
+ {
+ float signA = i & 1 ? 1.0f : -1.0f;
+ float signB = i & 2 ? -1.0f : 1.0f;
+ physx::PxVec3 point(signA, signB * goldenRatio, 0.0f);
+ p[i + 4 * j] = physx::PxVec3(point[j % 3], point[(j + 1) % 3], point[(j + 2) % 3]) * scale;
+ }
+
+ //generate triangles
+ uint16_t ti[20 * 3] =
+ {
+ 0, 7, 9,
+ 0, 9, 1,
+ 0, 1, 11,
+ 0, 11, 6,
+ 0, 6, 7,
+
+ 1, 9, 5,
+ 9, 7, 8,
+ 7, 6, 2,
+ 6, 11, 10,
+ 11, 1, 4,
+
+ 3, 5, 8,
+ 3, 8, 2,
+ 3, 2, 10,
+ 3, 10, 4,
+ 3, 4, 5,
+
+ 8, 5, 9,
+ 2, 8, 7,
+ 10, 2, 6,
+ 4, 10, 11,
+ 5, 4, 1
+ };
+
+ for(int i = 0; i < 20*3; i += 3)
+ {
+ mesh.mPolygons.push_back(Polygon(p[ti[i]], p[ti[i+1]], p[ti[i+2]]));
+ }
+
+ bool projectToSphere = subdivisions > 0;
+ while(subdivisions > 0)
+ {
+ subdivisions--;
+ Mesh sub;
+ for(auto& trig : mesh.mPolygons)
+ {
+ trig.subdivideTriangle(sub.mPolygons);
+ }
+ std::swap(sub.mPolygons, mesh.mPolygons);
+ }
+
+ if(projectToSphere)
+ {
+ for(auto& trig : mesh.mPolygons)
+ for(auto& point : trig.mPoints)
+ {
+ point.p = point.p.getNormalized() * radius;
+ }
+ }
+
+ return mesh;
+}
+
+Mesh generateCone(physx::PxVec4 a, physx::PxVec4 b, int segments, float grow, bool correctCone)
+{
+ Mesh mesh;
+
+ if(a.w < b.w)
+ std::swap(a, b);
+
+ physx::PxVec3 aCenter = a.getXYZ();
+ physx::PxVec3 bCenter = b.getXYZ();
+ float aRadius = a.w + grow;
+ float bRadius = b.w + grow;
+
+ physx::PxVec3 basis[3];
+ basis[2] = bCenter - aCenter;
+ basis[2].normalize();
+ computeBasis(basis[2], &basis[0], &basis[1]);
+
+ physx::PxVec3 pa = aCenter + aRadius*basis[0];
+ physx::PxVec3 pb = bCenter + bRadius*basis[0];
+ physx::PxVec3 dir = pb - pa;
+
+ physx::PxVec3 n = basis[2].cross(dir);
+ physx::PxVec3 n2 = dir.cross(n);
+ physx::PxVec3 focusPoint = aCenter + ((pa - aCenter).dot(n2)) / basis[2].dot(n2) * basis[2];
+
+ if(correctCone)
+ {
+ {
+ float focusDistance = (focusPoint - aCenter).magnitude();
+ physx::PxVec3 cCenter = (focusPoint + aCenter)*0.5f;
+ float cRadius = focusDistance*0.5f;
+ float d = (aCenter - cCenter).magnitude();
+ float a = (aRadius*aRadius - cRadius*cRadius + d*d) / (2.0f*d);
+ float h = sqrtf(aRadius*aRadius - a*a);
+ physx::PxVec3 P3 = aCenter + a * (cCenter - aCenter) / d;
+
+ aCenter = P3;
+ aRadius = h;
+ }
+
+ {
+ float focusDistance = (focusPoint - bCenter).magnitude();
+ physx::PxVec3 cCenter = (focusPoint + bCenter)*0.5f;
+ float cRadius = focusDistance*0.5f;
+ float d = (bCenter - cCenter).magnitude();
+ float a = (bRadius*bRadius - cRadius*cRadius + d*d) / (2.0f*d);
+ float h = sqrtf(bRadius*bRadius - a*a);
+ physx::PxVec3 P3 = bCenter + a * (cCenter - bCenter) / d;
+
+ bCenter = P3;
+ bRadius = h;
+ }
+ }
+
+
+ for(int i = 0; i < segments; i++)
+ {
+ float angle1 = (float)i / (float)segments*physx::PxTwoPi;
+ float angle2 = (float)(i+1) / (float)segments*physx::PxTwoPi;
+
+ Polygon p;
+ p.addPoints(Point(aCenter + (cosf(angle1)*basis[0] + sinf(angle1)*basis[1])*aRadius));
+ p.addPoints(Point(aCenter + (cosf(angle2)*basis[0] + sinf(angle2)*basis[1])*aRadius));
+ p.addPoints(Point(bCenter + (cosf(angle2)*basis[0] + sinf(angle2)*basis[1])*bRadius));
+ p.addPoints(Point(bCenter + (cosf(angle1)*basis[0] + sinf(angle1)*basis[1])*bRadius));
+
+ mesh.mPolygons.push_back(p);
+ }
+
+ return mesh;
+}
+
+Mesh generateCollisionConvex(physx::PxVec4* planes, uint32_t mask, float grow, bool flip)
+{
+ Mesh mesh;
+ if(grow != 0.0f)
+ {
+ physx::PxVec4* grownPlanes = new physx::PxVec4[32];
+ for(int i = 0; i < 32; i++)
+ {
+ if((1 << i) & mask)
+ {
+ grownPlanes[i] = planes[i];
+ grownPlanes[i].w -= grow;
+ }
+ }
+ planes = grownPlanes;
+ }
+
+ for(int i = 0; i < 32; i++)
+ {
+ if((1 << i) & mask)
+ mesh.addConvexPolygon(planes[i], planes, mask ^ (1 << i), flip);
+ }
+
+ if(grow != 0.0f)
+ delete[] planes;
+
+ return mesh;
+}
+
+Mesh generateCollisionCapsules(physx::PxVec4* spheres, int sphereCount, uint32_t* indices, int indexCount, float grow)
+{
+ Mesh finalMesh;
+ for(int i = 0; i < sphereCount; i++)
+ {
+ Mesh sphere = generateIcosahedron(spheres[i].w+ grow, 4);
+ sphere.applyTransfom(physx::PxTransform(spheres[i].getXYZ()));
+ finalMesh.merge(sphere);
+ }
+
+ for(int i = 0; i < indexCount; i += 2)
+ {
+ finalMesh.merge(generateCone(spheres[indices[i]], spheres[indices[i + 1]], 32, grow, true));
+ }
+
+ return finalMesh;
+}
+
+uint32_t generateConvexPolyhedronPlanes(int segmentsX, int segmentsY, physx::PxVec3 center, float radius, std::vector<physx::PxVec4>* planes)
+{
+ int offset = 0;
+ if(planes)
+ {
+ planes->reserve(planes->size() + segmentsX*segmentsY);
+ offset = (int)planes->size();
+ }
+
+ segmentsY += 1;
+ for(int i = 1; i < segmentsY; i++)
+ {
+ float angleY = (float)i / (float)segmentsY * physx::PxPi + physx::PxPiDivTwo;
+ for(int j = 0; j < segmentsX; j++)
+ {
+ float angleX = (float)j / (float)segmentsX * physx::PxTwoPi;
+
+ physx::PxVec3 nx(cosf(angleX), 0.0f, sinf(angleX));
+ physx::PxVec3 n = cosf(angleY) * nx + sinf(angleY)*physx::PxVec3(0.0f, 1.0f, 0.0f);
+
+ physx::PxVec3 p = n*radius + center;
+
+ if(planes) planes->push_back(constructPlaneFromPointNormal(p, n));
+ }
+ }
+ uint64_t shift = (segmentsX * (segmentsY - 1) + offset);
+ uint64_t excludeMask = (((uint64_t)1 << offset) - 1);
+ uint64_t mask = (((uint64_t)1 << shift) - 1) & ~excludeMask;
+ return static_cast<uint32_t>(mask);
+}
+
+MeshGeneratorRenderMesh::MeshGeneratorRenderMesh(const Mesh mesh)
+{
+ RenderVertex* vertices;
+ uint16_t* indices;
+ int vertexCount, indexCount;
+ mesh.generateRenderBuffers(&vertices, &indices, &vertexCount, &indexCount);
+
+ std::vector<D3D11_INPUT_ELEMENT_DESC> layout;
+ layout.push_back({"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0});
+ layout.push_back({"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0});
+
+ initialize(vertices, (uint32_t)vertexCount, sizeof(RenderVertex), layout, indices, indexCount);
+
+ delete vertices;
+ delete indices;
+}
+MeshGeneratorRenderMesh::~MeshGeneratorRenderMesh()
+{
+
+}
+
+MeshGeneratorRenderMeshSmooth::MeshGeneratorRenderMeshSmooth(const Mesh mesh)
+{
+ RenderVertex* vertices;
+ uint16_t* indices;
+ int vertexCount, indexCount;
+ mesh.generateSmoothRenderBuffers(&vertices, &indices, &vertexCount, &indexCount);
+
+ std::vector<D3D11_INPUT_ELEMENT_DESC> layout;
+ layout.push_back({"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0});
+ layout.push_back({"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0});
+
+ initialize(vertices, (uint32_t)vertexCount, sizeof(RenderVertex), layout, indices, indexCount);
+
+ delete vertices;
+ delete indices;
+}
+MeshGeneratorRenderMeshSmooth::~MeshGeneratorRenderMeshSmooth()
+{
+
+}
+
+
+
+} \ No newline at end of file
diff --git a/NvCloth/samples/SampleBase/utils/MeshGenerator.h b/NvCloth/samples/SampleBase/utils/MeshGenerator.h
new file mode 100644
index 0000000..4f4b0c9
--- /dev/null
+++ b/NvCloth/samples/SampleBase/utils/MeshGenerator.h
@@ -0,0 +1,114 @@
+/*
+* Copyright (c) 2008-2017, NVIDIA CORPORATION. All rights reserved.
+*
+* NVIDIA CORPORATION and its licensors retain all intellectual property
+* and proprietary rights in and to this software, 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.
+*/
+
+#ifndef MESH_GENERATOR_H
+#define MESH_GENERATOR_H
+
+#include <vector>
+#include "renderer/CustomRenderMesh.h"
+#include <foundation/PxVec3.h>
+
+namespace MeshGenerator
+{
+
+struct Point
+{
+ Point(){}
+ Point(physx::PxVec3 _p):p(_p){}
+ physx::PxVec3 p;
+
+ Point operator*(float f) const { return Point(p*f); }
+ Point operator+(Point pt) const { return Point(p+pt.p); }
+};
+
+struct RenderVertex
+{
+ RenderVertex() {}
+ RenderVertex(physx::PxVec3 _p, physx::PxVec3 _n):p(_p),n(_n) {}
+ physx::PxVec3 p;
+ physx::PxVec3 n;
+};
+
+struct Polygon
+{
+ Polygon() {}
+ template<typename P, typename... Args> Polygon(P p1, P p2, P p3, Args... args)
+ {
+ addPoints(p1, p2, p3, args...);
+ }
+
+ std::vector<Point> mPoints;
+
+ bool isTriangle()const { return mPoints.size() == 3; }
+
+ template<typename P, typename... Args> void addPoints(P p, Args... args)
+ {
+ mPoints.push_back(p);
+ addPoints(args...);
+ }
+ template<typename P> void addPoints(P p)
+ {
+ mPoints.push_back(p);
+ }
+
+ void triangulate(std::vector<Polygon>& out) const;
+ void triangulate(std::vector<RenderVertex>& verts, std::vector<uint16_t>& indices) const;
+ void triangulateWeld(std::vector<RenderVertex>& verts, std::vector<uint16_t>& indices) const; //normalize normals afterwards
+ void triangulateForCollision(std::vector<physx::PxVec3>& verts) const;
+ physx::PxVec3 calculateNormal() const;
+ float calculateArea() const;
+ void subdivideTriangle(std::vector<Polygon>& out) const;
+ bool Polygon::pointPlaneSide(physx::PxVec3 p, physx::PxVec4 plane) const;
+ void clip(physx::PxVec4 plane, bool flip = false);
+};
+
+struct Mesh
+{
+ std::vector<Polygon> mPolygons;
+
+ bool isTriangleMesh()const { bool b = true; for(const auto& p : mPolygons) { b = b && p.isTriangle(); } return b; }
+
+ void addConvexPolygon(physx::PxVec4 plane, physx::PxVec4* planes, uint32_t mask, bool flip);
+
+ void generateRenderBuffers(RenderVertex** vertices, uint16_t** indices, int* vertexCount, int* indexCount) const;
+ void generateSmoothRenderBuffers(RenderVertex** vertices, uint16_t** indices, int* vertexCount, int* indexCount) const;
+ int generateTriangleList(physx::PxVec3** positions);
+
+ void applyTransfom(physx::PxMat44 transform);
+
+ void merge(const Mesh& mesh);
+};
+
+Mesh generateTetrahedron(float radius);
+Mesh generateIcosahedron(float radius, int subdivisions);
+Mesh generateCone(physx::PxVec4 a, physx::PxVec4 b, int segments, float grow, bool correctCone);
+Mesh generateCollisionConvex(physx::PxVec4* planes, uint32_t mask, float grow, bool flip);
+Mesh generateCollisionCapsules(physx::PxVec4* spheres, int sphereCount, uint32_t* indices, int indexCount, float grow);
+
+uint32_t generateConvexPolyhedronPlanes(int segmentsX, int segmentsY, physx::PxVec3 center, float radius, std::vector<physx::PxVec4>* planes);
+
+class MeshGeneratorRenderMesh : public CustomRenderMesh
+{
+public:
+ MeshGeneratorRenderMesh(const Mesh mesh);
+ virtual ~MeshGeneratorRenderMesh();
+};
+
+class MeshGeneratorRenderMeshSmooth : public CustomRenderMesh
+{
+public:
+ MeshGeneratorRenderMeshSmooth(const Mesh mesh);
+ virtual ~MeshGeneratorRenderMeshSmooth();
+};
+
+
+};
+
+#endif \ No newline at end of file
diff --git a/NvCloth/samples/SampleBase/utils/Utils.h b/NvCloth/samples/SampleBase/utils/Utils.h
index 5e84e8e..1a5d5ee 100644
--- a/NvCloth/samples/SampleBase/utils/Utils.h
+++ b/NvCloth/samples/SampleBase/utils/Utils.h
@@ -3,6 +3,8 @@
#include <DeviceManager.h>
#include <assert.h>
+#include <foundation/PxVec3.h>
+#include <foundation/PxVec4.h>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -80,8 +82,32 @@ static const char* strext(const char* str)
return ext;
}
+//Math utilities
static inline float lerp(float a, float b, float t) { return a + (b - a) * t; }
+/** returns a PxVec4 containing [x,y,z,d] for plane equation ax + by + cz + d = 0.
+* Where plane contains p and has normal n.
+*/
+inline physx::PxVec4 constructPlaneFromPointNormal(physx::PxVec3 p, physx::PxVec3 n)
+{
+ n.normalize();
+ return physx::PxVec4(n, -p.dot(n));
+}
+
+/** 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);
+}
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////