aboutsummaryrefslogtreecommitdiff
path: root/extensions/flexExtRigid.cpp
diff options
context:
space:
mode:
authorMiles Macklin <[email protected]>2017-03-10 14:51:31 +1300
committerMiles Macklin <[email protected]>2017-03-10 14:51:31 +1300
commitad3d90fafe5ee79964bdfe1f1e0704c3ffcdfd5f (patch)
tree4cc6f3288363889d7342f7f8407c0251e6904819 /extensions/flexExtRigid.cpp
downloadflex-ad3d90fafe5ee79964bdfe1f1e0704c3ffcdfd5f.tar.xz
flex-ad3d90fafe5ee79964bdfe1f1e0704c3ffcdfd5f.zip
Initial 1.1.0 binary release
Diffstat (limited to 'extensions/flexExtRigid.cpp')
-rw-r--r--extensions/flexExtRigid.cpp195
1 files changed, 195 insertions, 0 deletions
diff --git a/extensions/flexExtRigid.cpp b/extensions/flexExtRigid.cpp
new file mode 100644
index 0000000..9c37c28
--- /dev/null
+++ b/extensions/flexExtRigid.cpp
@@ -0,0 +1,195 @@
+// 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) 20132017 NVIDIA Corporation. All rights reserved.
+
+#include "../include/NvFlexExt.h"
+
+#include "../core/maths.h"
+#include "../core/voxelize.h"
+#include "../core/sdf.h"
+
+#include <vector>
+
+namespace
+{
+
+float SampleSDF(const float* sdf, int dim, int x, int y, int z)
+{
+ assert(x < dim && x >= 0);
+ assert(y < dim && y >= 0);
+ assert(z < dim && z >= 0);
+
+ return sdf[z*dim*dim + y*dim + x];
+}
+
+// return normal of signed distance field
+Vec3 SampleSDFGrad(const float* sdf, int dim, int x, int y, int z)
+{
+ int x0 = std::max(x-1, 0);
+ int x1 = std::min(x+1, dim-1);
+
+ int y0 = std::max(y-1, 0);
+ int y1 = std::min(y+1, dim-1);
+
+ int z0 = std::max(z-1, 0);
+ int z1 = std::min(z+1, dim-1);
+
+ float dx = (SampleSDF(sdf, dim, x1, y, z) - SampleSDF(sdf, dim, x0, y, z))*(dim*0.5f);
+ float dy = (SampleSDF(sdf, dim, x, y1, z) - SampleSDF(sdf, dim, x, y0, z))*(dim*0.5f);
+ float dz = (SampleSDF(sdf, dim, x, y, z1) - SampleSDF(sdf, dim, x, y, z0))*(dim*0.5f);
+
+ return Vec3(dx, dy, dz);
+}
+
+} // anonymous namespace
+
+NvFlexExtAsset* NvFlexExtCreateRigidFromMesh(const float* vertices, int numVertices, const int* indices, int numTriangleIndices, float spacing, float expand)
+{
+ std::vector<Vec4> particles;
+ std::vector<Vec4> normals;
+ std::vector<int> phases;
+
+ const Vec3* positions = (Vec3*)vertices;
+
+ Vec3 meshLower(FLT_MAX), meshUpper(-FLT_MAX);
+ for (int i=0; i < numVertices; ++i)
+ {
+ meshLower = Min(meshLower, positions[i]);
+ meshUpper = Max(meshUpper, positions[i]);
+ }
+
+ Vec3 edges = meshUpper-meshLower;
+ float maxEdge = std::max(std::max(edges.x, edges.y), edges.z);
+
+ // tweak spacing to avoid edge cases for particles laying on the boundary
+ // just covers the case where an edge is a whole multiple of the spacing.
+ float spacingEps = spacing*(1.0f - 1e-4f);
+
+ // make sure to have at least one particle in each dimension
+ int dx, dy, dz;
+ dx = spacing > edges.x ? 1 : int(edges.x/spacingEps);
+ dy = spacing > edges.y ? 1 : int(edges.y/spacingEps);
+ dz = spacing > edges.z ? 1 : int(edges.z/spacingEps);
+
+ int maxDim = std::max(std::max(dx, dy), dz);
+
+ // expand border by two voxels to ensure adequate sampling at edges
+ meshLower -= 2.0f*Vec3(spacing);
+ meshUpper += 2.0f*Vec3(spacing);
+ maxDim += 4;
+
+ // we shift the voxelization bounds so that the voxel centers
+ // lie symmetrically to the center of the object. this reduces the
+ // chance of missing features, and also better aligns the particles
+ // with the mesh
+ Vec3 meshOffset;
+ meshOffset.x = 0.5f * (spacing - (edges.x - (dx-1)*spacing));
+ meshOffset.y = 0.5f * (spacing - (edges.y - (dy-1)*spacing));
+ meshOffset.z = 0.5f * (spacing - (edges.z - (dz-1)*spacing));
+ meshLower -= meshOffset;
+
+ // don't allow samplings with > 64 per-side
+ if (maxDim > 64)
+ return NULL;
+
+ std::vector<uint32_t> voxels(maxDim*maxDim*maxDim);
+
+ Voxelize(vertices, numVertices, indices, numTriangleIndices, maxDim, maxDim, maxDim, &voxels[0], meshLower, meshLower + Vec3(maxDim*spacing));
+
+ std::vector<float> sdf(maxDim*maxDim*maxDim);
+ MakeSDF(&voxels[0], maxDim, maxDim, maxDim, &sdf[0]);
+
+ Vec3 center;
+
+ for (int x=0; x < maxDim; ++x)
+ {
+ for (int y=0; y < maxDim; ++y)
+ {
+ for (int z=0; z < maxDim; ++z)
+ {
+ const int index = z*maxDim*maxDim + y*maxDim + x;
+
+ // if voxel is marked as occupied the add a particle
+ if (voxels[index])
+ {
+ Vec3 position = meshLower + spacing*Vec3(float(x) + 0.5f, float(y) + 0.5f, float(z) + 0.5f);
+
+ // normalize the sdf value and transform to world scale
+ Vec3 n = SafeNormalize(SampleSDFGrad(&sdf[0], maxDim, x, y, z));
+ float d = sdf[index]*maxEdge;
+
+ // move particles inside or outside shape
+ position += n*expand;
+
+ normals.push_back(Vec4(n, d));
+ particles.push_back(Vec4(position.x, position.y, position.z, 1.0f));
+ phases.push_back(0);
+
+ center += position;
+ }
+ }
+ }
+ }
+
+ NvFlexExtAsset* asset = new NvFlexExtAsset();
+ memset(asset, 0, sizeof(*asset));
+
+ if (particles.size())
+ {
+ const int numParticles = int(particles.size());
+
+ asset->numParticles = numParticles;
+ asset->maxParticles = numParticles;
+
+ asset->particles = new float[numParticles*4];
+ memcpy(asset->particles, &particles[0], sizeof(Vec4)*numParticles);
+
+ // store center of mass
+ center /= float(numParticles);
+
+ asset->numShapes = 1;
+ asset->numShapeIndices = numParticles;
+
+ // for rigids we just reference all particles in the shape
+ asset->shapeIndices = new int[numParticles];
+
+ for (int i = 0; i < numParticles; ++i)
+ asset->shapeIndices[i] = i;
+
+ asset->shapeCenters = new float[4];
+ asset->shapeCenters[0] = center.x;
+ asset->shapeCenters[1] = center.y;
+ asset->shapeCenters[2] = center.z;
+
+ asset->shapeCoefficients = new float[1];
+ asset->shapeCoefficients[0] = 1.0f;
+
+ asset->shapeOffsets = new int[1];
+ asset->shapeOffsets[0] = numParticles;
+ }
+
+ return asset;
+}