aboutsummaryrefslogtreecommitdiff
path: root/demo/scenes/waterballoon.h
diff options
context:
space:
mode:
Diffstat (limited to 'demo/scenes/waterballoon.h')
-rw-r--r--demo/scenes/waterballoon.h336
1 files changed, 336 insertions, 0 deletions
diff --git a/demo/scenes/waterballoon.h b/demo/scenes/waterballoon.h
new file mode 100644
index 0000000..544bf78
--- /dev/null
+++ b/demo/scenes/waterballoon.h
@@ -0,0 +1,336 @@
+
+class WaterBalloon : public Scene
+{
+public:
+
+ WaterBalloon(const char* name) : Scene(name) {}
+
+ virtual ~WaterBalloon()
+ {
+ for (size_t i = 0; i < mCloths.size(); ++i)
+ NvFlexExtDestroyTearingCloth(mCloths[i].asset);
+ }
+
+ void AddInflatable(const Mesh* mesh, float overPressure, float invMass, int phase)
+ {
+ // create a cloth mesh using the global positions / indices
+ const int numParticles = int(mesh->m_positions.size());
+ const int maxParticles = numParticles * 2;
+
+ Balloon balloon;
+ balloon.particleOffset = g_buffers->positions.size();
+ balloon.triangleOffset = g_buffers->triangles.size();
+ balloon.splitThreshold = 4.0f;
+
+ // add particles to system
+ for (size_t i = 0; i < mesh->GetNumVertices(); ++i)
+ {
+ const Vec3 p = Vec3(mesh->m_positions[i]);
+
+ g_buffers->positions.push_back(Vec4(p.x, p.y, p.z, invMass));
+ g_buffers->restPositions.push_back(Vec4(p.x, p.y, p.z, invMass));
+
+ g_buffers->velocities.push_back(0.0f);
+ g_buffers->phases.push_back(phase);
+ }
+
+ for (size_t i = 0; i < mesh->m_indices.size(); i += 3)
+ {
+ int a = mesh->m_indices[i + 0];
+ int b = mesh->m_indices[i + 1];
+ int c = mesh->m_indices[i + 2];
+
+ Vec3 n = -Normalize(Cross(mesh->m_positions[b] - mesh->m_positions[a], mesh->m_positions[c] - mesh->m_positions[a]));
+ g_buffers->triangleNormals.push_back(n);
+
+ g_buffers->triangles.push_back(a + balloon.particleOffset);
+ g_buffers->triangles.push_back(b + balloon.particleOffset);
+ g_buffers->triangles.push_back(c + balloon.particleOffset);
+ }
+
+ // create tearing asset
+ NvFlexExtAsset* cloth = NvFlexExtCreateTearingClothFromMesh((float*)&g_buffers->positions[balloon.particleOffset], numParticles, maxParticles, (int*)&mesh->m_indices[0], mesh->GetNumFaces(), 1.0f, 1.0f, 0.0f);
+ balloon.asset = cloth;
+
+ mCloths.push_back(balloon);
+ }
+
+ void Initialize()
+ {
+ mCloths.resize(0);
+
+ float minSize = 0.25f;
+ float maxSize = 0.5f;
+ float spacing = 4.0f;
+
+ // convex rocks
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 1; j++)
+ AddRandomConvex(10, Vec3(i*maxSize*spacing, 0.0f, j*maxSize*spacing), minSize, maxSize, Vec3(0.0f, 1.0f, 0.0f), Randf(0.0f, k2Pi));
+
+ float radius = 0.1f;
+ int group = 0;
+
+ g_numExtraParticles = 20000;
+ g_numSubsteps = 3;
+
+ g_params.radius = radius;
+ g_params.dynamicFriction = 0.125f;
+ g_params.dissipation = 0.0f;
+ g_params.numIterations = 5;
+ g_params.particleCollisionMargin = g_params.radius*0.05f;
+ g_params.relaxationFactor = 1.0f;
+ g_params.drag = 0.0f;
+ g_params.anisotropyScale = 25.0f;
+ g_params.smoothing = 1.f;
+ g_params.maxSpeed = 0.5f*g_numSubsteps*radius / g_dt;
+ g_params.gravity[1] *= 1.0f;
+ g_params.collisionDistance = 0.01f;
+ g_params.solidPressure = 0.0f;
+
+ g_params.fluid = true;
+
+ g_params.fluidRestDistance = radius*0.65f;
+ g_params.viscosity = 0.0;
+ g_params.adhesion = 0.0f;
+ g_params.cohesion = 0.02f;
+
+
+ // add inflatables
+ Mesh* mesh = ImportMesh(GetFilePathByPlatform("../../data/sphere_high.ply").c_str());
+
+ for (int y = 0; y < 2; ++y)
+ for (int i = 0; i < 2; ++i)
+ {
+ Vec3 lower = Vec3(2.0f + i*2.0f, 0.4f + y*1.2f, 1.0f);
+
+ mesh->Normalize();
+ mesh->Transform(TranslationMatrix(Point3(lower)));
+
+ AddInflatable(mesh, 1.0f, 0.25f, NvFlexMakePhase(group++, eNvFlexPhaseSelfCollide | eNvFlexPhaseSelfCollideFilter));
+ }
+
+ g_numSolidParticles = g_buffers->positions.size();
+ g_numExtraParticles = g_buffers->positions.size();
+
+ // fill inflatables with water
+ std::vector<Vec3> positions(10000);
+ int n = PoissonSample3D(0.45f, g_params.radius*0.42f, &positions[0], positions.size(), 10000);
+ //int n = TightPack3D(0.45f, g_params.radius*0.42f, &positions[0], positions.size());
+
+ mNumFluidParticles = 0;
+
+ for (size_t i = 0; i < mCloths.size(); ++i)
+ {
+ const int vertStart = i*mesh->GetNumVertices();
+ const int vertEnd = vertStart + mesh->GetNumVertices();
+
+ const int phase = NvFlexMakePhase(group++, eNvFlexPhaseSelfCollide | eNvFlexPhaseFluid);
+
+ Vec3 center;
+ for (int v = vertStart; v < vertEnd; ++v)
+ center += Vec3(g_buffers->positions[v]);
+
+ center /= float(vertEnd - vertStart);
+
+ printf("%d, %d - %f %f %f\n", vertStart, vertEnd, center.x, center.y, center.z);
+
+ for (int i = 0; i < n; ++i)
+ {
+ g_buffers->positions.push_back(Vec4(center + positions[i], 1.0f));
+ g_buffers->restPositions.push_back(Vec4());
+ g_buffers->velocities.push_back(0.0f);
+ g_buffers->phases.push_back(phase);
+ }
+
+ mNumFluidParticles += n;
+ }
+
+ delete mesh;
+
+ g_drawPoints = false;
+ g_drawEllipsoids = true;
+ g_drawSprings = 0;
+ g_drawCloth = false;
+ g_warmup = true;
+
+ }
+
+ void RebuildConstraints()
+ {
+ // update constraint data
+ g_buffers->triangles.resize(0);
+ g_buffers->springIndices.resize(0);
+ g_buffers->springStiffness.resize(0);
+ g_buffers->springLengths.resize(0);
+
+ for (int c = 0; c < int(mCloths.size()); ++c)
+ {
+ Balloon& balloon = mCloths[c];
+
+ for (int i = 0; i < balloon.asset->numTriangles; ++i)
+ {
+ g_buffers->triangles.push_back(balloon.asset->triangleIndices[i * 3 + 0] + balloon.particleOffset);
+ g_buffers->triangles.push_back(balloon.asset->triangleIndices[i * 3 + 1] + balloon.particleOffset);
+ g_buffers->triangles.push_back(balloon.asset->triangleIndices[i * 3 + 2] + balloon.particleOffset);
+ }
+
+ for (int i = 0; i < balloon.asset->numSprings * 2; ++i)
+ g_buffers->springIndices.push_back(balloon.asset->springIndices[i] + balloon.particleOffset);
+
+
+ for (int i = 0; i < balloon.asset->numSprings; ++i)
+ {
+ g_buffers->springStiffness.push_back(balloon.asset->springCoefficients[i]);
+ g_buffers->springLengths.push_back(balloon.asset->springRestLengths[i]);
+ }
+ }
+ }
+
+ virtual void Sync()
+ {
+ // send new particle data to the GPU
+ NvFlexSetRestParticles(g_flex, g_buffers->restPositions.buffer, g_buffers->restPositions.size());
+
+ // update solver
+ NvFlexSetSprings(g_flex, g_buffers->springIndices.buffer, g_buffers->springLengths.buffer, g_buffers->springStiffness.buffer, g_buffers->springLengths.size());
+ NvFlexSetDynamicTriangles(g_flex, g_buffers->triangles.buffer, g_buffers->triangleNormals.buffer, g_buffers->triangles.size() / 3);
+ }
+
+ virtual void Update()
+ {
+ // temporarily restore the mouse particle's mass so that we can tear it
+ if (g_mouseParticle != -1)
+ g_buffers->positions[g_mouseParticle].w = g_mouseMass;
+
+ // force larger radius for solid interactions to prevent interpenetration
+ g_params.solidRestDistance = g_params.radius;
+
+ // build new particle arrays
+ std::vector<Vec4> newParticles;
+ std::vector<Vec4> newParticlesRest;
+ std::vector<Vec3> newVelocities;
+ std::vector<int> newPhases;
+ std::vector<Vec4> newNormals;
+
+ for (int c = 0; c < int(mCloths.size()); ++c)
+ {
+ Balloon& balloon = mCloths[c];
+
+ const int destOffset = newParticles.size();
+
+ // append existing particles
+ for (int i = 0; i < balloon.asset->numParticles; ++i)
+ {
+ newParticles.push_back(g_buffers->positions[balloon.particleOffset + i]);
+ newParticlesRest.push_back(g_buffers->restPositions[balloon.particleOffset + i]);
+ newVelocities.push_back(g_buffers->velocities[balloon.particleOffset + i]);
+ newPhases.push_back(g_buffers->phases[balloon.particleOffset + i]);
+ newNormals.push_back(g_buffers->normals[balloon.particleOffset + i]);
+ }
+
+ // perform splitting
+ const int maxCopies = 2048;
+ const int maxEdits = 2048;
+
+ NvFlexExtTearingParticleClone particleCopies[maxCopies];
+ int numParticleCopies;
+
+ NvFlexExtTearingMeshEdit triangleEdits[maxEdits];
+ int numTriangleEdits;
+
+ // update asset's copy of the particles
+ memcpy(balloon.asset->particles, &g_buffers->positions[balloon.particleOffset], sizeof(Vec4)*balloon.asset->numParticles);
+
+ // tear
+ NvFlexExtTearClothMesh(balloon.asset, balloon.splitThreshold, 1, particleCopies, &numParticleCopies, maxCopies, triangleEdits, &numTriangleEdits, maxEdits);
+
+ // resize particle data arrays
+ newParticles.resize(newParticles.size() + numParticleCopies);
+ newParticlesRest.resize(newParticlesRest.size() + numParticleCopies);
+ newVelocities.resize(newVelocities.size() + numParticleCopies);
+ newPhases.resize(newPhases.size() + numParticleCopies);
+ newNormals.resize(newNormals.size() + numParticleCopies);
+
+ // copy particles
+ for (int i = 0; i < numParticleCopies; ++i)
+ {
+ const int srcIndex = balloon.particleOffset + particleCopies[i].srcIndex;
+ const int destIndex = destOffset + particleCopies[i].destIndex;
+
+ newParticles[destIndex] = g_buffers->positions[srcIndex];
+ newParticlesRest[destIndex] = g_buffers->restPositions[srcIndex];
+ newVelocities[destIndex] = g_buffers->velocities[srcIndex];
+ newPhases[destIndex] = g_buffers->phases[srcIndex];
+ newNormals[destIndex] = g_buffers->normals[srcIndex];
+ }
+
+ if (numParticleCopies)
+ {
+ // reduce split threshold for this balloon
+ balloon.splitThreshold = 1.75f;
+ }
+
+ balloon.particleOffset = destOffset;
+ balloon.asset->numParticles += numParticleCopies;
+ }
+
+ // append fluid particles
+ const int fluidStart = g_numSolidParticles;
+ const int fluidEnd = fluidStart + mNumFluidParticles;
+
+ g_numSolidParticles = newParticles.size();
+
+ for (int i = fluidStart; i < fluidEnd; ++i)
+ {
+ newParticles.push_back(g_buffers->positions[i]);
+ newParticlesRest.push_back(Vec4());
+ newVelocities.push_back(g_buffers->velocities[i]);
+ newPhases.push_back(g_buffers->phases[i]);
+ newNormals.push_back(g_buffers->normals[i]);
+ }
+
+ g_buffers->positions.assign(&newParticles[0], newParticles.size());
+ g_buffers->restPositions.assign(&newParticlesRest[0], newParticlesRest.size());
+ g_buffers->velocities.assign(&newVelocities[0], newVelocities.size());
+ g_buffers->phases.assign(&newPhases[0], newPhases.size());
+ g_buffers->normals.assign(&newNormals[0], newNormals.size());
+
+ // build active indices list
+ g_buffers->activeIndices.resize(g_buffers->positions.size());
+ for (int i = 0; i < g_buffers->positions.size(); ++i)
+ g_buffers->activeIndices[i] = i;
+
+ // update constraint buffers
+ RebuildConstraints();
+
+ // restore mouse mass
+ if (g_mouseParticle != -1)
+ g_buffers->positions[g_mouseParticle].w = 0.0f;
+ }
+
+ virtual void Draw(int pass)
+ {
+ if (!g_drawMesh)
+ return;
+
+ for (size_t i = 0; i < mCloths.size(); ++i)
+ {
+ DrawCloth(&g_buffers->positions[0], &g_buffers->normals[0], NULL, &g_buffers->triangles[mCloths[i].triangleOffset], mCloths[i].asset->numTriangles, g_buffers->positions.size(), (i + 2) % 6);//, g_params.radius*0.25f);
+ }
+ }
+
+ struct Balloon
+ {
+ NvFlexExtAsset* asset;
+
+ int particleOffset;
+ int triangleOffset;
+
+ float splitThreshold;
+ };
+
+ int mNumFluidParticles;
+
+ std::vector<Balloon> mCloths;
+};