aboutsummaryrefslogtreecommitdiff
path: root/NvCloth/samples/SampleBase/utils
diff options
context:
space:
mode:
authorMarijn Tamis <[email protected]>2018-05-03 18:22:48 +0200
committerMarijn Tamis <[email protected]>2018-05-03 18:22:48 +0200
commitca32c59a58d37c1822e185a2d5f3d0d3e8943593 (patch)
treeb06b9eec03f34344ef8fc31aa147b2714d3962ee /NvCloth/samples/SampleBase/utils
parentForced rename of platform folders in cmake dir. Git didn't pick this up before. (diff)
downloadnvcloth-ca32c59a58d37c1822e185a2d5f3d0d3e8943593.tar.xz
nvcloth-ca32c59a58d37c1822e185a2d5f3d0d3e8943593.zip
NvCloth 1.1.4 Release. (24070740)
Diffstat (limited to 'NvCloth/samples/SampleBase/utils')
-rw-r--r--NvCloth/samples/SampleBase/utils/AnimatedModelUtilities.cpp102
-rw-r--r--NvCloth/samples/SampleBase/utils/AnimatedModelUtilities.h26
-rw-r--r--NvCloth/samples/SampleBase/utils/ClothMeshGenerator.cpp217
-rw-r--r--NvCloth/samples/SampleBase/utils/ClothMeshGenerator.h21
-rw-r--r--NvCloth/samples/SampleBase/utils/DataStream.cpp67
-rw-r--r--NvCloth/samples/SampleBase/utils/DataStream.h72
-rw-r--r--NvCloth/samples/SampleBase/utils/JobManager.cpp19
-rw-r--r--NvCloth/samples/SampleBase/utils/JobManager.h30
-rw-r--r--NvCloth/samples/SampleBase/utils/MeshGenerator.cpp353
-rw-r--r--NvCloth/samples/SampleBase/utils/MeshGenerator.h9
10 files changed, 837 insertions, 79 deletions
diff --git a/NvCloth/samples/SampleBase/utils/AnimatedModelUtilities.cpp b/NvCloth/samples/SampleBase/utils/AnimatedModelUtilities.cpp
new file mode 100644
index 0000000..9bb15f8
--- /dev/null
+++ b/NvCloth/samples/SampleBase/utils/AnimatedModelUtilities.cpp
@@ -0,0 +1,102 @@
+/*
+* 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 "DataStream.h"
+#include "renderer/Model.h"
+#include "scene/Scene.h"
+#include "utils/DebugLineRenderBuffer.h"
+#include <map>
+
+bool saveBoneCapsuleData(std::string filepath, Model* model,
+ std::vector<physx::PxVec4>& sphereOffsets, std::vector<uint32_t>& activeSpheres, std::vector<uint32_t>& capsuleNodes)
+{
+ DataStream stream;
+ uint32_t sphereOffsetCount = (uint32_t)sphereOffsets.size();
+ stream.write(sphereOffsetCount);
+ for(int i = 0; i < (int)sphereOffsets.size(); i++)
+ {
+ stream.write(std::string(model->getNodeName(i)));
+ stream.write(sphereOffsets[i]);
+ }
+ uint32_t activeSphereCount = (uint32_t)activeSpheres.size();
+ stream.write(activeSphereCount);
+ for(int i = 0; i < (int)activeSpheres.size(); i++)
+ {
+ stream.write(activeSpheres[i]);
+ }
+ uint32_t capsuleNodeCount = (uint32_t)capsuleNodes.size();
+ stream.write(capsuleNodeCount);
+ for(int i = 0; i < (int)capsuleNodes.size(); i++)
+ {
+ stream.write(capsuleNodes[i]);
+ }
+
+ stream.saveToFile(filepath.c_str());
+ return true;
+}
+
+bool loadBoneCapsuleData(std::string filepath, Model* model,
+ std::vector<physx::PxVec4>& sphereOffsets, std::vector<uint32_t>& activeSpheres, std::vector<uint32_t>& capsuleNodes)
+{
+ if(!DataStream::fileExists(filepath.c_str()))
+ return false;
+
+ assert(sphereOffsets.size() == model->getNodeCount());
+
+ DataStream stream(filepath.c_str());
+ std::map<int, int> fileNodeIdToModelNodeId;
+ uint32_t sphereOffsetCount = stream.read<uint32_t>();
+ for(int i = 0; i < (int)sphereOffsetCount; i++)
+ {
+ auto nodeName = stream.read<std::string>();
+ int modelNode = model->getNodeIdByNameWithErrorCode(nodeName);
+ fileNodeIdToModelNodeId[i] = modelNode;
+ if(modelNode == -1)
+ {
+ stream.read<physx::PxVec4>();
+ printf("Warning: node [%d] \"%s\" not found in model (%s)\n", i, nodeName.c_str(), filepath.c_str());
+ continue;
+ }
+ sphereOffsets[modelNode] = stream.read<physx::PxVec4>();
+ }
+ activeSpheres.resize(stream.read<uint32_t>());
+ for(int i = 0; i < (int)activeSpheres.size(); i++)
+ {
+ int fileNode = stream.read<uint32_t>();
+ if(fileNodeIdToModelNodeId[fileNode] == -1)
+ continue;
+ activeSpheres[i] = fileNodeIdToModelNodeId[fileNode];
+ }
+ capsuleNodes.resize(stream.read<uint32_t>());
+ for(int i = 0; i < (int)capsuleNodes.size(); i++)
+ {
+ int fileNode = stream.read<uint32_t>();
+ if(fileNodeIdToModelNodeId[fileNode] == -1)
+ continue;
+ capsuleNodes[i] = fileNodeIdToModelNodeId[fileNode];
+ }
+ return true;
+}
+
+void renderBoneLines(Scene* scene, Model* model, ModelInstance* instance, physx::PxMat44 transform, float scale)
+{
+ DebugLineRenderBuffer* dbl = scene->getSceneController()->getDebugLineRenderBuffer();
+
+ //Render bone lines
+ model->traverseNodes([&transform, scale, instance, dbl](int nodeId, int parrentId)
+ {
+ physx::PxVec3 a = instance->mNodes[parrentId].mTransform.transform(physx::PxVec3(0.0f, 0.0f, 0.0f));
+ physx::PxVec3 b = instance->mNodes[nodeId].mTransform.transform(physx::PxVec3(0.0f, 0.0f, 0.0f));
+ a = transform.transform(a * scale);
+ b = transform.transform(b * scale);
+ dbl->addLine(a, b, 0xFFFFFFFF);
+ });
+} \ No newline at end of file
diff --git a/NvCloth/samples/SampleBase/utils/AnimatedModelUtilities.h b/NvCloth/samples/SampleBase/utils/AnimatedModelUtilities.h
new file mode 100644
index 0000000..efe04b2
--- /dev/null
+++ b/NvCloth/samples/SampleBase/utils/AnimatedModelUtilities.h
@@ -0,0 +1,26 @@
+/*
+* 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 <vector>
+#include <string>
+#include <PxVec4.h>
+#include <PxVec3.h>
+#include <PxMat44.h>
+class Model;
+class Scene;
+
+bool saveBoneCapsuleData(std::string filepath, Model* model,
+ std::vector<physx::PxVec4>& sphereOffsets, std::vector<uint32_t>& activeSpheres, std::vector<uint32_t>& capsuleNodes);
+
+bool loadBoneCapsuleData(std::string filepath, Model* model,
+ std::vector<physx::PxVec4>& sphereOffsets, std::vector<uint32_t>& activeSpheres, std::vector<uint32_t>& capsuleNodes);
+
+void renderBoneLines(Scene* scene, Model* model, ModelInstance* instance, physx::PxMat44 transform = physx::PxMat44(physx::PxIdentity), float scale = 1.0f); \ No newline at end of file
diff --git a/NvCloth/samples/SampleBase/utils/ClothMeshGenerator.cpp b/NvCloth/samples/SampleBase/utils/ClothMeshGenerator.cpp
index 495ba15..a0c0d3a 100644
--- a/NvCloth/samples/SampleBase/utils/ClothMeshGenerator.cpp
+++ b/NvCloth/samples/SampleBase/utils/ClothMeshGenerator.cpp
@@ -10,6 +10,25 @@
#include "ClothMeshGenerator.h"
+#include "PsMathUtils.h"
+
+#include <fstream>
+#include <iterator>
+#include <algorithm>
+#include <assert.h>
+
+namespace
+{
+ template<typename T>
+ std::vector<T> readValuesFromFile(const std::string& path)
+ {
+ std::ifstream inputFile(path);
+ std::vector<T> data{ std::istream_iterator<T>{inputFile}, { } };
+ return std::move(data);
+ }
+} // end of anonymous namespace
+
+
void ClothMeshData::Clear()
{
mVertices.clear();
@@ -34,8 +53,6 @@ GeneratePlaneCloth(x,y,2,2) generates:
*/
-// Submesh submesh;
-
Clear();
mVertices.resize((segmentsX + 1) * (segmentsY + 1));
mInvMasses.resize((segmentsX + 1) * (segmentsY + 1));
@@ -144,6 +161,90 @@ GeneratePlaneCloth(x,y,2,2) generates:
}
}
+void ClothMeshData::GenerateCylinderWave(float radiusTop, float radiusBottom, float height, float frequency, float ampitudeTop, float ampitudeBottom, int segmentsX, int segmentsY, physx::PxMat44 transform, bool attachTop, bool attachBottom, bool createQuads, int missingXsegments)
+{
+ Clear();
+ int particleXsegments = segmentsX - std::max(0, missingXsegments - 1);
+ int triangleXsegments = segmentsX - missingXsegments;
+ assert(missingXsegments < segmentsX);
+ mVertices.resize((particleXsegments + 0) * (segmentsY + 1));
+ mInvMasses.resize((particleXsegments + 0) * (segmentsY + 1));
+ mTriangles.resize(triangleXsegments * segmentsY * 2);
+ if (createQuads)
+ mQuads.resize(triangleXsegments * segmentsY);
+
+ mMesh.vertices.resize(mVertices.size());
+ mMesh.indices.resize(3 * mTriangles.size());
+
+ float slopeX;
+ float slopeY;
+ {
+ float y = height;
+ float x = radiusBottom - radiusTop;
+ float l = sqrtf(x*x + y*y);
+ slopeY = x / l;
+ slopeX = y / l;
+ }
+
+ // Vertices
+ for (int y = 0; y < segmentsY + 1; y++)
+ {
+ float h = height - (float)y / (float)segmentsY * height - 0.5f*height;
+ float ynorm = (float)y / (float)(segmentsY - 1);
+ float w = ynorm;
+ float r = radiusBottom * w + (1.0f - w) * radiusTop;
+ for (int x = 0; x < particleXsegments; x++)
+ {
+ float theta = (float)x / (float)segmentsX * physx::PxTwoPi;
+ float rw = r + cosf(frequency*theta)*(ampitudeBottom * w + (1.0f - w) * ampitudeTop);
+ mVertices[x + y * particleXsegments] = transform.transform(physx::PxVec3(sinf(theta)*rw, h, cosf(theta)*rw));
+ mInvMasses[x + y * particleXsegments] = (y == 0 && attachTop || y == segmentsY && attachBottom) ? 0.0f : 1.0f;
+
+ mMesh.vertices[x + y * particleXsegments].position = mVertices[x + y * particleXsegments];
+ mMesh.vertices[x + y * particleXsegments].uv = physx::PxVec2((float)x / (float)particleXsegments, (float)y / (float)segmentsY);
+ // Not the correct normal, but we recalculate it anyway when updating the cloth mesh
+ mMesh.vertices[x + y * particleXsegments].normal = physx::PxVec3(cosf(theta)*slopeX, slopeY, -sinf(theta)*slopeX);
+ }
+ }
+
+ if (createQuads)
+ {
+ // Quads
+ for (int y = 0; y < segmentsY; y++)
+ {
+ for (int x = 0; x < triangleXsegments; x++)
+ {
+ mQuads[(x + y * triangleXsegments)] = Quad((uint32_t)(x + 0) + (y + 0) * (particleXsegments),
+ (uint32_t)((x + 1) % particleXsegments) + (y + 0) * (particleXsegments),
+ (uint32_t)((x + 1) % particleXsegments) + (y + 1) * (particleXsegments),
+ (uint32_t)((x + 0) % particleXsegments) + (y + 1) * (particleXsegments));
+ }
+ }
+ }
+
+ // Triangles
+ for (int y = 0; y < segmentsY; y++)
+ {
+ for (int x = 0; x < triangleXsegments; x++)
+ {
+ mTriangles[(x + y * triangleXsegments) * 2 + 0] = Triangle((uint32_t)((x + 1) % particleXsegments) + (y + 1) * (particleXsegments),
+ (uint32_t)((x + 1) % particleXsegments) + (y + 0) * (particleXsegments),
+ (uint32_t)(x + 0) + (y + 0) * (particleXsegments));
+
+ mTriangles[(x + y * triangleXsegments) * 2 + 1] = Triangle((uint32_t)((x + 0) % particleXsegments) + (y + 1) * (particleXsegments),
+ (uint32_t)((x + 1) % particleXsegments) + (y + 1) * (particleXsegments),
+ (uint32_t)(x + 0) + (y + 0) * (particleXsegments));
+ }
+ }
+
+ for (int i = 0; i < (int)mTriangles.size(); i++)
+ {
+ mMesh.indices[3 * i + 0] = mTriangles[i].a;
+ mMesh.indices[3 * i + 1] = mTriangles[i].b;
+ mMesh.indices[3 * i + 2] = mTriangles[i].c;
+ }
+}
+
void ClothMeshData::AttachClothPlaneByAngles(int segmentsX, int segmentsY, bool attachByWidth)
{
for (int y = 0; y < segmentsY + 1; y++)
@@ -161,6 +262,105 @@ void ClothMeshData::AttachClothPlaneBySide(int segmentsX, int segmentsY, bool at
mInvMasses[x + y * (segmentsX + 1)] = 0.0f;
}
+void ClothMeshData::AttachClothUsingTopVertices(float thresholdY)
+{
+ int topVertexIndex = -1;
+ physx::PxVec3 topVertex(-1e30f, -1e30f, -1e30f);
+
+ for (int i = 0; i < (int)mVertices.size(); ++i)
+ {
+ if (mVertices[i].y > topVertex.y)
+ {
+ topVertex = mVertices[i];
+ topVertexIndex = i;
+ }
+ }
+ NV_CLOTH_ASSERT(topVertexIndex >= 0);
+
+ for (int i = 0; i < (int)mVertices.size(); ++i)
+ {
+ if (topVertex.y - mVertices[i].y < thresholdY)
+ {
+ mInvMasses[i] = 0.0f;
+ }
+ }
+}
+
+bool ClothMeshData::ReadClothFromFile(const std::string& verticesPath, const std::string& indicesPath, physx::PxMat44 transform)
+{
+ std::vector<float> verticesXYZ = readValuesFromFile<float>(verticesPath);
+ std::vector<uint32_t> indices = readValuesFromFile<uint32_t>(indicesPath);
+
+ if(verticesXYZ.size() < 3*3 || indices.size() < 3)
+ return false;
+
+ return InitializeFromData<float,uint32_t>(ToBoundedData(verticesXYZ), ToBoundedData(indices), transform);
+}
+
+template<typename PositionType, typename IndexType>
+bool ClothMeshData::InitializeFromData(nv::cloth::BoundedData positions, nv::cloth::BoundedData indices, physx::PxMat44 transform)
+{
+ if(positions.count < 3 || indices.count < 3)
+ return false;
+
+ NV_CLOTH_ASSERT(sizeof(PositionType) != physx::PxVec3 || positions.count % 3 == 0);
+ NV_CLOTH_ASSERT(indices.count % 3 == 0);
+
+ auto numVertices = (sizeof(PositionType) == sizeof(physx::PxVec3)) ? positions.count : positions.count / 3;
+ const auto numTriangles = indices.count / 3;
+
+ Clear();
+ mVertices.resize(numVertices);
+ mInvMasses.resize(numVertices);
+ mTriangles.resize(numTriangles);
+
+ // Quads not supported yet
+ //mQuads.resize(numTriangles / 2);
+
+ mMesh.vertices.resize(mVertices.size());
+ mMesh.indices.resize(3 * mTriangles.size());
+
+ for(int i = 0; i < (int)numVertices; ++i)
+ {
+ physx::PxVec3 pos;
+ if(sizeof(PositionType) == sizeof(physx::PxVec3))
+ pos = positions.at<physx::PxVec3>(i);
+ else
+ pos = physx::PxVec3(positions.at<float>(i * 3), positions.at<float>(i * 3 + 1), positions.at<float>(i * 3 + 2));
+
+ pos = transform.transform(pos);
+
+ mVertices[i] = pos;
+ mInvMasses[i] = 1.0f;
+
+ mMesh.vertices[i].position = pos;
+ mMesh.vertices[i].normal = transform.transform(physx::PxVec3(0.f, 1.f, 0.f)); // TODO
+ mMesh.vertices[i].uv = physx::PxVec2(0.0f, 0.0f); // TODO
+ }
+
+ for(int i = 0; i < (int)numTriangles; ++i)
+ {
+ mTriangles[i] = Triangle(
+ indices.at<IndexType>(i * 3),
+ indices.at<IndexType>(i * 3 + 1),
+ indices.at<IndexType>(i * 3 + 2)
+ );
+ }
+
+ for(int i = 0; i < (int)numTriangles; i++)
+ {
+ mMesh.indices[3 * i + 0] = mTriangles[i].a;
+ mMesh.indices[3 * i + 1] = mTriangles[i].b;
+ mMesh.indices[3 * i + 2] = mTriangles[i].c;
+ }
+
+ return true;
+}
+template bool ClothMeshData::InitializeFromData<float,uint16_t>(nv::cloth::BoundedData positions, nv::cloth::BoundedData indices, physx::PxMat44 transform);
+template bool ClothMeshData::InitializeFromData<float,uint32_t>(nv::cloth::BoundedData positions, nv::cloth::BoundedData indices, physx::PxMat44 transform);
+template bool ClothMeshData::InitializeFromData<physx::PxVec3,uint16_t>(nv::cloth::BoundedData positions, nv::cloth::BoundedData indices, physx::PxMat44 transform);
+template bool ClothMeshData::InitializeFromData<physx::PxVec3,uint32_t>(nv::cloth::BoundedData positions, nv::cloth::BoundedData indices, physx::PxMat44 transform);
+
void ClothMeshData::SetInvMasses(float invMass)
{
// Doesn't modify attached vertices
@@ -178,17 +378,6 @@ void ClothMeshData::SetInvMassesFromDensity(float density)
mInvMasses[i] = 1.f / density;
}
-template <typename T>
-nv::cloth::BoundedData ToBoundedData(T& vector)
-{
- nv::cloth::BoundedData d;
- d.data = &vector[0];
- d.stride = sizeof(vector[0]);
- d.count = (physx::PxU32)vector.size();
-
- return d;
-}
-
nv::cloth::ClothMeshDesc ClothMeshData::GetClothMeshDesc()
{
nv::cloth::ClothMeshDesc d;
@@ -218,7 +407,7 @@ void ClothMeshData::Merge(const ClothMeshData& other)
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());
+ mMesh.vertices.insert(mMesh.vertices.end(), other.mMesh.vertices.begin(), other.mMesh.vertices.end());
for(const auto& t : other.mTriangles)
{
diff --git a/NvCloth/samples/SampleBase/utils/ClothMeshGenerator.h b/NvCloth/samples/SampleBase/utils/ClothMeshGenerator.h
index 1db4115..a765fee 100644
--- a/NvCloth/samples/SampleBase/utils/ClothMeshGenerator.h
+++ b/NvCloth/samples/SampleBase/utils/ClothMeshGenerator.h
@@ -18,6 +18,17 @@
struct ClothMeshData
{
+ template <typename T>
+ static nv::cloth::BoundedData ToBoundedData(T& vector)
+ {
+ nv::cloth::BoundedData d;
+ d.data = &vector[0];
+ d.stride = sizeof(vector[0]);
+ d.count = (physx::PxU32)vector.size();
+
+ return d;
+ }
+
struct Triangle
{
Triangle(){}
@@ -46,10 +57,18 @@ struct ClothMeshData
void Clear();
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 GenerateCylinderWave(float radiusTop, float radiusBottom, float height, float frequency, float ampitudeTop, float ampitudeBottom, int segmentsX, int segmentsY, physx::PxMat44 transform = physx::PxIdentity, bool attachTop = false, bool attachBottom = false, bool createQuads = false, int missingXsegments = 0);
void AttachClothPlaneByAngles(int segmentsX, int segmentsY, bool attachByWidth = true);
void AttachClothPlaneBySide(int segmentsX, int segmentsY, bool attachByWidth = true);
+ bool ReadClothFromFile(const std::string& verticesPath, const std::string& indicesPath, physx::PxMat44 transform = physx::PxIdentity);
+
+ //positions as float (3 elements per position)
+ template<typename PositionType = float, typename IndexType = uint16_t>
+ bool InitializeFromData(nv::cloth::BoundedData positions, nv::cloth::BoundedData indices, physx::PxMat44 transform = physx::PxMat44(physx::PxIdentity));
+
+ void AttachClothUsingTopVertices(float thresholdY = 0.5f);
+
void SetInvMasses(float invMass);
void SetInvMassesFromDensity(float density); // Todo
diff --git a/NvCloth/samples/SampleBase/utils/DataStream.cpp b/NvCloth/samples/SampleBase/utils/DataStream.cpp
new file mode 100644
index 0000000..c61badc
--- /dev/null
+++ b/NvCloth/samples/SampleBase/utils/DataStream.cpp
@@ -0,0 +1,67 @@
+/*
+* 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 "DataStream.h"
+#include <fstream>
+
+DataStream::DataStream()
+ :
+ mReadPos(0),
+ mWritePos(0)
+{
+
+}
+DataStream::DataStream(void* data, int sizeInBytes)
+ :
+ mReadPos(0),
+ mWritePos(0)
+{
+ write(data, sizeInBytes);
+}
+DataStream::DataStream(const char* filename)
+ :
+ mReadPos(0),
+ mWritePos(0)
+{
+ std::ifstream file;
+ file.open(filename,std::ifstream::binary | std::ios::ate);
+ assert(file.good());
+
+ std::streamsize size = file.tellg();
+ mBuffer.resize(size);
+ file.seekg(0, std::ios::beg);
+ file.read(reinterpret_cast<char*>(mBuffer.data()), size);
+
+ mWritePos = size;
+ file.close();
+}
+
+bool DataStream::fileExists(const char* filename)
+{
+ std::ifstream file;
+ file.open(filename, std::ifstream::binary | std::ios::ate);
+ return file.good();
+}
+
+void DataStream::saveToFile(const char* filename)
+{
+ std::ofstream file(filename, std::fstream::binary | std::fstream::trunc);
+ file.write(reinterpret_cast<char*>(mBuffer.data()), mBuffer.size());
+ file.flush();
+ file.close();
+}
+
+void DataStream::write(void* data, int sizeInBytes)
+{
+ if((int)mBuffer.size() < mWritePos + sizeInBytes)
+ mBuffer.resize(mWritePos + sizeInBytes);
+ memcpy(&mBuffer[mWritePos], data, sizeInBytes);
+ mWritePos += sizeInBytes;
+} \ No newline at end of file
diff --git a/NvCloth/samples/SampleBase/utils/DataStream.h b/NvCloth/samples/SampleBase/utils/DataStream.h
new file mode 100644
index 0000000..c47da39
--- /dev/null
+++ b/NvCloth/samples/SampleBase/utils/DataStream.h
@@ -0,0 +1,72 @@
+/*
+* 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 <vector>
+#include <string>
+#include <assert.h>
+
+class DataStream
+{
+public:
+ DataStream();
+ DataStream(void* data, int sizeInBytes);
+ DataStream(const char* filename);
+ static bool fileExists(const char* filename);
+
+ void saveToFile(const char* filename);
+
+ template<typename T>
+ void write(T& value)
+ {
+ if(mBuffer.size() < mWritePos + sizeof(T))
+ mBuffer.resize(mWritePos + sizeof(T));
+ memcpy(&mBuffer[mWritePos], &value, sizeof(T));
+ mWritePos += sizeof(T);
+ }
+ template<>
+ void write<std::string>(std::string& value)
+ {
+ int len = (int)value.length();
+ if(mBuffer.size() < mWritePos + len + sizeof(int))
+ mBuffer.resize(mWritePos + len + sizeof(int));
+ memcpy(&mBuffer[mWritePos], &len, sizeof(int));
+ mWritePos += sizeof(int);
+ memcpy(&mBuffer[mWritePos], value.c_str(), len);
+ mWritePos += len;
+ }
+
+ void write(void* data, int sizeInBytes);
+
+ template<typename T>
+ T read()
+ {
+ T value;
+ assert(mReadPos + sizeof(T) <= mBuffer.size());
+ memcpy(&value, &mBuffer[mReadPos], sizeof(T));
+ mReadPos += sizeof(T);
+ return value;
+ }
+ template<>
+ std::string read<std::string>()
+ {
+ int len = read<int>();
+ std::string value;
+ value.resize(len);
+ assert(mReadPos + len < (int)mBuffer.size());
+ memcpy(&value[0], &mBuffer[mReadPos], len);
+ mReadPos += len;
+ return value;
+ }
+private:
+ std::vector<unsigned char> mBuffer;
+ int mReadPos;
+ int mWritePos;
+}; \ No newline at end of file
diff --git a/NvCloth/samples/SampleBase/utils/JobManager.cpp b/NvCloth/samples/SampleBase/utils/JobManager.cpp
index 2a18d1c..a1e8454 100644
--- a/NvCloth/samples/SampleBase/utils/JobManager.cpp
+++ b/NvCloth/samples/SampleBase/utils/JobManager.cpp
@@ -41,9 +41,10 @@ void Job::Execute()
else
ExecuteInternal();
- mFinishedLock.lock();
- mFinished = true;
- mFinishedLock.unlock();
+ {
+ std::lock_guard<std::mutex> lock(mFinishedLock);
+ mFinished = true;
+ }
mFinishedEvent.notify_one();
}
@@ -53,16 +54,19 @@ void Job::AddReference()
}
void Job::RemoveReference()
{
- if (0 == --mRefCount)
+ int refCount = --mRefCount;
+ if (0 == refCount)
{
mParent->Submit(this);
}
+ assert(refCount >= 0);
}
void Job::Wait()
{
std::unique_lock<std::mutex> lock(mFinishedLock);
mFinishedEvent.wait(lock, [this](){return mFinished;} );
+ lock.unlock();
return;
}
@@ -115,9 +119,12 @@ void MultithreadedSolverHelper::StartSimulation(float dt)
if (mSolver->getSimulationChunkCount() != mSimulationChunkJobs.size())
{
- mSimulationChunkJobs.resize(mSolver->getSimulationChunkCount(), Job());
+ mSimulationChunkJobs.resize(mSolver->getSimulationChunkCount(), JobDependency());
for (int j = 0; j < mSolver->getSimulationChunkCount(); j++)
- mSimulationChunkJobs[j].Initialize(mJobManager, [this, j](Job*) {mSolver->simulateChunk(j); mEndSimulationJob.RemoveReference(); });
+ {
+ mSimulationChunkJobs[j].Initialize(mJobManager, [this, j](Job*) {mSolver->simulateChunk(j); });
+ mSimulationChunkJobs[j].SetDependentJob(&mEndSimulationJob);
+ }
}
else
{
diff --git a/NvCloth/samples/SampleBase/utils/JobManager.h b/NvCloth/samples/SampleBase/utils/JobManager.h
index 648fa33..7bb88c9 100644
--- a/NvCloth/samples/SampleBase/utils/JobManager.h
+++ b/NvCloth/samples/SampleBase/utils/JobManager.h
@@ -23,8 +23,8 @@
#include <queue>
#include <atomic>
-#include <task/PxTaskManager.h>
-#include <task/PxTask.h>
+#include "task/PxTaskManager.h"
+#include "task/PxTask.h"
namespace nv
{
@@ -78,9 +78,10 @@ class Job
public:
Job() = default;
Job(const Job&);
+ ~Job() { mValid = false; }
void Initialize(JobManager* parent, std::function<void(Job*)> function = std::function<void(Job*)>(), int refcount = 1);
void Reset(int refcount = 1); //Call this before reusing a job that doesn't need to be reinitialized
- void Execute();
+ virtual void Execute();
void AddReference();
void RemoveReference();
void Wait(); //Block until job is finished
@@ -94,6 +95,22 @@ private:
bool mFinished;
std::mutex mFinishedLock;
std::condition_variable mFinishedEvent;
+ bool mValid = true;
+};
+
+//this Job is a dependency to another job
+class JobDependency : public Job
+{
+public:
+ void SetDependentJob(Job* job) { mDependendJob = job; }
+ virtual void Execute() override
+ {
+ auto dependendJob = mDependendJob;
+ Job::Execute();
+ dependendJob->RemoveReference();
+ }
+private:
+ Job* mDependendJob;
};
class JobManager
@@ -134,10 +151,11 @@ public:
function(i);*/
Job finalJob;
finalJob.Initialize(this, std::function<void(Job*)>(), count);
- Job jobs[count];
+ JobDependency jobs[count];
for(int j = 0; j < count; j++)
{
- jobs[j].Initialize(this, [j, &finalJob, function](Job*) {function(j); finalJob.RemoveReference(); });
+ jobs[j].Initialize(this, [j, &finalJob, function](Job*) {function(j); });
+ jobs[j].SetDependentJob(&finalJob);
jobs[j].RemoveReference();
}
finalJob.Wait();
@@ -166,7 +184,7 @@ public:
private:
Job mStartSimulationJob;
Job mEndSimulationJob;
- std::vector<Job> mSimulationChunkJobs;
+ std::vector<JobDependency> mSimulationChunkJobs;
float mDt;
diff --git a/NvCloth/samples/SampleBase/utils/MeshGenerator.cpp b/NvCloth/samples/SampleBase/utils/MeshGenerator.cpp
index 5541cc3..ccb3bf3 100644
--- a/NvCloth/samples/SampleBase/utils/MeshGenerator.cpp
+++ b/NvCloth/samples/SampleBase/utils/MeshGenerator.cpp
@@ -387,56 +387,28 @@ Mesh generateCone(physx::PxVec4 a, physx::PxVec4 b, int segments, float grow, bo
//sphere a with smaller radius
float cRadius = aRadius - bRadius;
- physx::PxVec3 cCenter = aCenter;
-
- //sphere in between the a and b
- physx::PxVec3 dCenter = (aCenter+bCenter)*0.5f;
- float dRadius = (aCenter - bCenter).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 - aCenter).getNormalized(); //offset direction
-
- physx::PxVec3 aPoint = aCenter + offset*aRadius;
- aCenter = (aPoint - aCenter).dot(basis[2])*basis[2] + aCenter;
- aRadius = (aPoint - aCenter).magnitude();
- physx::PxVec3 bPoint = bCenter + offset*bRadius;
- bCenter = (bPoint - aCenter).dot(basis[2])*basis[2] + aCenter;
- bRadius = (bPoint - bCenter).magnitude();
-
-
- }
-
- //old code, probably wrong
- /*
- physx::PxVec3 pa = aCenter + aRadius*basis[0];
- physx::PxVec3 pb = bCenter + bRadius*basis[0];
- physx::PxVec3 dir = pb - pa;
-
- //construct plane containing pa and pb, with normal perpendicular to basis[0]
- physx::PxVec3 n = basis[2].cross(dir);
- physx::PxVec3 n2 = dir.cross(n);
-
- //line plane intersection
- physx::PxVec3 focusPoint = aCenter + ((pa - aCenter).dot(n2)) / basis[2].dot(n2) * basis[2];
-
- {
- float focusDistance = (focusPoint - aCenter).magnitude();
- //make circle with center in mid point between focusPoint and aCenter
- physx::PxVec3 cCenter = (focusPoint + aCenter)*0.5f;
- float cRadius = focusDistance*0.5f;
-
- aCenter = IntersectSpheres(&aRadius, aCenter, aRadius, cCenter, cRadius);
+ if(cRadius > 0.00001)
+ {
+ physx::PxVec3 cCenter = aCenter;
+
+ //sphere in between the a and b
+ physx::PxVec3 dCenter = (aCenter + bCenter)*0.5f;
+ float dRadius = (aCenter - bCenter).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 - aCenter).getNormalized(); //offset direction
+
+ physx::PxVec3 aPoint = aCenter + offset*aRadius;
+ aCenter = (aPoint - aCenter).dot(basis[2])*basis[2] + aCenter;
+ aRadius = (aPoint - aCenter).magnitude();
+ physx::PxVec3 bPoint = bCenter + offset*bRadius;
+ bCenter = (bPoint - aCenter).dot(basis[2])*basis[2] + aCenter;
+ bRadius = (bPoint - bCenter).magnitude();
+ }
}
-
- {
- float focusDistance = (focusPoint - bCenter).magnitude();
- physx::PxVec3 cCenter = (focusPoint + bCenter)*0.5f;
- float cRadius = focusDistance*0.5f;
- bCenter = IntersectSpheres(&bRadius, bCenter, bRadius, cCenter, cRadius);
- }*/
}
@@ -491,7 +463,7 @@ Mesh generateCollisionCapsules(physx::PxVec4* spheres, int sphereCount, uint32_t
Mesh finalMesh;
for(int i = 0; i < sphereCount; i++)
{
- Mesh sphere = generateIcosahedron(spheres[i].w+ grow, 4);
+ Mesh sphere = generateIcosahedron(spheres[i].w+ grow, 2);
sphere.applyTransfom(physx::PxTransform(spheres[i].getXYZ()));
finalMesh.merge(sphere);
}
@@ -504,6 +476,272 @@ Mesh generateCollisionCapsules(physx::PxVec4* spheres, int sphereCount, uint32_t
return finalMesh;
}
+::SimpleMesh generateFastSphere(int segmentsX, int segmentY, physx::PxMat44 transform)
+{
+ SimpleMesh mesh;
+ const int xSegments = segmentsX;
+ const int ySegments = segmentY;
+
+ {
+ //bottom
+ SimpleMesh::Vertex v;
+ v.position = physx::PxVec3(0.0f, -1.0f, 0.0f);
+ v.normal = transform.rotate(physx::PxVec4(v.position, 0.0f)).getXYZ();
+ v.position = transform.transform(v.position);
+ v.uv = physx::PxVec2(0.0f, 0.0f);
+ mesh.vertices.push_back(v);
+ }
+
+ //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;
+
+ SimpleMesh::Vertex v;
+ v.position = physx::PxVec3(cos(yaw)*cos(pitch), sin(pitch), sin(yaw)*cos(pitch));
+ v.uv = physx::PxVec2(xf, yf);
+ v.normal = transform.rotate(physx::PxVec4(v.position, 0.0f)).getXYZ();
+ v.position = transform.transform(v.position);
+ mesh.vertices.push_back(v);
+ }
+ }
+
+ {
+ //top
+ SimpleMesh::Vertex v;
+ v.position = physx::PxVec3(0.0f, 1.0f, 0.0f);
+ v.normal = transform.rotate(physx::PxVec4(v.position,0.0f)).getXYZ();
+ v.position = transform.transform(v.position);
+ v.uv = physx::PxVec2(0.0f, 1.0f);
+ mesh.vertices.push_back(v);
+ }
+
+ //bottom cap
+ for(int x = 0; x < xSegments; x++)
+ {
+ mesh.indices.push_back(0);
+ mesh.indices.push_back(1 + x);
+ mesh.indices.push_back(1 + (x + 1) % xSegments);
+ }
+
+ 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++)
+ {
+ mesh.indices.push_back(RingVertex(x, y));
+ mesh.indices.push_back(RingVertex(x + 1, y));
+ mesh.indices.push_back(RingVertex(x, y + 1));
+
+ mesh.indices.push_back(RingVertex(x + 1, y));
+ mesh.indices.push_back(RingVertex(x + 1, y + 1));
+ mesh.indices.push_back(RingVertex(x, y + 1));
+ }
+ }
+
+ //bottom cap
+ for(int x = 0; x < xSegments; x++)
+ {
+ mesh.indices.push_back((uint16_t)mesh.vertices.size() - 1);
+ mesh.indices.push_back(RingVertex(x, ySegments - 2));
+ mesh.indices.push_back(RingVertex(x + 1, ySegments - 2));
+ }
+
+ return mesh;
+}
+
+::SimpleMesh generateFastCylinder(int segmentsX, int segmentY, physx::PxMat44 transform)
+{
+ SimpleMesh mesh;
+ const int xSegments = segmentsX;
+ const int ySegments = segmentY;
+
+
+ //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;
+
+ SimpleMesh::Vertex v;
+ v.position = physx::PxVec3(cos(yaw), yf, sin(yaw));
+ v.uv = physx::PxVec2(xf, yf);
+ v.normal = transform.rotate(physx::PxVec4(physx::PxVec3(cos(yaw), 0.0f, sin(yaw)), 0.0f)).getXYZ();
+ v.position = transform.transform(v.position);
+ mesh.vertices.push_back(v);
+ }
+ }
+
+
+ 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++)
+ {
+ mesh.indices.push_back(RingVertex(x, y));
+ mesh.indices.push_back(RingVertex(x + 1, y));
+ mesh.indices.push_back(RingVertex(x, y + 1));
+
+ mesh.indices.push_back(RingVertex(x + 1, y));
+ mesh.indices.push_back(RingVertex(x + 1, y + 1));
+ mesh.indices.push_back(RingVertex(x, y + 1));
+ }
+ }
+
+ return mesh;
+}
+
+::SimpleMesh generateCollisionCapsulesFast(physx::PxVec4* spheres, int sphereCount, uint32_t* indices, int indexCount, float grow)
+{
+ static ::SimpleMesh sphere = generateFastSphere(24,12,physx::PxTransform(physx::PxVec3(0.0f, 0.0f, 0.0f), physx::PxQuat(0.0f, physx::PxVec3(0.0f, 1.0f, 0.0f))));
+ static ::SimpleMesh cylinder = generateFastCylinder(24, 1, physx::PxTransform(physx::PxVec3(0.0f, 1.0f, 0.0f), physx::PxQuat(0.0f, physx::PxVec3(0.0f, 1.0f, 0.0f))));
+
+ ::SimpleMesh mesh;
+ mesh.vertices.resize(sphere.vertices.size()*sphereCount + cylinder.vertices.size()*(indexCount / 2));
+ mesh.indices.resize(sphere.indices.size()*sphereCount + cylinder.indices.size()*(indexCount / 2));
+
+ 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(PxVec4(spheres[i].w + grow, spheres[i].w + grow, spheres[i].w + grow, 1.0f));
+
+ for(int vi = 0; vi<(int)sphere.vertices.size(); vi++)
+ {
+ SimpleMesh::Vertex v = sphere.vertices[vi];
+ v.normal = transform.rotate(physx::PxVec4(v.normal, 0.0f)).getXYZ();
+ v.position = transform.transform(v.position);
+ mesh.vertices[nextVertex++] = v;
+ }
+
+ for(int ii = 0; ii < (int)sphere.indices.size(); ii++)
+ {
+ mesh.indices[nextIndex++] = sphere.indices[ii]+ baseIndex;
+ }
+ }
+
+ 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(PxVec4(sphereRadiusA, length/2.0f, sphereRadiusA+grow, 1.0f));
+ physx::PxMat44 scaleB = physx::PxMat44(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)
+ orientation = physx::PxQuat(physx::PxTwoPi, physx::PxVec3(1.0f, 0.0f, 0.0f));
+ else if(u.dot(v) > 0.9999)
+ orientation = physx::PxQuat(0.0f, physx::PxVec3(1.0f, 0.0f, 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 = (int)cylinder.vertices.size() / 2;
+ for(int vi = 0; vi<firstRing; vi++)
+ {
+ SimpleMesh::Vertex v = cylinder.vertices[vi];
+ v.normal = transform.rotate(physx::PxVec4(v.normal, 0.0f)).getXYZ();
+ v.position = transform.transform(v.position);
+ mesh.vertices[nextVertex++] = v;
+ }
+ transform = physx::PxMat44(physx::PxTransform(spherePosA, orientation))*scaleB;
+ for(int vi = firstRing; vi<(int)cylinder.vertices.size(); vi++)
+ {
+ SimpleMesh::Vertex v = cylinder.vertices[vi];
+ v.normal = transform.rotate(physx::PxVec4(v.normal, 0.0f)).getXYZ();
+ v.position = transform.transform(v.position);
+ mesh.vertices[nextVertex++] = v;
+ }
+
+ for(int ii = 0; ii < (int)cylinder.indices.size(); ii++)
+ {
+ mesh.indices[nextIndex++] = cylinder.indices[ii] + baseIndex;
+ }
+ }
+
+ return mesh;
+}
+
uint32_t generateConvexPolyhedronPlanes(int segmentsX, int segmentsY, physx::PxVec3 center, float radius, std::vector<physx::PxVec4>* planes)
{
int offset = 0;
@@ -546,7 +784,7 @@ MeshGeneratorRenderMesh::MeshGeneratorRenderMesh(const Mesh mesh)
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);
+ initialize(vertices, (uint32_t)vertexCount, sizeof(RenderVertex), layout, indices, indexCount, 0);
delete vertices;
delete indices;
@@ -567,11 +805,22 @@ MeshGeneratorRenderMeshSmooth::MeshGeneratorRenderMeshSmooth(const Mesh mesh)
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);
+ initialize(vertices, (uint32_t)vertexCount, sizeof(RenderVertex), layout, indices, indexCount, 0);
delete vertices;
delete indices;
}
+
+MeshGeneratorRenderMeshSmooth::MeshGeneratorRenderMeshSmooth(const ::SimpleMesh mesh, int flags)
+{
+ 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});
+ layout.push_back({"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0});
+
+ initialize(mesh.vertices.data(), (uint32_t)mesh.vertices.size(), sizeof(::SimpleMesh::Vertex), layout, mesh.indices.data(), (uint32_t)mesh.indices.size(), flags);
+}
+
MeshGeneratorRenderMeshSmooth::~MeshGeneratorRenderMeshSmooth()
{
diff --git a/NvCloth/samples/SampleBase/utils/MeshGenerator.h b/NvCloth/samples/SampleBase/utils/MeshGenerator.h
index 4f4b0c9..2e0344e 100644
--- a/NvCloth/samples/SampleBase/utils/MeshGenerator.h
+++ b/NvCloth/samples/SampleBase/utils/MeshGenerator.h
@@ -14,6 +14,7 @@
#include <vector>
#include "renderer/CustomRenderMesh.h"
#include <foundation/PxVec3.h>
+#include "renderer/Mesh.h"
namespace MeshGenerator
{
@@ -92,6 +93,13 @@ Mesh generateCone(physx::PxVec4 a, physx::PxVec4 b, int segments, float grow, bo
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);
+//Generates simple meshes with smooth shading
+::SimpleMesh generateFastSphere(int segmentsX, int segmentY, physx::PxMat44 transform);
+::SimpleMesh generateFastCylinder(int segmentsX, int segmentY, physx::PxMat44 transform); //no caps
+
+//Combines cashed spheres and cylinders to generate the capsules
+::SimpleMesh generateCollisionCapsulesFast(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
@@ -105,6 +113,7 @@ class MeshGeneratorRenderMeshSmooth : public CustomRenderMesh
{
public:
MeshGeneratorRenderMeshSmooth(const Mesh mesh);
+ MeshGeneratorRenderMeshSmooth(const ::SimpleMesh mesh, int flags = 0); //flags from CustomRenderMesh
virtual ~MeshGeneratorRenderMeshSmooth();
};