diff options
| author | Miles Macklin <[email protected]> | 2017-03-10 14:51:31 +1300 |
|---|---|---|
| committer | Miles Macklin <[email protected]> | 2017-03-10 14:51:31 +1300 |
| commit | ad3d90fafe5ee79964bdfe1f1e0704c3ffcdfd5f (patch) | |
| tree | 4cc6f3288363889d7342f7f8407c0251e6904819 /demo/scenes | |
| download | flex-ad3d90fafe5ee79964bdfe1f1e0704c3ffcdfd5f.tar.xz flex-ad3d90fafe5ee79964bdfe1f1e0704c3ffcdfd5f.zip | |
Initial 1.1.0 binary release
Diffstat (limited to 'demo/scenes')
55 files changed, 5859 insertions, 0 deletions
diff --git a/demo/scenes/adhesion.h b/demo/scenes/adhesion.h new file mode 100644 index 0000000..efbdec2 --- /dev/null +++ b/demo/scenes/adhesion.h @@ -0,0 +1,50 @@ + +class Adhesion : public Scene +{ +public: + + Adhesion(const char* name) : Scene(name) {} + + virtual void Initialize() + { + float radius = 0.1f; + + g_params.radius = radius; + + g_params.fluid = true; + g_params.numIterations = 3; + g_params.vorticityConfinement = 0.0f; + g_params.fluidRestDistance = g_params.radius*0.55f; + g_params.anisotropyScale = 3.0f / radius; + g_params.smoothing = 0.5f; + g_params.relaxationFactor = 1.f; + g_params.restitution = 0.0f; + g_params.collisionDistance = 0.01f; + + g_fluidColor = Vec4(0.0f, 0.8f, 0.2f, 1.0f); + //g_fluidColor = Vec4(0.7f, 0.6f, 0.6f, 0.2f); + + g_params.dynamicFriction = 0.5f; + g_params.viscosity = 50.0f; + g_params.adhesion = 0.5f; + g_params.cohesion = 0.08f; + g_params.surfaceTension = 0.0f; + + g_numExtraParticles = 64 * 1024; + + AddBox(Vec3(1.0f, 1.5f, 0.1f), Vec3(0.0f, 1.5f, 0.0f)); + AddBox(Vec3(1.0f, 0.1f, 6.0f), Vec3(-1.0f, 3.0f, 0.0f)); + + g_emitters[0].mEnabled = true; + g_emitters[0].mSpeed = (g_params.fluidRestDistance*2.f / g_dt); + + g_params.numPlanes = 3; + + // draw options + g_drawEllipsoids = true; + + g_pause = false; + } + + bool mViscous; +}; diff --git a/demo/scenes/armadilloshower.h b/demo/scenes/armadilloshower.h new file mode 100644 index 0000000..fdbf194 --- /dev/null +++ b/demo/scenes/armadilloshower.h @@ -0,0 +1,75 @@ + + +class ArmadilloShower : public Scene +{ +public: + + ArmadilloShower(const char* name, bool viscous) : Scene(name), mViscous(viscous) {} + + virtual void Initialize() + { + float minSize = 0.5f; + float maxSize = 1.0f; + + float radius = 0.1f; + + for (int i=0; i < 5; i++) + AddRandomConvex(10, Vec3(i*2.0f, 0.0f, Randf(0.0f, 2.0f)), minSize, maxSize, Vec3(0.0f, 1.0f, 0.0f), Randf(0.0f, k2Pi*10.0f)); + + g_params.radius = radius; + + g_params.fluid = true; + g_params.numIterations = 3; + g_params.vorticityConfinement = 0.0f; + g_params.fluidRestDistance = g_params.radius*0.5f; + g_params.anisotropyScale = 20.0f; + + if (mViscous) + { + g_fluidColor = Vec4(0.0f, 0.8f, 0.2f, 1.0f); + + g_params.dynamicFriction = 0.5f; + g_params.viscosity = 10.85f; + g_params.cohesion = 0.25f; + } + else + { + g_params.dynamicFriction = 0.025f; + g_params.viscosity = 0.05f; + } + + g_numExtraParticles = 64*1024; + + g_diffuseScale = 1.0f; + + NvFlexDistanceFieldId sdf = CreateSDF(GetFilePathByPlatform("../../data/armadillo.ply").c_str(), 128); + AddSDF(sdf, Vec3(2.0f, 0.0f, -1.0f), Quat(), 2.0f); + + Vec3 meshLower, meshUpper; + g_mesh->GetBounds(meshLower, meshUpper); + + Emitter e1; + e1.mDir = Vec3(-1.0f, 0.0f, 0.0f); + e1.mRight = Vec3(0.0f, 0.0f, 1.0f); + e1.mPos = Vec3(-1.0f, 0.15f, 0.50f) + meshLower + Vec3(meshUpper.x, meshUpper.y*0.75f, meshUpper.z*0.5f); + e1.mSpeed = (g_params.radius*0.5f/g_dt)*2.0f; // 2 particle layers per-frame + e1.mEnabled = true; + + Emitter e2; + e2.mDir = Vec3(1.0f, 0.0f, 0.0f); + e2.mRight = Vec3(0.0f, 0.0f, -1.0f); + e2.mPos = Vec3(-1.0f, 0.15f, 0.50f) + meshLower + Vec3(0.0f, meshUpper.y*0.75f, meshUpper.z*0.5f); + e2.mSpeed = (g_params.radius*0.5f/g_dt)*2.0f; // 2 particle layers per-frame + e2.mEnabled = true; + + g_emitters.push_back(e1); + g_emitters.push_back(e2); + + g_emit = true; + + // draw options + g_drawEllipsoids = true; + } + + bool mViscous; +};
\ No newline at end of file diff --git a/demo/scenes/bananas.h b/demo/scenes/bananas.h new file mode 100644 index 0000000..b404a1e --- /dev/null +++ b/demo/scenes/bananas.h @@ -0,0 +1,60 @@ + + +class BananaPile : public Scene +{ +public: + + BananaPile(const char* name) : Scene(name) + { + } + + virtual void Initialize() + { + float s = 1.0f; + + Vec3 lower(0.0f, 1.0f + g_params.radius*0.25f, 0.0f); + + int dimx = 3; + int dimy = 40; + int dimz = 2; + + float radius = g_params.radius; + int group = 0; + + // create a basic grid + for (int x = 0; x < dimx; ++x) + { + for (int y = 0; y < dimy; ++y) + { + for (int z = 0; z < dimz; ++z) + { + CreateParticleShape(GetFilePathByPlatform("../../data/banana.obj").c_str(), lower + (s*1.1f)*Vec3(float(x), y*0.4f, float(z)), Vec3(s), 0.0f, radius*0.95f, Vec3(0.0f), 1.0f, true, 0.8f, NvFlexMakePhase(group++, 0), true, radius*0.1f, 0.0f, 0.0f, 1.25f*Vec4(0.875f, 0.782f, 0.051f, 1.0f)); + } + } + } + + AddPlinth(); + + g_numSubsteps = 3; + g_params.numIterations = 2; + + g_params.radius *= 1.0f; + g_params.dynamicFriction = 0.25f; + g_params.dissipation = 0.03f; + g_params.particleCollisionMargin = g_params.radius*0.05f; + g_params.sleepThreshold = g_params.radius*0.2f; + g_params.shockPropagation = 2.5f; + g_params.restitution = 0.55f; + g_params.damping = 0.25f; + + // draw options + g_drawPoints = false; + + g_emitters[0].mEnabled = true; + g_emitters[0].mSpeed = (g_params.radius*2.0f / g_dt); + } + + virtual void Update() + { + } +}; diff --git a/demo/scenes/bouyancy.h b/demo/scenes/bouyancy.h new file mode 100644 index 0000000..816146f --- /dev/null +++ b/demo/scenes/bouyancy.h @@ -0,0 +1,76 @@ + + + +class Buoyancy : public Scene +{ +public: + + Buoyancy(const char* name) : Scene(name) {} + + virtual void Initialize() + { + float radius = 0.1f; + float restDistance = radius*0.5f; + int group = 0; + + int n = 3; + float spacing = 64*restDistance*0.9f/(2.0f*n); + float sampling = restDistance*0.8f; + Vec3 size = sampling*12.0f; + + const float mass[] = {1.0f, 0.25f, 0.005f }; + + for (int j=0; j < 1; ++j) + for (int i=0; i < n; ++i) + CreateParticleShape(GetFilePathByPlatform("../../data/sphere.ply").c_str(), Vec3(spacing - 0.5f*size.x + i*spacing * 2, 2.0f + j*size.y*1.2f, 0.6f), size, 0.0f, sampling, Vec3(0.0f, 0.0f, 0.0f), mass[i], true, 1.0f, NvFlexMakePhase(group++, 0), true, 0.0001f); + + g_numSolidParticles = g_buffers->positions.size(); + + int x = 64; + int y = 20; + int z = 32; + + CreateParticleGrid(Vec3(0.0f), x, y, z, restDistance*0.9f, Vec3(0.0f), 1.0f, false, 0.0f, NvFlexMakePhase(group++, eNvFlexPhaseSelfCollide | eNvFlexPhaseFluid)); + + g_params.radius = radius; + g_params.dynamicFriction = 0.1f; + g_params.fluid = true; + g_params.viscosity = 2.0f; + g_params.numIterations = 4; + g_params.vorticityConfinement = 180.f; + g_params.anisotropyScale = 20.0f; + g_params.fluidRestDistance = restDistance; + g_params.numPlanes = 5; + g_params.cohesion = 0.001625f; + g_params.collisionDistance = restDistance; + g_params.solidPressure = 0.1f; + g_params.restitution = 0.0f; + g_params.relaxationFactor = 1.0f; + g_params.relaxationMode = eNvFlexRelaxationLocal; + + g_numSubsteps = 2; + + g_maxDiffuseParticles = 64*1024; + g_diffuseScale = 0.25f; + g_diffuseShadow = false; + g_diffuseColor = 1.5f; + g_diffuseMotionScale = 1.5f; + g_params.diffuseBallistic = 35; + g_params.diffuseThreshold *= 0.1f; + + g_drawPlaneBias = g_params.collisionDistance*1.5f; + + g_lightDistance *= 0.65f; + + g_fluidColor = Vec4(0.2f, 0.6f, 0.9f, 1.0f); + + // draw options + g_drawDensity = true; + g_drawDiffuse = true; + g_drawEllipsoids = true; + g_drawPoints = false; + + g_warmup = true; + } + +}; diff --git a/demo/scenes/bunnybath.h b/demo/scenes/bunnybath.h new file mode 100644 index 0000000..db9e6ac --- /dev/null +++ b/demo/scenes/bunnybath.h @@ -0,0 +1,84 @@ + +class BunnyBath : public Scene +{ +public: + + BunnyBath(const char* name, bool dam) : Scene(name), mDam(dam) {} + + void Initialize() + { + float radius = 0.1f; + + // deforming bunny + float s = radius*0.5f; + float m = 0.25f; + int group = 1; + + CreateParticleShape(GetFilePathByPlatform("../../data/bunny.ply").c_str(), Vec3(4.0f, 0.0f, 0.0f), 0.5f, 0.0f, s, Vec3(0.0f, 0.0f, 0.0f), m, true, 1.0f, NvFlexMakePhase(group++, 0), true, 0.0f); + CreateParticleShape(GetFilePathByPlatform("../../data/box.ply").c_str(), Vec3(4.0f, 0.0f, 1.0f), 0.45f, 0.0f, s, Vec3(0.0f, 0.0f, 0.0f), m, true, 1.0f, NvFlexMakePhase(group++, 0), true, 0.0f); + CreateParticleShape(GetFilePathByPlatform("../../data/bunny.ply").c_str(), Vec3(3.0f, 0.0f, 0.0f), 0.5f, 0.0f, s, Vec3(0.0f, 0.0f, 0.0f), m, true, 1.0f, NvFlexMakePhase(group++, 0), true, 0.0f); + CreateParticleShape(GetFilePathByPlatform("../../data/sphere.ply").c_str(), Vec3(3.0f, 0.0f, 1.0f), 0.45f, 0.0f, s, Vec3(0.0f, 0.0f, 0.0f), m, true, 1.0f, NvFlexMakePhase(group++, 0), true, 0.0f); + CreateParticleShape(GetFilePathByPlatform("../../data/bunny.ply").c_str(), Vec3(2.0f, 0.0f, 1.0f), 0.5f, 0.0f, s, Vec3(0.0f, 0.0f, 0.0f), m, true, 1.0f, NvFlexMakePhase(group++, 0), true, 0.0f); + CreateParticleShape(GetFilePathByPlatform("../../data/box.ply").c_str(), Vec3(2.0f, 0.0f, 0.0f), 0.45f, 0.0f, s, Vec3(0.0f, 0.0f, 0.0f), m, true, 1.0f, NvFlexMakePhase(group++, 0), true, 0.0f); + + g_numSolidParticles = g_buffers->positions.size(); + + float restDistance = radius*0.55f; + + if (mDam) + { + CreateParticleGrid(Vec3(0.0f, 0.0f, 0.6f), 24, 48, 24, restDistance, Vec3(0.0f), 1.0f, false, 0.0f, NvFlexMakePhase(0, eNvFlexPhaseSelfCollide | eNvFlexPhaseFluid), 0.005f); + g_lightDistance *= 0.5f; + } + + g_sceneLower = Vec3(0.0f); + + g_numSubsteps = 2; + + g_params.radius = radius; + g_params.dynamicFriction = 0.01f; + g_params.fluid = true; + g_params.viscosity = 2.0f; + g_params.numIterations = 4; + g_params.vorticityConfinement = 40.0f; + g_params.anisotropyScale = 30.0f; + g_params.fluidRestDistance = restDistance; + g_params.solidPressure = 0.f; + g_params.relaxationFactor = 0.0f; + g_params.cohesion = 0.02f; + g_params.collisionDistance = 0.01f; + + g_maxDiffuseParticles = 64*1024; + g_diffuseScale = 0.5f; + + g_fluidColor = Vec4(0.113f, 0.425f, 0.55f, 1.f); + + Emitter e1; + e1.mDir = Vec3(1.0f, 0.0f, 0.0f); + e1.mRight = Vec3(0.0f, 0.0f, -1.0f); + e1.mPos = Vec3(radius, 1.f, 0.65f); + e1.mSpeed = (restDistance/g_dt)*2.0f; // 2 particle layers per-frame + e1.mEnabled = true; + + g_emitters.push_back(e1); + + g_numExtraParticles = 48*1024; + + g_lightDistance = 1.8f; + + g_params.numPlanes = 5; + + g_waveFloorTilt = 0.0f; + g_waveFrequency = 1.5f; + g_waveAmplitude = 2.0f; + + g_warmup = true; + + // draw options + g_drawPoints = false; + g_drawEllipsoids = true; + g_drawDiffuse = true; + } + + bool mDam; +}; diff --git a/demo/scenes/ccdfluid.h b/demo/scenes/ccdfluid.h new file mode 100644 index 0000000..356eec7 --- /dev/null +++ b/demo/scenes/ccdfluid.h @@ -0,0 +1,107 @@ + +class CCDFluid : public Scene +{ +public: + + CCDFluid (const char* name) : Scene(name) {} + + void Initialize() + { + const float radius = 0.05f; + const float restDistance = radius*0.6f; + + int dx = int(ceilf(1.f / restDistance)); + int dy = int(ceilf(1.f / restDistance)); + int dz = int(ceilf(1.f / restDistance)); + + CreateParticleGrid(Vec3(0.0f, 1.0f, 0.0f), dx, dy, dz, restDistance, Vec3(0.0f), 1.0f, false, 0.0f, NvFlexMakePhase(0, eNvFlexPhaseSelfCollide | eNvFlexPhaseFluid), restDistance*0.01f); + + Vec3 lower, upper; + GetParticleBounds(lower, upper); + + Vec3 center = (lower+upper)*0.5f; + + //Mesh* shape = ImportMesh("../../data/box.ply"); + //shape->Transform(ScaleMatrix(Vec3(2.0f))); + + Mesh* shape = ImportMesh("../../data/torus.obj"); + shape->Transform(ScaleMatrix(Vec3(0.7f))); + + //Mesh* box = ImportMesh("../../data/sphere.ply"); + //box->Transform(TranslationMatrix(Point3(0.0f, 0.1f, 0.0f))*ScaleMatrix(Vec3(1.5f))); + + // invert box faces + for (int i=0; i < int(shape->GetNumFaces()); ++i) + swap(shape->m_indices[i*3+0], shape->m_indices[i*3+1]); + + shape->CalculateNormals(); + + // shift into torus interior + for (int i=0; i < g_buffers->positions.size(); ++i) + (Vec3&)(g_buffers->positions[i]) -= Vec3(2.1f, 0.0f, 0.0f); + + mesh = CreateTriangleMesh(shape); + AddTriangleMesh(mesh, Vec3(center), Quat(), 1.0f); + + // initialize our moving frame to the center of the box + newOffset = g_buffers->shapePositions[0].x; + newRotation = 0.0f; + rotationSpeed = 0.0f; + + g_numSubsteps = 2; + + g_params.fluid = true; + g_params.radius = radius; + g_params.fluidRestDistance = restDistance; + g_params.dynamicFriction = 0.1f; + g_params.restitution = 0.0f; + g_params.shapeCollisionMargin = 0.05f; + //g_params.maxAcceleration = 50.0f; + g_params.maxSpeed = g_numSubsteps*restDistance/g_dt; + g_params.collisionDistance = restDistance; + //g_params.shapeCollisionMargin = 0.0001f; + + g_params.numIterations = 3; + //g_params.relaxationFactor = 0.5f; + + g_params.smoothing = 0.4f; + g_params.anisotropyScale = 3.0f / radius; + + g_params.viscosity = 0.001f; + g_params.cohesion = 0.05f; + g_params.surfaceTension = 0.0f; + + // draw options + g_drawPoints = true; + g_drawEllipsoids = false; + g_drawDiffuse = true; + } + + virtual void DoGui() + { + imguiSlider("Linear", &newOffset, 0.0f, 2.0f, 0.0001f); + imguiSlider("Rotation", &rotationSpeed, 0.0f, 10.0f, 0.1f); + } + + virtual void Update() + { + g_buffers->shapePrevPositions[0].x = g_buffers->shapePositions[0].x; + g_buffers->shapePositions[0].x = newOffset; + + newRotation += rotationSpeed*g_dt; + + g_buffers->shapePrevRotations[0] = g_buffers->shapeRotations[0]; + g_buffers->shapeRotations[0] = QuatFromAxisAngle(Vec3(0.0f, 1.0f, 0.0f), newRotation); + + // update previous transform of the disc + UpdateShapes(); + } + + float newOffset; + float newRotation; + + float rotationSpeed; + + NvFlexTriangleMeshId mesh; +}; +
\ No newline at end of file diff --git a/demo/scenes/clothlayers.h b/demo/scenes/clothlayers.h new file mode 100644 index 0000000..eb1a01f --- /dev/null +++ b/demo/scenes/clothlayers.h @@ -0,0 +1,81 @@ + + +class ClothLayers : public Scene +{ +public: + + ClothLayers(const char* name) : + Scene(name) {} + + virtual void Initialize() + { + + float stretchStiffness = 1.0f; + float bendStiffness = 0.8f; + float shearStiffness = 0.5f; + + int dimx = 64; + int dimz = 64; + float radius = 0.05f; + int phase = NvFlexMakePhase(0, eNvFlexPhaseSelfCollide); + +#if 1 + CreateSpringGrid(Vec3(-0.6f, 2.9f, -0.6f), dimx, dimz, 1, radius, phase, stretchStiffness, bendStiffness, shearStiffness, 0.0f, 1.0f); + CreateSpringGrid(Vec3(-0.6f, 2.6f, -0.6f), dimx, dimz, 1, radius, phase, stretchStiffness, bendStiffness, shearStiffness, 0.0f, 1.0f); + CreateSpringGrid(Vec3(-0.6f, 2.3f, -0.6f), dimx, dimz, 1, radius, phase, stretchStiffness, bendStiffness, shearStiffness, 0.0f, 1.0f); + CreateSpringGrid(Vec3(-0.6f, 2.0f, -0.6f), dimx, dimz, 1, radius, phase, stretchStiffness, bendStiffness, shearStiffness, 0.0f, 1.0f); + + Vec3 lower, upper; + GetParticleBounds(lower, upper); + + Mesh* sphere = ImportMesh(GetFilePathByPlatform("../../data/sphere.ply").c_str()); + sphere->Normalize(); + + NvFlexTriangleMeshId mesh = CreateTriangleMesh(sphere); + AddTriangleMesh(mesh, Vec3(), Quat(), 2.0f); + + delete sphere; +#else + // This scene can cause the cloth to bounce + // Might need to run it a few times to repro + CreateSpringGrid(Vec3(-0.6f, 2.9f, -0.6f), dimx, dimz, 1, radius, phase, stretchStiffness, bendStiffness, shearStiffness, 0.0f, 1.0f); + + Vec3 lower, upper; + GetParticleBounds(lower, upper); + + Mesh* disc = CreateDiscMesh(2.0f, 300); + disc->m_positions[0].y -= 0.25f; + disc->CalculateNormals(); + NvFlexTriangleMeshId mesh = CreateTriangleMesh(disc); + AddTriangleMesh(mesh, Vec3(0.0f, 2.88f, 1.0f), Quat(), 1.0f); + delete disc; + + Mesh* disc1 = CreateDiscMesh(2.0f, 250); + disc1->m_positions[0].y -= 0.25f; + disc1->CalculateNormals(); + NvFlexTriangleMeshId mesh1 = CreateTriangleMesh(disc1); + AddTriangleMesh(mesh1, Vec3(1.0f, 1.5f, 0.0f), Quat(), 1.0f); + delete disc1; +#endif + + g_params.radius = radius*1.0f; + g_params.dynamicFriction = 0.1625f; + g_params.dissipation = 0.0f; + g_params.numIterations = 8; + g_params.viscosity = 0.0f; + g_params.drag = 0.05f; + g_params.collisionDistance = radius; + g_params.shapeCollisionMargin = radius*0.1f; + g_params.relaxationFactor = 1.3f; + + g_numSubsteps = 3; + + + g_windStrength = 0.0f; + + // draw options + g_drawPoints = true; + g_drawSprings = false; + } +}; + diff --git a/demo/scenes/dambreak.h b/demo/scenes/dambreak.h new file mode 100644 index 0000000..c2f9a40 --- /dev/null +++ b/demo/scenes/dambreak.h @@ -0,0 +1,62 @@ + + +class DamBreak : public Scene +{ +public: + + DamBreak(const char* name, float radius) : Scene(name), mRadius(radius) {} + + virtual void Initialize() + { + const float radius = mRadius; + const float restDistance = mRadius*0.65f; + + int dx = int(ceilf(1.0f / restDistance)); + int dy = int(ceilf(2.0f / restDistance)); + int dz = int(ceilf(1.0f / restDistance)); + + CreateParticleGrid(Vec3(0.0f, restDistance, 0.0f), dx, dy, dz, restDistance, Vec3(0.0f), 1.0f, false, 0.0f, NvFlexMakePhase(0, eNvFlexPhaseSelfCollide | eNvFlexPhaseFluid), restDistance*0.01f); + + g_sceneLower = Vec3(0.0f, 0.0f, -0.5f); + g_sceneUpper = Vec3(3.0f, 0.0f, -0.5f); + + g_numSubsteps = 2; + + g_params.fluid = true; + g_params.radius = radius; + g_params.fluidRestDistance = restDistance; + g_params.dynamicFriction = 0.f; + g_params.restitution = 0.001f; + + g_params.numIterations = 3; + g_params.relaxationFactor = 1.0f; + + g_params.smoothing = 0.4f; + g_params.anisotropyScale = 3.0f / radius; + + g_params.viscosity = 0.001f; + g_params.cohesion = 0.1f; + g_params.vorticityConfinement = 80.0f; + g_params.surfaceTension = 0.0f; + + g_params.numPlanes = 5; + + // limit velocity to CFL condition + g_params.maxSpeed = 0.5f*radius*g_numSubsteps / g_dt; + + g_maxDiffuseParticles = 0; + + g_fluidColor = Vec4(0.113f, 0.425f, 0.55f, 1.0f); + + g_waveFrequency = 1.0f; + g_waveAmplitude = 2.0f; + g_waveFloorTilt = 0.0f; + + // draw options + g_drawPoints = true; + g_drawEllipsoids = false; + g_drawDiffuse = true; + } + + float mRadius; +}; diff --git a/demo/scenes/darts.h b/demo/scenes/darts.h new file mode 100644 index 0000000..594a2ed --- /dev/null +++ b/demo/scenes/darts.h @@ -0,0 +1,59 @@ + +class Darts : public Scene +{ +public: + + Darts(const char* name) : Scene(name) {} + + void Initialize() + { + float radius = 0.1f; + int phase = NvFlexMakePhase(0, 0); + + if (1) + { + Vec3 v = Vec3(10.0f, 0.0f, 0.0f); + + float y = 8.0f; + + g_buffers->positions.push_back(Vec4(0.0f, y, 0.0f, 1.0f)); + g_buffers->velocities.push_back(v); + g_buffers->phases.push_back(phase); + + g_buffers->positions.push_back(Vec4(-1.0f, y, -0.5f, 0.9f)); + g_buffers->velocities.push_back(v); + g_buffers->phases.push_back(phase); + + g_buffers->positions.push_back(Vec4(-1.0f, y, 0.5f, 0.9f)); + g_buffers->velocities.push_back(v); + g_buffers->phases.push_back(phase); + + g_buffers->triangles.push_back(0); + g_buffers->triangles.push_back(1); + g_buffers->triangles.push_back(2); + g_buffers->triangleNormals.push_back(0.0f); + + CreateSpring(0, 1, 1.0f); + CreateSpring(1, 2, 1.0f); + CreateSpring(2, 0, 1.0f); + + g_buffers->positions[0].y -= radius*2.5f; + //g_buffers->positions[0].x = 1.0f; + //g_buffers->positions[1].y += radius; + } + + g_params.drag = 0.01f; + g_params.lift = 0.1f; + g_params.dynamicFriction = 0.25f; + //g_params.gravity[1] = 0.0f; + + g_drawPoints = false; + } + + void Update() + { + g_params.wind[0] = 0.0f; + g_params.wind[1] = 0.0f; + g_params.wind[2] = 0.0f; + } +}; diff --git a/demo/scenes/debris.h b/demo/scenes/debris.h new file mode 100644 index 0000000..39013ff --- /dev/null +++ b/demo/scenes/debris.h @@ -0,0 +1,319 @@ + +class RigidDebris : public Scene +{ +public: + + RigidDebris(const char* name) : Scene(name) {} + + struct Instance + { + Vec3 mTranslation; + Quat mRotation; + float mLifetime; + + int mGroup; + int mParticleOffset; + + int mMeshIndex; + }; + + struct MeshBatch + { + GpuMesh* mMesh; + NvFlexExtAsset* mAsset; + + std::vector<Matrix44> mInstanceTransforms; + }; + + struct MeshAsset + { + const char* file; + float scale; + }; + + void Initialize() + { + float radius = 0.1f; + + const int numMeshes = 8; + MeshAsset meshes[numMeshes] = + { + { "../../data/rocka.ply", 0.2f }, + { "../../data/box.ply", 0.1f }, + { "../../data/torus.obj", 0.3f }, + { "../../data/rockd.ply", 0.2f }, + { "../../data/banana.obj", 0.3f }, + { "../../data/rocka.ply", 0.2f }, + { "../../data/box.ply", 0.1f }, + { "../../data/rockd.ply", 0.2f }, + //"../../data/rockf.ply" + }; + + for (int i = 0; i < numMeshes; ++i) + { + Mesh* mesh = ImportMesh(GetFilePathByPlatform(meshes[i].file).c_str()); + mesh->Normalize(meshes[i].scale); + + const float spacing = radius*0.5f; + + MeshBatch b; + b.mAsset = NvFlexExtCreateRigidFromMesh((float*)&mesh->m_positions[0], int(mesh->m_positions.size()), (int*)&mesh->m_indices[0], mesh->m_indices.size(), spacing, -spacing*0.5f); + b.mMesh = CreateGpuMesh(mesh); + + mBatches.push_back(b); + } + + Mesh* level = ImportMeshFromBin(GetFilePathByPlatform("../../data/testzone.bin").c_str()); + level->Transform(TranslationMatrix(Point3(-10.0f, 0.0f, 10.0f))); + + NvFlexTriangleMeshId mesh = CreateTriangleMesh(level); + AddTriangleMesh(mesh, Vec3(), Quat(), 1.0f); + + delete level; + + g_params.radius = radius; + g_params.dynamicFriction = 0.6f; + g_params.staticFriction = 0.35f; + g_params.particleFriction = 0.25f; + g_params.dissipation = 0.0f; + g_params.numIterations = 4; + g_params.viscosity = 0.0f; + g_params.drag = 0.0f; + g_params.lift = 0.0f; + g_params.numPlanes = 0; + g_params.collisionDistance = radius*0.5f; + g_params.particleCollisionMargin = radius*0.25f; + + g_numExtraParticles = 32000; + + g_drawPoints = false; + + g_numSubsteps = 2; + + g_lightDistance *= 3.0f; + + mAttractForce = 0.0f; + + mGroupCounter = 0; + mInstances.resize(0); + } + + void Update() + { + // copy transforms out + for (int i = 0; i < int(mInstances.size()); ++i) + { + mInstances[i].mTranslation = g_buffers->rigidTranslations[i]; + mInstances[i].mRotation = g_buffers->rigidRotations[i]; + } + + if (g_emit) + { + // emit new debris + int numToEmit = 1;//Rand()%8; + + int particleOffset = NvFlexGetActiveCount(g_flex); + + for (int i = 0; i < numToEmit; ++i) + { + // choose a random mesh to emit + const int meshIndex = Rand() % mBatches.size(); + + NvFlexExtAsset* asset = mBatches[meshIndex].mAsset; + + // check we can fit in the container + if (int(g_buffers->positions.size()) - particleOffset < asset->numParticles) + break; + + Instance inst; + inst.mLifetime = 1000.0f;// Randf(5.0f, 60.0f); + inst.mParticleOffset = particleOffset; + inst.mRotation = QuatFromAxisAngle(UniformSampleSphere(), Randf()*k2Pi); + + float spread = 0.2f; + inst.mTranslation = g_emitters[0].mPos + Vec3(Randf(-spread, spread), Randf(-spread, spread), 0.0f); + inst.mMeshIndex = meshIndex; + + Vec3 linearVelocity = g_emitters[0].mDir*15.0f;//*Randf(5.0f, 10.0f);//Vec3(Randf(0.0f, 10.0f), 0.0f, 0.0f); + Vec3 angularVelocity = Vec3(UniformSampleSphere()*Randf()*k2Pi); + + inst.mGroup = mGroupCounter++; + + const int phase = NvFlexMakePhase(inst.mGroup, 0); + + // generate initial particle positions + for (int j = 0; j < asset->numParticles; ++j) + { + Vec3 localPos = Vec3(&asset->particles[j * 4]) - Vec3(&asset->shapeCenters[0]); + + g_buffers->positions[inst.mParticleOffset + j] = Vec4(inst.mTranslation + inst.mRotation*localPos, 1.0f); + g_buffers->velocities[inst.mParticleOffset + j] = linearVelocity + Cross(angularVelocity, localPos); + g_buffers->phases[inst.mParticleOffset + j] = phase; + } + + particleOffset += asset->numParticles; + + mInstances.push_back(inst); + } + } + + // destroy old debris pieces + for (int i = 0; i < int(mInstances.size());) + { + Instance& inst = mInstances[i]; + + inst.mLifetime -= g_dt; + + if (inst.mLifetime <= 0.0f) + { + inst = mInstances.back(); + mInstances.pop_back(); + } + else + { + ++i; + } + } + + // compact instances + static std::vector<Vec4> particles(g_buffers->positions.size()); + static std::vector<Vec3> velocities(g_buffers->velocities.size()); + static std::vector<int> phases(g_buffers->phases.size()); + + g_buffers->rigidTranslations.resize(0); + g_buffers->rigidRotations.resize(0); + g_buffers->rigidCoefficients.resize(0); + g_buffers->rigidIndices.resize(0); + g_buffers->rigidLocalPositions.resize(0); + g_buffers->rigidOffsets.resize(0); + + // start index + g_buffers->rigidOffsets.push_back(0); + + // clear mesh batches + for (int i = 0; i < int(mBatches.size()); ++i) + mBatches[i].mInstanceTransforms.resize(0); + + numActive = 0; + + for (int i = 0; i < int(mInstances.size()); ++i) + { + Instance& inst = mInstances[i]; + + NvFlexExtAsset* asset = mBatches[inst.mMeshIndex].mAsset; + + for (int j = 0; j < asset->numParticles; ++j) + { + particles[numActive + j] = g_buffers->positions[inst.mParticleOffset + j]; + velocities[numActive + j] = g_buffers->velocities[inst.mParticleOffset + j]; + phases[numActive + j] = g_buffers->phases[inst.mParticleOffset + j]; + } + + g_buffers->rigidCoefficients.push_back(1.0f); + g_buffers->rigidTranslations.push_back(inst.mTranslation); + g_buffers->rigidRotations.push_back(inst.mRotation); + + for (int j = 0; j < asset->numShapeIndices; ++j) + { + g_buffers->rigidLocalPositions.push_back(Vec3(&asset->particles[j * 4]) - Vec3(&asset->shapeCenters[0])); + g_buffers->rigidIndices.push_back(asset->shapeIndices[j] + numActive); + } + + g_buffers->rigidOffsets.push_back(g_buffers->rigidIndices.size()); + + mInstances[i].mParticleOffset = numActive; + + // Draw transform + Matrix44 xform = TranslationMatrix(Point3(inst.mTranslation - inst.mRotation*Vec3(asset->shapeCenters)))*RotationMatrix(inst.mRotation); + mBatches[inst.mMeshIndex].mInstanceTransforms.push_back(xform); + + numActive += asset->numParticles; + } + + // update particle buffers + g_buffers->positions.assign(&particles[0], particles.size()); + g_buffers->velocities.assign(&velocities[0], velocities.size()); + g_buffers->phases.assign(&phases[0], phases.size()); + + // rebuild active indices + g_buffers->activeIndices.resize(numActive); + for (int i = 0; i < numActive; ++i) + g_buffers->activeIndices[i] = i; + + if (mAttractForce != 0.0f) + { + const Vec3 forward(-sinf(g_camAngle.x)*cosf(g_camAngle.y), sinf(g_camAngle.y), -cosf(g_camAngle.x)*cosf(g_camAngle.y)); + + Vec3 attractPos = g_camPos + forward*5.0f; + float invRadius = 1.0f / 5.0f; + + for (int i = 0; i < int(g_buffers->velocities.size()); ++i) + { + Vec3 dir = Vec3(g_buffers->positions[i]) - attractPos; + float d = Length(dir); + + g_buffers->velocities[i] += Normalize(dir)*Randf(0.0, 1.0f)*mAttractForce*Max(0.0f, 1.0f - d*invRadius); + } + } + } + + virtual void PostInitialize() + { + g_sceneLower = Vec3(-5.0f, 0.0f, 0.0f); + g_sceneUpper = g_sceneLower + Vec3(10.0f, 10.0f, 5.0f); + } + + virtual void Sync() + { + NvFlexSetRigids(g_flex, g_buffers->rigidOffsets.buffer, g_buffers->rigidIndices.buffer, g_buffers->rigidLocalPositions.buffer, g_buffers->rigidLocalNormals.buffer, g_buffers->rigidCoefficients.buffer, g_buffers->rigidRotations.buffer, g_buffers->rigidTranslations.buffer, g_buffers->rigidOffsets.size() - 1, g_buffers->rigidIndices.size()); + } + + virtual void KeyDown(int key) + { + if (key == 'B') + { + float bombStrength = 10.0f; + + Vec3 bombPos = g_emitters[0].mPos + g_emitters[0].mDir*5.0f; + bombPos.y -= 5.0f; + + for (int i = 0; i < int(g_buffers->velocities.size()); ++i) + { + Vec3 dir = Vec3(g_buffers->positions[i]) - bombPos; + + g_buffers->velocities[i] += Normalize(dir)*bombStrength*Randf(0.0, 1.0f); + } + } + + if (key == 'V') + { + if (mAttractForce == 0.0f) + mAttractForce = -1.5f; + else + mAttractForce = 0.0f; + } + } + + void Draw(int pass) + { + if (!g_drawMesh) + return; + + for (int b = 0; b < int(mBatches.size()); ++b) + { + if (mBatches[b].mInstanceTransforms.size()) + { + extern Colour gColors[]; + DrawGpuMeshInstances(mBatches[b].mMesh, &mBatches[b].mInstanceTransforms[0], mBatches[b].mInstanceTransforms.size(), Vec3(gColors[b % 8])); + } + } + } + + float mAttractForce; + + std::vector<MeshBatch> mBatches; + int numActive; + + int mGroupCounter; + std::vector<Instance> mInstances; +}; diff --git a/demo/scenes/deformables.h b/demo/scenes/deformables.h new file mode 100644 index 0000000..2de87d7 --- /dev/null +++ b/demo/scenes/deformables.h @@ -0,0 +1,42 @@ + + +class Deformables : public Scene +{ +public: + + Deformables(const char* name) : Scene(name) {} + + void Initialize() + { + g_params.dynamicFriction = 0.25f; + + for (int i=0; i < 5; i++) + AddRandomConvex(10, Vec3(i*2.0f, 0.0f, Randf(0.0f, 2.0f)), 0.5f, 1.0f, Vec3(0.0f, 1.0f, 0.0f), Randf(0.0f, k2Pi)); + + if (0) + { + int group = 0; + + float minSize = 0.2f; + float maxSize = 0.4f; + + for (int z=0; z < 1; ++z) + for (int y=0; y < 1; ++y) + for (int x=0; x < 5; ++x) + CreateRandomBody(12, Vec3(2.0f*x, 2.0f + y, 1.0f + 1.0f*z), minSize, maxSize, RandomUnitVector(), Randf(0.0f, k2Pi), 1.0f, NvFlexMakePhase(group++, 0), 0.25f); + } + else + { + CreateTetMesh(GetFilePathByPlatform("../../data/tets/duck.tet").c_str(), Vec3(2.0f, 1.0f, 2.0f), 2.00000105f, 1.0f, 0); + CreateTetMesh(GetFilePathByPlatform("../../data/tets/duck.tet").c_str(), Vec3(2.0f, 3.0f, 2.0f), 2.00000105f, 1.0f, 1); + } + + g_params.numIterations = 5; + g_params.relaxationFactor = 1.0f; + g_params.radius = 0.025f; + + // draw options + g_drawPoints = true; + g_drawSprings = false; + } +}; diff --git a/demo/scenes/envcloth.h b/demo/scenes/envcloth.h new file mode 100644 index 0000000..7405739 --- /dev/null +++ b/demo/scenes/envcloth.h @@ -0,0 +1,77 @@ + + +class EnvironmentalCloth: public Scene +{ +public: + + EnvironmentalCloth(const char* name, int dimx, int dimz, int gridx, int gridz) : + Scene(name), + mDimX(dimx), + mDimZ(dimz), + mGridX(gridx), + mGridZ(gridz) {} + + virtual void Initialize() + { + float scale = 1.0f; + + float minSize = 0.5f*scale; + float maxSize = 1.0f*scale; + + for (int i=0; i < 5; i++) + AddRandomConvex(10, Vec3(i*2.0f, 0.0f, Randf(0.0f, 2.0f)), minSize, maxSize, Vec3(0.0f, 1.0f, 0.0f), Randf(0.0f, k2Pi)); + + float stretchStiffness = 0.9f; + float bendStiffness = 0.8f; + float shearStiffness = 0.5f; + + int dimx = mDimX; + int dimz = mDimZ; + float radius = 0.05f*scale; + g_params.gravity[1] *= scale; + + int gridx = mGridX; + int gridz = mGridZ; + + int clothIndex = 0; + int phase = NvFlexMakePhase(0, eNvFlexPhaseSelfCollide); + + for (int x=0; x < gridx; ++x) + { + for (int y=0; y < 1; ++y) + { + for (int z=0; z < gridz; ++z) + { + clothIndex++; + + CreateSpringGrid(Vec3(x*dimx*radius, scale*(1.0f + z*0.5f), z*dimx*radius), dimx, dimz, 1, radius, phase, stretchStiffness, bendStiffness, shearStiffness, Vec3(Randf(-0.2f, 0.2f)), 1.0f); + } + } + } + + g_params.radius = radius*1.05f; + g_params.dynamicFriction = 0.25f; + g_params.dissipation = 0.0f; + g_params.numIterations = 8; + g_params.viscosity = 0.0f; + g_params.drag = 0.1f; + g_params.lift = 0.5f; + g_params.collisionDistance = 0.05f; + + // cloth converges faster with a global relaxation factor + g_params.relaxationMode = eNvFlexRelaxationGlobal; + g_params.relaxationFactor = 0.25f; + + g_windStrength = 0.0f; + g_numSubsteps = 2; + + // draw options + g_drawPoints = false; + g_drawSprings = false; + } + + int mDimX; + int mDimZ; + int mGridX; + int mGridZ; +}; diff --git a/demo/scenes/flag.h b/demo/scenes/flag.h new file mode 100644 index 0000000..c8bf3ff --- /dev/null +++ b/demo/scenes/flag.h @@ -0,0 +1,83 @@ + +class FlagCloth: public Scene +{ +public: + + FlagCloth(const char* name) : Scene(name) {} + + void Initialize() + { + int dimx = 64; + int dimz = 32; + float radius = 0.05f; + + float stretchStiffness = 0.9f; + float bendStiffness = 1.0f; + float shearStiffness = 0.9f; + int phase = NvFlexMakePhase(0, eNvFlexPhaseSelfCollide); + + CreateSpringGrid(Vec3(0.0f, 0.0f, -3.0f), dimx, dimz, 1, radius, phase, stretchStiffness, bendStiffness, shearStiffness, 0.0f, 1.0f); + + const int c1 = 0; + const int c2 = dimx*(dimz-1); + + g_buffers->positions[c1].w = 0.0f; + g_buffers->positions[c2].w = 0.0f; + + // add tethers + for (int i=0; i < int(g_buffers->positions.size()); ++i) + { + // hack to rotate cloth + swap(g_buffers->positions[i].y, g_buffers->positions[i].z); + g_buffers->positions[i].y *= -1.0f; + + g_buffers->velocities[i] = RandomUnitVector()*0.1f; + + float minSqrDist = FLT_MAX; + + if (i != c1 && i != c2) + { + float stiffness = -0.8f; + float give = 0.1f; + + float sqrDist = LengthSq(Vec3(g_buffers->positions[c1])-Vec3(g_buffers->positions[c2])); + + if (sqrDist < minSqrDist) + { + CreateSpring(c1, i, stiffness, give); + CreateSpring(c2, i, stiffness, give); + + minSqrDist = sqrDist; + } + } + } + + g_params.radius = radius*1.0f; + g_params.dynamicFriction = 0.25f; + g_params.dissipation = 0.0f; + g_params.numIterations = 4; + g_params.drag = 0.06f; + g_params.relaxationFactor = 1.0f; + + g_numSubsteps = 2; + + // draw options + g_drawPoints = false; + g_drawSprings = false; + g_windFrequency *= 2.0f; + g_windStrength = 10.0f; + + } + + void Update() + { + const Vec3 kWindDir = Vec3(3.0f, 15.0f, 0.0f); + const float kNoise = fabsf(Perlin1D(g_windTime*0.05f, 2, 0.25f)); + Vec3 wind = g_windStrength*kWindDir*Vec3(kNoise, kNoise*0.1f, -kNoise*0.1f); + + g_params.wind[0] = wind.x; + g_params.wind[1] = wind.y; + g_params.wind[2] = wind.z; + } +}; + diff --git a/demo/scenes/fluidblock.h b/demo/scenes/fluidblock.h new file mode 100644 index 0000000..82de2cb --- /dev/null +++ b/demo/scenes/fluidblock.h @@ -0,0 +1,72 @@ + + +class FluidBlock : public Scene +{ +public: + + FluidBlock(const char* name) : Scene(name) {} + + virtual void Initialize() + { + float minSize = 0.5f; + float maxSize = 0.7f; + + float radius = 0.1f; + float restDistance = radius*0.55f; + int group = 0; + + AddRandomConvex(6, Vec3(5.0f, -0.1f, 0.6f), 1.0f, 1.0f, Vec3(1.0f, 1.0f, 0.0f), 0.0f); + + float ly = 0.5f; + + AddRandomConvex(10, Vec3(2.5f, ly*0.5f, 1.f), minSize*0.5f, maxSize*0.5f, Vec3(0.0f, 1.0f, 0.0f), Randf(0.0f, 2.0f*kPi)); + + AddRandomConvex(12, Vec3(3.8f, ly-0.5f, 1.f), minSize, maxSize, Vec3(1.0f, 0.0f, 0.0f), Randf(0.0f, 2.0f*kPi)); + AddRandomConvex(12, Vec3(3.8f, ly-0.5f, 2.6f), minSize, maxSize, Vec3(1.0f, 0.0f, 0.0f), 0.2f + Randf(0.0f, 2.0f*kPi)); + + AddRandomConvex(12, Vec3(4.6f, ly, 0.2f), minSize, maxSize, Vec3(1.0f, 0.0f, 1.0f), Randf(0.0f, 2.0f*kPi)); + AddRandomConvex(12, Vec3(4.6f, ly, 2.0f), minSize, maxSize, Vec3(1.0f, 0.0f, 1.0f), 0.2f + Randf(0.0f, 2.0f*kPi)); + + float size = 0.3f; + for (int i=0; i < 32; ++i) + CreateParticleShape(GetFilePathByPlatform("../../data/torus.obj").c_str(), Vec3(4.5f, 2.0f + radius*2.0f*i, 1.0f), size, 0.0f, radius*0.5f, Vec3(0.0f, 0.0f, 0.0f), 0.125f, true, 1.0f, NvFlexMakePhase(group++, 0), true, 0.0f); + + g_numSolidParticles = g_buffers->positions.size(); + + float sizex = 1.76f; + float sizey = 2.20f; + float sizez = 3.50f; + + int x = int(sizex/restDistance); + int y = int(sizey/restDistance); + int z = int(sizez/restDistance); + + CreateParticleGrid(Vec3(0.0f, restDistance*0.5f, 0.0f), x, y, z, restDistance, Vec3(0.0f), 1.0f, false, 0.0f, NvFlexMakePhase(group++, eNvFlexPhaseSelfCollide | eNvFlexPhaseFluid)); + + g_params.radius = radius; + g_params.dynamicFriction = 0.0f; + g_params.fluid = true; + g_params.viscosity = 0.0f; + g_params.numIterations = 3; + g_params.vorticityConfinement = 40.f; + g_params.anisotropyScale = 20.0f; + g_params.fluidRestDistance = restDistance; + g_params.numPlanes = 5; + //g_params.cohesion = 0.05f; + + g_maxDiffuseParticles = 128*1024; + g_diffuseScale = 0.75f; + + g_waveFloorTilt = -0.025f; + + g_lightDistance *= 0.5f; + + // draw options + g_drawDensity = true; + g_drawDiffuse = true; + g_drawEllipsoids = true; + g_drawPoints = false; + + g_warmup = true; + } +};
\ No newline at end of file diff --git a/demo/scenes/fluidclothcoupling.h b/demo/scenes/fluidclothcoupling.h new file mode 100644 index 0000000..403a775 --- /dev/null +++ b/demo/scenes/fluidclothcoupling.h @@ -0,0 +1,192 @@ + +class FluidClothCoupling : public Scene +{ +public: + + FluidClothCoupling(const char* name, bool viscous) : Scene(name), mViscous(viscous) {} + + void Initialize() + { + float stretchStiffness = 1.0f; + float bendStiffness = 0.4f; + float shearStiffness = 0.4f; + + int dimx = 32; + int dimy = 32; + float radius = 0.1f; + float invmass = 0.25f; + int group = 0; + + { + int clothStart = 0; + + CreateSpringGrid(Vec3(0.0f, 1.0f, 0.0f), dimx, dimy, 1, radius*0.25f, NvFlexMakePhase(group++, 0), stretchStiffness, bendStiffness, shearStiffness, Vec3(0.0f), invmass); + + int corner0 = clothStart + 0; + int corner1 = clothStart + dimx-1; + int corner2 = clothStart + dimx*(dimy-1); + int corner3 = clothStart + dimx*dimy-1; + + g_buffers->positions[corner0].w = 0.0f; + g_buffers->positions[corner1].w = 0.0f; + g_buffers->positions[corner2].w = 0.0f; + g_buffers->positions[corner3].w = 0.0f; + + // add tethers + for (int i=clothStart; i < int(g_buffers->positions.size()); ++i) + { + float x = g_buffers->positions[i].x; + g_buffers->positions[i].y = 1.5f - sinf(DegToRad(25.0f))*x; + g_buffers->positions[i].x = cosf(DegToRad(25.0f))*x; + + //g_buffers->positions[i].y += 0.5f-g_buffers->positions[i].x; + + if (i != corner0 && i != corner1 && i != corner2 && i != corner3) + { + float stiffness = -0.5f; + float give = 0.05f; + + CreateSpring(corner0, i, stiffness, give); + CreateSpring(corner1, i, stiffness, give); + CreateSpring(corner2, i, stiffness, give); + CreateSpring(corner3, i, stiffness, give); + } + } + + g_buffers->positions[corner1] = g_buffers->positions[corner0] + (g_buffers->positions[corner1]-g_buffers->positions[corner0])*0.9f; + g_buffers->positions[corner2] = g_buffers->positions[corner0] + (g_buffers->positions[corner2]-g_buffers->positions[corner0])*0.9f; + g_buffers->positions[corner3] = g_buffers->positions[corner0] + (g_buffers->positions[corner3]-g_buffers->positions[corner0])*0.9f; + } + + { + // net + int clothStart = g_buffers->positions.size(); + + CreateSpringGrid(Vec3(0.75f, 1.0f, 0.0f), dimx, dimy, 1, radius*0.25f, NvFlexMakePhase(group++, 0), stretchStiffness, bendStiffness, shearStiffness, Vec3(0.0f), invmass); + + int corner0 = clothStart + 0; + int corner1 = clothStart + dimx-1; + int corner2 = clothStart + dimx*(dimy-1); + int corner3 = clothStart + dimx*dimy-1; + + g_buffers->positions[corner0].w = 0.0f; + g_buffers->positions[corner1].w = 0.0f; + g_buffers->positions[corner2].w = 0.0f; + g_buffers->positions[corner3].w = 0.0f; + + // add tethers + for (int i=clothStart; i < int(g_buffers->positions.size()); ++i) + { + if (i != corner0 && i != corner1 && i != corner2 && i != corner3) + { + float stiffness = -0.5f; + float give = 0.1f; + + CreateSpring(corner0, i, stiffness, give); + CreateSpring(corner1, i, stiffness, give); + CreateSpring(corner2, i, stiffness, give); + CreateSpring(corner3, i, stiffness, give); + } + } + + g_buffers->positions[corner1] = g_buffers->positions[corner0] + (g_buffers->positions[corner1]-g_buffers->positions[corner0])*0.8f; + g_buffers->positions[corner2] = g_buffers->positions[corner0] + (g_buffers->positions[corner2]-g_buffers->positions[corner0])*0.8f; + g_buffers->positions[corner3] = g_buffers->positions[corner0] + (g_buffers->positions[corner3]-g_buffers->positions[corner0])*0.8f; + + } + + { + // net + int clothStart = g_buffers->positions.size(); + + CreateSpringGrid(Vec3(1.5f, 0.5f, 0.0f), dimx, dimy, 1, radius*0.25f, NvFlexMakePhase(group++, 0), stretchStiffness, bendStiffness, shearStiffness, Vec3(0.0f), invmass); + + int corner0 = clothStart + 0; + int corner1 = clothStart + dimx-1; + int corner2 = clothStart + dimx*(dimy-1); + int corner3 = clothStart + dimx*dimy-1; + + g_buffers->positions[corner0].w = 0.0f; + g_buffers->positions[corner1].w = 0.0f; + g_buffers->positions[corner2].w = 0.0f; + g_buffers->positions[corner3].w = 0.0f; + + // add tethers + for (int i=clothStart; i < int(g_buffers->positions.size()); ++i) + { + if (i != corner0 && i != corner1 && i != corner2 && i != corner3) + { + float stiffness = -0.5f; + float give = 0.1f; + + CreateSpring(corner0, i, stiffness, give); + CreateSpring(corner1, i, stiffness, give); + CreateSpring(corner2, i, stiffness, give); + CreateSpring(corner3, i, stiffness, give); + } + } + + g_buffers->positions[corner1] = g_buffers->positions[corner0] + (g_buffers->positions[corner1]-g_buffers->positions[corner0])*0.8f; + g_buffers->positions[corner2] = g_buffers->positions[corner0] + (g_buffers->positions[corner2]-g_buffers->positions[corner0])*0.8f; + g_buffers->positions[corner3] = g_buffers->positions[corner0] + (g_buffers->positions[corner3]-g_buffers->positions[corner0])*0.8f; + + } + + g_numSolidParticles = g_buffers->positions.size(); + g_ior = 1.0f; + + g_numExtraParticles = 64*1024; + + g_params.radius = radius; + g_params.fluid = true; + g_params.numIterations = 5; + g_params.vorticityConfinement = 0.0f; + g_params.anisotropyScale = 30.0f; + g_params.fluidRestDistance = g_params.radius*0.5f; + g_params.smoothing = 0.5f; + g_params.solidPressure = 0.25f; + g_numSubsteps = 3; + //g_params.numIterations = 6; + + g_params.maxSpeed = 0.5f*g_numSubsteps*g_params.radius/g_dt; + + g_maxDiffuseParticles = 32*1024; + g_diffuseScale = 0.5f; + g_lightDistance = 3.0f; + + // for viscous goo + if (mViscous) + { + g_fluidColor = Vec4(0.0f, 0.8f, 0.2f, 1.0f); + + g_params.dynamicFriction = 0.3f; + g_params.cohesion = 0.025f; + g_params.viscosity = 50.85f; + } + else + { + g_params.dynamicFriction = 0.125f; + g_params.viscosity = 0.1f; + g_params.cohesion = 0.0035f; + g_params.viscosity = 4.0f; + } + + g_emitters[0].mEnabled = false; + + Emitter e; + e.mDir = Normalize(Vec3(1.0f, 0.0f, 0.0f)); + e.mEnabled = true; + e.mPos = Vec3(-0.25f, 1.75f, 0.5f); + e.mRight = Cross(e.mDir, Vec3(0.0f, 0.0f, 1.0f)); + e.mSpeed = (g_params.fluidRestDistance/(g_dt*2.0f)); + + g_emitters.push_back(e); + + // draw options + g_drawPoints = false; + g_drawSprings = false; + g_drawEllipsoids = true; + } + + bool mViscous; +};
\ No newline at end of file diff --git a/demo/scenes/forcefield.h b/demo/scenes/forcefield.h new file mode 100644 index 0000000..1ffcd12 --- /dev/null +++ b/demo/scenes/forcefield.h @@ -0,0 +1,92 @@ + + +class ForceField : public Scene +{ +public: + + + ForceField(const char* name) : Scene(name) + { + } + + virtual void Initialize() + { + const float radius = 0.01f; + const int phase = NvFlexMakePhase(0, eNvFlexPhaseSelfCollide); + + CreateParticleGrid(Vec3(-1.0f, radius, 0.0f), 200, 6, 50, radius*0.5f, Vec3(0.0f), 1.0f, false, 0.0f, phase); + + g_params.radius = radius*1.0f; + g_params.dynamicFriction = 0.4f; + g_params.staticFriction = 0.4f; + g_params.particleFriction = 0.25f; + g_params.dissipation = 0.0f; + g_params.numIterations = 2; + g_params.viscosity = 0.0f; + + g_numSubsteps = 2; + + // draw options + g_drawPoints = true; + + callback = NULL; + + } + + virtual void PostInitialize() + { + // free previous callback, todo: destruction phase for tests + if (callback) + NvFlexExtDestroyForceFieldCallback(callback); + + // create new callback + callback = NvFlexExtCreateForceFieldCallback(g_flex); + + // expand scene bounds to include force field + g_sceneLower -= Vec3(1.0f); + g_sceneUpper += Vec3(1.0f); + } + + void DrawCircle(const Vec3& pos, const Vec3& u, const Vec3& v, float radius, int segments) + { + BeginLines(); + + Vec3 start = pos + radius*v; + + for (int i=1; i <=segments; ++i) + { + float theta = k2Pi*(float(i)/segments); + Vec3 end = pos + radius*sinf(theta)*u + radius*cosf(theta)*v; + + DrawLine(start, end, Vec4(1.0f)); + + start = end; + } + + EndLines(); + } + + virtual void Draw(int phase) + { + DrawCircle(forcefield.mPosition, Vec3(1.0f, 0.0f, 0.0f), Vec3(0.0f, 1.0f, 0.0f), forcefield.mRadius, 20); + DrawCircle(forcefield.mPosition, Vec3(0.0f, 0.0f, 1.0f), Vec3(0.0f, 1.0f, 0.0f), forcefield.mRadius, 20); + } + + virtual void Update() + { + float time = g_frame*g_dt; + + (Vec3&)forcefield.mPosition = Vec3((sinf(time)), 0.5f, 0.0f); + forcefield.mRadius = (sinf(time*1.5f)*0.5f + 0.5f); + forcefield.mStrength = -30.0f; + forcefield.mMode = eNvFlexExtModeForce; + forcefield.mLinearFalloff = true; + + NvFlexExtSetForceFields(callback, &forcefield, 1); + } + + NvFlexExtForceField forcefield; + + NvFlexExtForceFieldCallback* callback; + +};
\ No newline at end of file diff --git a/demo/scenes/frictionmoving.h b/demo/scenes/frictionmoving.h new file mode 100644 index 0000000..ae8ba8e --- /dev/null +++ b/demo/scenes/frictionmoving.h @@ -0,0 +1,93 @@ + +class FrictionMovingShape: public Scene +{ +public: + + FrictionMovingShape(const char* name, int type) : + Scene(name), mType(type) {} + + virtual void Initialize() + { + float stretchStiffness = 1.0f; + float bendStiffness = 0.5f; + float shearStiffness = 0.5f; + + float radius = 0.05f; + + int dimx = 40; + int dimz = 40; + int phase = NvFlexMakePhase(0, eNvFlexPhaseSelfCollide | eNvFlexPhaseSelfCollideFilter); + + float spacing = radius*0.8f; + + for (int i=0; i < 3; ++i) + CreateSpringGrid(Vec3(-dimx*spacing*0.5f, 1.5f + i*0.2f, -dimz*spacing*0.5f), dimx, dimz, 1, spacing, phase, stretchStiffness, bendStiffness, shearStiffness, 0.0f, 1.0f); + + g_params.radius = radius*1.0f; + g_params.dynamicFriction = 0.45f; + g_params.particleFriction = 0.45f; + g_params.dissipation = 0.0f; + g_params.numIterations = 8; + g_params.viscosity = 0.0f; + g_params.drag = 0.05f; + g_params.collisionDistance = radius*0.5f; + g_params.relaxationMode = eNvFlexRelaxationGlobal; + g_params.relaxationFactor = 0.25f; + g_params.numPlanes = 1; + + g_numSubsteps = 2; + + g_windStrength = 0.0f; + + // draw options + g_drawPoints = false; + g_drawSprings = false; + + g_lightDistance *= 1.5f; + + mTime = 0.0f; + } + + void Update() + { + ClearShapes(); + + mTime += g_dt; + + // let cloth settle on object + float startTime = 1.0f; + + float time = Max(0.0f, mTime-startTime); + float lastTime = Max(0.0f, time-g_dt); + + const float rotationSpeed = 1.0f; + const float translationSpeed = 1.0f; + + Vec3 pos = Vec3(translationSpeed*(1.0f-cosf(time)), 0.5f, 0.0f); + Vec3 prevPos = Vec3(translationSpeed*(1.0f-cosf(lastTime)), 0.5f, 0.0f); + + Quat rot = QuatFromAxisAngle(Vec3(0.0f, 1.0f, 0.0f), 1.0f-cosf(rotationSpeed*time)); + Quat prevRot = QuatFromAxisAngle(Vec3(0.0f, 1.0f, 0.0f), 1.0f-cosf(rotationSpeed*lastTime)); + + switch(mType) + { + case 0: + AddBox(Vec3(1.0f, 0.5f, 1.0f), pos, rot); + break; + case 1: + AddSphere(0.5f, pos, rot); + break; + case 2: + AddCapsule(0.1f, 1.5f, pos, rot); + break; + }; + + g_buffers->shapePrevPositions[0] = Vec4(prevPos, 0.0f); + g_buffers->shapePrevRotations[0] = prevRot; + + UpdateShapes(); + } + + float mTime; + int mType; +};
\ No newline at end of file diff --git a/demo/scenes/frictionramp.h b/demo/scenes/frictionramp.h new file mode 100644 index 0000000..f9f36cf --- /dev/null +++ b/demo/scenes/frictionramp.h @@ -0,0 +1,40 @@ + + +class FrictionRamp : public Scene +{ +public: + + FrictionRamp(const char* name) : Scene(name) {} + + virtual void Initialize() + { + float radius = 0.1f; + + g_params.radius = radius; + g_params.dynamicFriction = 0.35f; + g_params.dissipation = 0.0f; + g_params.numIterations = 8; + g_params.viscosity = 0.0f; + g_params.drag = 0.0f; + g_params.lift = 0.0f; + g_params.collisionDistance = radius*0.5f; + + g_windStrength = 0.0f; + + g_numSubsteps = 1; + + // draw options + g_drawPoints = false; + g_wireframe = false; + g_drawSprings = false; + + for (int i = 0; i < 3; ++i) + { + // box + CreateParticleShape(GetFilePathByPlatform("../../data/box.ply").c_str(), Vec3(0.0f, 3.5f, -i*2.0f), 0.5f, 0.0f, radius, 0.0f, 1.0f, true, 1.0f, NvFlexMakePhase(i, 0), true, 0.0f); + + // ramp + AddBox(Vec3(5.0f, 0.25f, 1.f), Vec3(3.0f, 1.0f, -i*2.0f), QuatFromAxisAngle(Vec3(0.0f, 0.0f, 1.0f), DegToRad(-11.25f*(i + 1)))); + } + } +};
\ No newline at end of file diff --git a/demo/scenes/gamemesh.h b/demo/scenes/gamemesh.h new file mode 100644 index 0000000..6de6bd0 --- /dev/null +++ b/demo/scenes/gamemesh.h @@ -0,0 +1,191 @@ + +class GameMesh : public Scene +{ +public: + + GameMesh(const char* name, int scene) : Scene(name), mScene(scene) {} + + void Initialize() + { + Mesh* level = ImportMeshFromBin(GetFilePathByPlatform("../../data/testzone.bin").c_str()); + level->Normalize(100.0f); + level->Transform(TranslationMatrix(Point3(0.0f, -5.0f, 0.0f))); + level->CalculateNormals(); + + Vec3 lower, upper; + level->GetBounds(lower, upper); + Vec3 center = (lower+upper)*0.5f; + + NvFlexTriangleMeshId mesh = CreateTriangleMesh(level); + AddTriangleMesh(mesh, Vec3(), Quat(), 1.0f); + + delete level; + + int group = 0; + + // rigids + if (mScene == 0) + { + float radius = 0.05f; + + for (int z=0; z < 80; ++z) + for (int x=0; x < 80; ++x) + CreateParticleGrid( + center - Vec3(-16.0f, 0.0f, 15.0f) + 2.0f*Vec3(x*radius*2 - 1.0f, 1.0f + radius, 1.f + z*2.0f*radius) + Vec3(Randf(radius), 0.0f, Randf(radius)), + 2, 2 + int(Randf(0.0f, 4.0f)), 2, radius*0.9f, Vec3(0.0f), 1.0f, true, 1.0f, NvFlexMakePhase(group++, 0), 0.0f); + + // separte solid particle count + g_numSolidParticles = g_buffers->positions.size(); + + g_params.radius = radius; + g_params.dynamicFriction = 0.3f; + g_params.dissipation = 0.0f; + g_params.fluid = false; + g_params.fluidRestDistance = g_params.radius*0.5f; + g_params.viscosity = 0.05f; + g_params.anisotropyScale = 20.0f; + g_params.numIterations = 2; + g_params.numPlanes = 1; + g_params.sleepThreshold = g_params.radius*0.3f; + g_params.maxSpeed = g_numSubsteps*g_params.radius/g_dt; + g_params.collisionDistance = radius*0.5f; + g_params.shapeCollisionMargin = g_params.collisionDistance*0.05f; + + g_numSubsteps = 2; + + g_emitters[0].mEnabled = true; + g_emitters[0].mSpeed = 2.0f*(g_params.radius*0.5f)/g_dt; + + // draw options + g_drawPoints = true; + g_drawMesh = false; + } + + // basic particles + if (mScene == 1) + { + float radius = 0.1f; + + CreateParticleGrid(center - Vec3(2.0f, 7.0f, 2.0f) , 32, 64, 32, radius*1.02f, Vec3(0.0f), 1.0f, false, 0.0f, NvFlexMakePhase(0, eNvFlexPhaseSelfCollide), 0.0f); + + g_params.radius = radius; + g_params.dynamicFriction = 0.1f; + g_params.dissipation = 0.0f; + g_params.numIterations = 4; + g_params.numPlanes = 1; + g_params.fluid = false; + g_params.particleCollisionMargin = g_params.radius*0.1f; + g_params.restitution = 0.0f; + + g_params.collisionDistance = g_params.radius*0.5f; + g_params.shapeCollisionMargin = g_params.collisionDistance*0.05f; + + g_numSubsteps = 2; + + // draw options + g_drawPoints = true; + } + + // fluid particles + if (mScene == 2) + { + float radius = 0.1f; + float restDistance = radius*0.6f; + + CreateParticleGrid(center - Vec3(0.0f, 7.0f, 2.0f) , 32, 64, 32, restDistance, Vec3(0.0f), 1.0f, false, 0.0f, NvFlexMakePhase(0, eNvFlexPhaseSelfCollide | eNvFlexPhaseFluid), 0.0f); + + g_params.radius = radius; + g_params.dynamicFriction = 0.1f; + g_params.dissipation = 0.0f; + g_params.numPlanes = 1; + g_params.fluidRestDistance = restDistance; + g_params.viscosity = 0.5f; + g_params.numIterations = 3; + g_params.anisotropyScale = 30.0f; + g_params.smoothing = 0.5f; + g_params.fluid = true; + g_params.relaxationFactor = 1.0f; + g_params.restitution = 0.0f; + g_params.smoothing = 0.5f; + g_params.collisionDistance = g_params.radius*0.5f; + g_params.shapeCollisionMargin = g_params.collisionDistance*0.05f; + + g_numSubsteps = 2; + + // draw options + g_drawPoints = false; + g_drawEllipsoids = true; + g_drawDiffuse = true; + + g_lightDistance = 5.0f; + } + + // cloth + if (mScene == 3) + { + float stretchStiffness = 1.0f; + float bendStiffness = 0.8f; + float shearStiffness = 0.8f; + + int dimx = 32; + int dimz = 32; + float radius = 0.05f; + + int gridx = 8; + int gridz = 3; + + for (int x=0; x < gridx; ++x) + { + for (int y=0; y < 1; ++y) + { + for (int z=0; z < gridz; ++z) + { + CreateSpringGrid(center - Vec3(9.0f, 1.0f, 0.1f) + Vec3(x*dimx*radius, 0.0f, z*1.0f), dimx, dimz, 1, radius*0.95f, NvFlexMakePhase(0, eNvFlexPhaseSelfCollide | eNvFlexPhaseSelfCollideFilter), stretchStiffness, bendStiffness, shearStiffness, 0.0f, 1.0f); + } + } + } + + Vec3 l, u; + GetParticleBounds(l, u); + + Vec3 center = (u+l)*0.5f; + printf("%f %f %f\n", center.x, center.y, center.z); + + g_params.radius = radius*1.0f; + g_params.dynamicFriction = 0.4f; + g_params.staticFriction = 0.5f; + g_params.dissipation = 0.0f; + g_params.numIterations = 8; + g_params.drag = 0.06f; + g_params.sleepThreshold = g_params.radius*0.125f; + g_params.relaxationFactor = 2.0f; + g_params.collisionDistance = g_params.radius; + g_params.shapeCollisionMargin = g_params.collisionDistance*0.05f; + + g_windStrength = 0.0f; + + g_numSubsteps = 2; + + // draw options + g_drawPoints = false; + } + } + + virtual void PostInitialize() + { + // just focus on the particles, don't need to see the whole level + Vec3 lower, upper; + GetParticleBounds(lower, upper); + + g_sceneUpper = upper; + g_sceneLower = lower; + } + + virtual void CenterCamera(void) + { + g_camPos = Vec3((g_sceneLower.x+g_sceneUpper.x)*0.5f, min(g_sceneUpper.y*1.25f, 6.0f), g_sceneUpper.z + min(g_sceneUpper.y, 6.0f)*2.0f); + g_camAngle = Vec3(0.0f, -DegToRad(15.0f), 0.0f); + } + + int mScene; +}; diff --git a/demo/scenes/googun.h b/demo/scenes/googun.h new file mode 100644 index 0000000..79ff396 --- /dev/null +++ b/demo/scenes/googun.h @@ -0,0 +1,72 @@ + +class GooGun : public Scene +{ +public: + + GooGun(const char* name, bool viscous) : Scene(name), mViscous(viscous) {} + + virtual void Initialize() + { + float minSize = 0.5f; + float maxSize = 1.0f; + + float radius = 0.1f; + + for (int i = 0; i < 5; i++) + AddRandomConvex(10, Vec3(i*2.0f, 0.0f, Randf(0.0f, 2.0f)), minSize, maxSize, Vec3(0.0f, 1.0f, 0.0f), Randf(0.0f, k2Pi*10.0f)); + + g_params.radius = radius; + + g_params.fluid = true; + g_params.numIterations = 3; + g_params.vorticityConfinement = 0.0f; + g_params.fluidRestDistance = g_params.radius*0.55f; + g_params.anisotropyScale = 2.0f / radius; + g_params.smoothing = 0.5f; + g_params.relaxationFactor = 1.f; + g_params.restitution = 0.0f; + g_params.collisionDistance = 0.01f; + g_params.shapeCollisionMargin = g_params.collisionDistance*0.25f; + + if (mViscous) + { + g_fluidColor = Vec4(0.0f, 0.8f, 0.2f, 1.0f); + + g_params.dynamicFriction = 1.0f; + g_params.viscosity = 50.0f; + g_params.adhesion = 0.5f; + g_params.cohesion = 0.3f; + g_params.surfaceTension = 0.0f; + } + else + { + g_params.dynamicFriction = 0.25f; + g_params.viscosity = 0.5f; + g_params.cohesion = 0.05f; + g_params.adhesion = 0.0f; + } + + g_numExtraParticles = 64 * 1024; + +#if 1 + NvFlexDistanceFieldId sdf = CreateSDF(GetFilePathByPlatform("../../data/armadillo.ply").c_str(), 128); + AddSDF(sdf, Vec3(2.0f, 0.0f, -1.0f), Quat(), 2.0f); +#else + // Test multiple SDFs + NvFlexDistanceFieldId sdf = CreateSDF(GetFilePathByPlatform("../../data/armadillo.ply").c_str(), 128); + AddSDF(sdf, Vec3(2.0f, 0.0f, 0.0f), Quat(), 2.0f); + + NvFlexDistanceFieldId sdf2 = CreateSDF(GetFilePathByPlatform("../../data/bunny.ply").c_str(), 128); + AddSDF(sdf2, Vec3(4.0f, 0.0f, 0.0f), Quat(), 2.0f); +#endif + + g_emitters[0].mEnabled = true; + g_emitters[0].mSpeed = (g_params.fluidRestDistance*2.f / g_dt); + + // draw options + g_drawEllipsoids = true; + g_pause = false; + } + + bool mViscous; +}; diff --git a/demo/scenes/granularpile.h b/demo/scenes/granularpile.h new file mode 100644 index 0000000..56a85ea --- /dev/null +++ b/demo/scenes/granularpile.h @@ -0,0 +1,57 @@ + + +class GranularPile : public Scene +{ +public: + + GranularPile(const char* name) : Scene(name) {} + + virtual void Initialize() + { + // granular pile + float radius = 0.075f; + + Vec3 lower(8.0f, 4.0f, 2.0f); + + CreateParticleShape(GetFilePathByPlatform("../../data/sphere.ply").c_str(), lower, 1.0f, 0.0f, radius, 0.0f, 0.f, true, 1.0f, NvFlexMakePhase(1, 0), true, 0.00f); + g_numSolidParticles = g_buffers->positions.size(); + + CreateParticleShape(GetFilePathByPlatform("../../data/sandcastle.obj").c_str(), Vec3(-2.0f, -radius*0.15f, 0.0f), 4.0f, 0.0f, radius*1.0001f, 0.0f, 1.0f, false, 0.0f, NvFlexMakePhase(0, eNvFlexPhaseSelfCollide), false, 0.00f); + + g_numSubsteps = 2; + + g_params.radius = radius; + g_params.staticFriction = 1.0f; + g_params.dynamicFriction = 0.5f; + g_params.viscosity = 0.0f; + g_params.numIterations = 12; + g_params.particleCollisionMargin = g_params.radius*0.25f; // 5% collision margin + g_params.sleepThreshold = g_params.radius*0.25f; + g_params.shockPropagation = 6.f; + g_params.restitution = 0.2f; + g_params.relaxationFactor = 1.f; + g_params.damping = 0.14f; + g_params.numPlanes = 1; + + // draw options + g_drawPoints = true; + g_warmup = false; + + // hack, change the color of phase 0 particles to 'sand' + extern Colour gColors[]; + gColors[0] = Colour(0.805f, 0.702f, 0.401f); + } + + void Update() + { + // launch ball after 3 seconds + if (g_frame == 180) + { + for (int i=0; i < g_numSolidParticles; ++i) + { + g_buffers->positions[i].w = 0.9f; + g_buffers->velocities[i] = Vec3(-15.0f, 0.0f, 0.0f); + } + } + } +};
\ No newline at end of file diff --git a/demo/scenes/granularshape.h b/demo/scenes/granularshape.h new file mode 100644 index 0000000..6d21738 --- /dev/null +++ b/demo/scenes/granularshape.h @@ -0,0 +1,36 @@ + + + +class GranularShape : public Scene +{ +public: + + GranularShape(const char* name) : Scene(name) {} + + void Initialize() + { + // granular dragon + CreateParticleShape(GetFilePathByPlatform("../../data/dragon.obj").c_str(),Vec3(0.0f, 2.5f, 0.0f), 16.0f, DegToRad(-20.0f), g_params.radius*1.05f, Vec3(0.0f, 0.0f, 0.0f), 1.0f, false, 0.0f, NvFlexMakePhase(0, eNvFlexPhaseSelfCollide), false, g_params.radius*0.05f); + + AddBox(Vec3(8.0f, 8.0f, 5.0f)); + g_buffers->shapePositions[0] += Vec4(0.0f, -1.5f, 0.0f, 0.0f); + + g_params.staticFriction = 1.0f; + g_params.dynamicFriction = 0.65f; + g_params.dissipation = 0.01f; + g_params.numIterations = 6; + g_params.particleCollisionMargin = g_params.radius*0.5f; // 5% collision margin + g_params.sleepThreshold = g_params.radius*0.35f; + g_params.shockPropagation = 3.f; + g_params.restitution = 0.01f; + g_params.gravity[1] *= 1.f; + + g_numSubsteps = 3; + + extern Colour gColors[]; + gColors[1] = Colour(0.805f, 0.702f, 0.401f); + + // draw options + g_drawPoints = true; + } +}; diff --git a/demo/scenes/inflatable.h b/demo/scenes/inflatable.h new file mode 100644 index 0000000..58f5f08 --- /dev/null +++ b/demo/scenes/inflatable.h @@ -0,0 +1,159 @@ + + +class Inflatable : public Scene +{ +public: + + Inflatable(const char* name) : Scene(name) {} + + virtual ~Inflatable() + { + for (size_t i = 0; i < mCloths.size(); ++i) + delete mCloths[i]; + } + + void AddInflatable(const Mesh* mesh, float overPressure, int phase) + { + const int startVertex = g_buffers->positions.size(); + + // add mesh 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, 1.0f)); + g_buffers->velocities.push_back(0.0f); + g_buffers->phases.push_back(phase); + } + + int triOffset = g_buffers->triangles.size(); + int triCount = mesh->GetNumFaces(); + + g_buffers->inflatableTriOffsets.push_back(triOffset / 3); + g_buffers->inflatableTriCounts.push_back(mesh->GetNumFaces()); + g_buffers->inflatablePressures.push_back(overPressure); + + 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 + startVertex); + g_buffers->triangles.push_back(b + startVertex); + g_buffers->triangles.push_back(c + startVertex); + } + + // create a cloth mesh using the global positions / indices + ClothMesh* cloth = new ClothMesh(&g_buffers->positions[0], g_buffers->positions.size(), &g_buffers->triangles[triOffset], triCount * 3, 0.8f, 1.0f); + + for (size_t i = 0; i < cloth->mConstraintIndices.size(); ++i) + g_buffers->springIndices.push_back(cloth->mConstraintIndices[i]); + + for (size_t i = 0; i < cloth->mConstraintCoefficients.size(); ++i) + g_buffers->springStiffness.push_back(cloth->mConstraintCoefficients[i]); + + for (size_t i = 0; i < cloth->mConstraintRestLengths.size(); ++i) + g_buffers->springLengths.push_back(cloth->mConstraintRestLengths[i]); + + mCloths.push_back(cloth); + + // add inflatable params + g_buffers->inflatableVolumes.push_back(cloth->mRestVolume); + g_buffers->inflatableCoefficients.push_back(cloth->mConstraintScale); + } + + void Initialize() + { + mCloths.resize(0); + + float minSize = 0.75f; + float maxSize = 1.0f; + + // convex rocks + for (int i = 0; i < 5; i++) + AddRandomConvex(10, Vec3(i*2.0f, 0.0f, Randf(0.0f, 2.0f)), minSize, maxSize, Vec3(0.0f, 1.0f, 0.0f), Randf(0.0f, k2Pi)); + + float radius = 0.12f; + int group = 0; + + const char* meshes[2] = + { + "../../data/box_high_weld.ply", + "../../data/sphere.ply" + }; + + mPressure = 1.0f; + + for (int y = 0; y < 2; ++y) + { + for (int i = 0; i < 4; ++i) + { + Mesh* mesh = ImportMesh(GetFilePathByPlatform(meshes[(i + y) & 1]).c_str()); + mesh->Normalize(); + mesh->Transform(TranslationMatrix(Point3(i*2.0f, 1.0f + y*2.0f, 1.5f))); + + AddInflatable(mesh, mPressure, NvFlexMakePhase(group++, 0)); + + delete mesh; + } + } + + g_params.radius = radius; + g_params.dynamicFriction = 0.4f; + g_params.dissipation = 0.0f; + g_params.numIterations = 10; + g_params.particleCollisionMargin = g_params.radius*0.05f; + g_params.drag = 0.0f; + g_params.collisionDistance = 0.01f; + + // better convergence with global relaxation factor + g_params.relaxationMode = eNvFlexRelaxationGlobal; + g_params.relaxationFactor = 0.25f; + + g_windStrength = 0.0f; + + g_numSubsteps = 2; + + // draw options + g_drawPoints = false; + g_drawSprings = 0; + g_drawCloth = false; + } + + virtual void DoGui() + { + if (imguiSlider("Over Pressure", &mPressure, 0.25f, 3.0f, 0.001f)) + { + for (int i = 0; i < int(g_buffers->inflatablePressures.size()); ++i) + g_buffers->inflatablePressures[i] = mPressure; + } + } + + virtual void Sync() + { + NvFlexSetInflatables(g_flex, g_buffers->inflatableTriOffsets.buffer, g_buffers->inflatableTriCounts.buffer, g_buffers->inflatableVolumes.buffer, g_buffers->inflatablePressures.buffer, g_buffers->inflatableCoefficients.buffer, mCloths.size()); + } + + virtual void Draw(int pass) + { + if (!g_drawMesh) + return; + + int indexStart = 0; + + for (size_t i = 0; i < mCloths.size(); ++i) + { + DrawCloth(&g_buffers->positions[0], &g_buffers->normals[0], NULL, &g_buffers->triangles[indexStart], mCloths[i]->mTris.size(), g_buffers->positions.size(), i % 6, g_params.radius*0.35f); + + indexStart += mCloths[i]->mTris.size() * 3; + } + } + + float mPressure; + + std::vector<ClothMesh*> mCloths; +}; diff --git a/demo/scenes/initialoverlap.h b/demo/scenes/initialoverlap.h new file mode 100644 index 0000000..5c3abe4 --- /dev/null +++ b/demo/scenes/initialoverlap.h @@ -0,0 +1,30 @@ + + +// tests initial particle overlap, particle should be projected out of the box without high velocity +class InitialOverlap : public Scene +{ +public: + + InitialOverlap(const char* name) : Scene(name) {} + + virtual void Initialize() + { + g_params.radius = 0.1f; + g_params.numIterations = 2; + + // test max acceleration clamping is working, test at 5x gravity + g_params.maxAcceleration = 50.0f; + + // plinth + AddBox(1.0f, Vec3(0.0f, 0.0f, 0.0f)); + + g_buffers->positions.push_back(Vec4(0.0f, 0.5f, 0.0f, 1.0f)); + g_buffers->velocities.push_back(Vec3(0.0f)); + g_buffers->phases.push_back(0); + + g_numSubsteps = 2; + + // draw options + g_drawPoints = true; + } +}; diff --git a/demo/scenes/lighthouse.h b/demo/scenes/lighthouse.h new file mode 100644 index 0000000..e4b410a --- /dev/null +++ b/demo/scenes/lighthouse.h @@ -0,0 +1,59 @@ + + +class Lighthouse : public Scene +{ +public: + + Lighthouse(const char* name) : Scene(name) {} + + virtual void Initialize() + { + float radius = 0.15f; + float restDistance = radius*0.6f; + + NvFlexDistanceFieldId sdf = CreateSDF(GetFilePathByPlatform("../../data/lighthouse.ply").c_str(), 128); + AddSDF(sdf, Vec3(4.0f, 0.0f, 0.0f), Quat(), 10.f); + + CreateParticleGrid(Vec3(0.0f, 0.3f, 0.0f), 48, 48, 128, restDistance, Vec3(0.0f), 1.0f, false, 0.0f, NvFlexMakePhase(0, eNvFlexPhaseSelfCollide | eNvFlexPhaseFluid), 0.005f); + + g_sceneLower = 0.0f; + g_sceneUpper = Vec3(12, 0.0f, 0.0f); + + g_numSubsteps = 2; + + g_params.radius = radius; + g_params.dynamicFriction = 0.f; + g_params.fluid = true; + g_params.viscosity = 0.01f; + g_params.numIterations = 3; + g_params.vorticityConfinement = 50.0f; + g_params.anisotropyScale = 20.0f; + g_params.fluidRestDistance = restDistance; + g_params.gravity[1] *= 0.5f; + g_params.cohesion *= 0.5f; + + g_fluidColor = Vec4(0.413f, 0.725f, 0.85f, 0.7f); + + g_maxDiffuseParticles = 1024 * 1024; + g_diffuseScale = 0.3f; + g_diffuseShadow = true; + g_diffuseColor = 1.0f; + g_diffuseMotionScale = 1.0f; + g_params.diffuseThreshold *= 10.f; + g_params.diffuseBallistic = 4; + g_params.diffuseBuoyancy = 2.0f; + g_params.diffuseDrag = 1.0f; + + g_params.numPlanes = 5; + + g_waveFrequency = 1.2f; + g_waveAmplitude = 2.2f; + g_waveFloorTilt = 0.1f; + + + // draw options + g_drawPoints = false; + g_drawEllipsoids = true; + g_drawDiffuse = true; + } +};
\ No newline at end of file diff --git a/demo/scenes/localspacecloth.h b/demo/scenes/localspacecloth.h new file mode 100644 index 0000000..f28912e --- /dev/null +++ b/demo/scenes/localspacecloth.h @@ -0,0 +1,134 @@ + + + +class LocalSpaceCloth : public Scene +{ +public: + + LocalSpaceCloth (const char* name) : Scene(name) {} + + void Initialize() + { + float stretchStiffness = 1.0f; + float bendStiffness = 1.0f; + float shearStiffness = 1.0f; + + float radius = 0.1f; + + CreateSpringGrid(Vec3(0.5f, 1.45f, -0.5f), 32, 20, 1, radius*0.5f, NvFlexMakePhase(0, eNvFlexPhaseSelfCollide | eNvFlexPhaseSelfCollideFilter), stretchStiffness, bendStiffness, shearStiffness, Vec3(0.0f), 1.0f); + + int c1 = 1; + int c2 = 20; + + // add tethers + for (int i=0; i < int(g_buffers->positions.size()); ++i) + { + float minSqrDist = FLT_MAX; + + if (i != c1 && i != c2) + { + float stiffness = -0.8f; + float give = 0.01f; + + float sqrDist = LengthSq(Vec3(g_buffers->positions[c1])-Vec3(g_buffers->positions[c2])); + + if (sqrDist < minSqrDist) + { + CreateSpring(c1, i, stiffness, give); + CreateSpring(c2, i, stiffness, give); + + minSqrDist = sqrDist; + } + } + } + + + + for (int i=0; i < g_buffers->positions.size(); ++i) + { + if (g_buffers->positions[i].x == 0.5f) + g_buffers->positions[i].w = 0.0f; + } + + translation = Vec3(0.0f, 1.0f, 0.0f); + size = Vec3(0.5f, 1.1f, 0.6f); + rotation = 0.0f; + rotationSpeed = 0.0f; + + linearInertialScale = 0.25f; + angularInertialScale = 0.25f; + + AddBox(size, translation); + + // initialize our moving frame to the center of the box + NvFlexExtMovingFrameInit(&meshFrame, translation, Quat()); + + g_numSubsteps = 2; + + g_params.fluid = false; + g_params.radius = radius; + g_params.dynamicFriction = 0.f; + g_params.restitution = 0.0f; + g_params.shapeCollisionMargin = 0.05f; + + g_params.numIterations = 6; + + // draw options + g_drawPoints = false; + } + + virtual void DoGui() + { + imguiSlider("Rotation", &rotationSpeed, 0.0f, 20.0f, 0.1f); + imguiSlider("Translation", &translation.x, -2.0f, 2.0f, 0.001f); + + imguiSlider("Linear Inertia", &linearInertialScale, 0.0f, 1.0f, 0.001f); + imguiSlider("Angular Inertia", &angularInertialScale, 0.0f, 1.0f, 0.001f); + + } + + virtual void Update() + { + rotation += rotationSpeed*g_dt; + + // new position of the box center + Vec3 newPosition = translation;//meshFrame.GetPosition() + Vec3(float(g_lastdx), 0.0f, float(g_lastdy))*0.001f; + Quat newRotation = QuatFromAxisAngle(Vec3(0.0f, 1.0f, 0.0f), rotation); + + NvFlexExtMovingFrameUpdate(&meshFrame, newPosition, newRotation, g_dt); + + // update all the particles in the sim with inertial forces + NvFlexExtMovingFrameApply( + &meshFrame, + &g_buffers->positions[0].x, + &g_buffers->velocities[0].x, + g_buffers->positions.size(), + linearInertialScale, + angularInertialScale, + g_dt); + + // update collision shapes + g_buffers->shapePositions.resize(0); + g_buffers->shapeRotations.resize(0); + g_buffers->shapePrevPositions.resize(0); + g_buffers->shapePrevRotations.resize(0); + g_buffers->shapeGeometry.resize(0); + g_buffers->shapeFlags.resize(0); + + AddBox(size, newPosition, newRotation); + + UpdateShapes(); + } + + Vec3 size; + Vec3 translation; + float rotation; + float rotationSpeed; + + float linearInertialScale; + float angularInertialScale; + + NvFlexExtMovingFrame meshFrame; + + NvFlexTriangleMeshId mesh; +}; diff --git a/demo/scenes/localspacefluid.h b/demo/scenes/localspacefluid.h new file mode 100644 index 0000000..494249a --- /dev/null +++ b/demo/scenes/localspacefluid.h @@ -0,0 +1,127 @@ + + +class LocalSpaceFluid : public Scene +{ +public: + + LocalSpaceFluid (const char* name) : Scene(name) {} + + void Initialize() + { + const float radius = 0.05f; + const float restDistance = radius*0.6f; + + int dx = int(ceilf(1.f / restDistance)); + int dy = int(ceilf(1.f / restDistance)); + int dz = int(ceilf(1.f / restDistance)); + + CreateParticleGrid(Vec3(0.0f, 1.0f, 0.0f), dx, dy, dz, restDistance, Vec3(0.0f), 1.0f, false, 0.0f, NvFlexMakePhase(0, eNvFlexPhaseSelfCollide | eNvFlexPhaseFluid), restDistance*0.01f); + + Vec3 lower, upper; + GetParticleBounds(lower, upper); + + Vec3 center = (lower+upper)*0.5f; + + Mesh* shape = ImportMesh("../../data/torus.obj"); + shape->Transform(ScaleMatrix(Vec3(0.7f))); + + //Mesh* box = ImportMesh("../../data/sphere.ply"); + //box->Transform(TranslationMatrix(Point3(0.0f, 0.1f, 0.0f))*ScaleMatrix(Vec3(1.5f))); + + // invert box faces + for (int i=0; i < int(shape->GetNumFaces()); ++i) + swap(shape->m_indices[i*3+0], shape->m_indices[i*3+1]); + + shape->CalculateNormals(); + + // shift into torus interior + for (int i=0; i < g_buffers->positions.size(); ++i) + (Vec3&)(g_buffers->positions[i]) -= Vec3(2.1f, 0.0f, 0.0f); + + mesh = CreateTriangleMesh(shape); + AddTriangleMesh(mesh, Vec3(center), Quat(), 1.0f); + + // initialize our moving frame to the center of the box + NvFlexExtMovingFrameInit(&meshFrame, center, Quat()); + + g_numSubsteps = 2; + + g_params.fluid = true; + g_params.radius = radius; + g_params.fluidRestDistance = restDistance; + g_params.dynamicFriction = 0.f; + g_params.restitution = 0.0f; + g_params.collisionDistance = 0.05f; + g_params.shapeCollisionMargin = 0.00001f; + g_params.maxSpeed = g_numSubsteps*restDistance/g_dt; + + g_params.numIterations = 4; + + g_params.smoothing = 0.4f; + g_params.anisotropyScale = 3.0f / radius; + g_params.viscosity = 0.001f; + g_params.cohesion = 0.05f; + g_params.surfaceTension = 0.0f; + + translation = center; + rotation = 0.0f; + rotationSpeed = 0.0f; + + linearInertialScale = 0.25f; + angularInertialScale = 0.75f; + + // draw options + g_drawPoints = false; + g_drawEllipsoids = true; + g_drawDiffuse = true; + } + + virtual void DoGui() + { + imguiSlider("Rotation", &rotationSpeed, 0.0f, 7.0f, 0.1f); + imguiSlider("Translation", &translation.x, -2.0f, 2.0f, 0.001f); + imguiSlider("Linear Inertia", &linearInertialScale, 0.0f, 1.0f, 0.001f); + imguiSlider("Angular Inertia", &angularInertialScale, 0.0f, 1.0f, 0.001f); + } + + virtual void Update() + { + rotation += rotationSpeed*g_dt; + + // new position of the box center + Vec3 newPosition = translation;//meshFrame.GetPosition() + Vec3(float(g_lastdx), 0.0f, float(g_lastdy))*0.001f; + Quat newRotation = QuatFromAxisAngle(Vec3(0.0f, 1.0f, 0.0f), rotation); + + NvFlexExtMovingFrameUpdate(&meshFrame, newPosition, newRotation, g_dt); + + // update all the particles in the sim with inertial forces + NvFlexExtMovingFrameApply( + &meshFrame, + &g_buffers->positions[0].x, + &g_buffers->velocities[0].x, + g_buffers->positions.size(), + linearInertialScale, + angularInertialScale, + g_dt); + + // update torus transform + g_buffers->shapePrevPositions[0] = g_buffers->shapePositions[0]; + g_buffers->shapePrevRotations[0] = g_buffers->shapeRotations[0]; + + g_buffers->shapePositions[0] = Vec4(newPosition, 1.0f); + g_buffers->shapeRotations[0] = newRotation; + + UpdateShapes(); + } + + Vec3 translation; + float rotation; + float rotationSpeed; + + float linearInertialScale; + float angularInertialScale; + + NvFlexExtMovingFrame meshFrame; + + NvFlexTriangleMeshId mesh; +};
\ No newline at end of file diff --git a/demo/scenes/lowdimensionalshapes.h b/demo/scenes/lowdimensionalshapes.h new file mode 100644 index 0000000..5d32ea5 --- /dev/null +++ b/demo/scenes/lowdimensionalshapes.h @@ -0,0 +1,54 @@ + +class LowDimensionalShapes: public Scene +{ +public: + + LowDimensionalShapes(const char* name) : Scene(name) {} + + virtual void Initialize() + { + float radius = 0.1f; + int group = 0; + + Mesh* mesh = ImportMesh(GetFilePathByPlatform("../../data/box.ply").c_str()); + + CreateParticleShape(mesh, Vec3(0.0f, 1.0f, 0.0f), Vec3(1.2f, 0.001f, 1.2f), 0.0f, radius, Vec3(0.0f, 0.0f, 0.0f), 1.0f, true, 1.0f, NvFlexMakePhase(group++, 0), true, 0.0f); + + for (int i=0; i < 64; ++i) + CreateParticleShape(mesh, Vec3(i / 8 * radius, 0.0f, i % 8 * radius), Vec3(0.1f, 0.8f, 0.1f), 0.0f, radius, Vec3(0.0f, 0.0f, 0.0f), 1.0f, true, 1.0f, NvFlexMakePhase(group++, 0), true, 0.0f); + + delete mesh; + + g_params.radius = radius; + g_params.dynamicFriction = 1.0f; + g_params.fluid = false; + g_params.fluidRestDistance = radius; + g_params.viscosity = 0.0f; + g_params.numIterations = 4; + g_params.vorticityConfinement = 0.f; + g_params.anisotropyScale = 20.0f; + g_params.numPlanes = 1; + g_params.collisionDistance = radius*0.5f; + g_params.shockPropagation = 5.0f; + + g_numSubsteps = 2; + + g_maxDiffuseParticles = 0; + g_diffuseScale = 0.75f; + + g_lightDistance *= 1.5f; + + g_fluidColor = Vec4(0.2f, 0.6f, 0.9f, 1.0f); + + // draw options + g_drawDensity = false; + g_drawDiffuse = false; + g_drawEllipsoids = false; + g_drawPoints = true; + g_drawMesh = false; + + g_warmup = false; + + } + +}; diff --git a/demo/scenes/melting.h b/demo/scenes/melting.h new file mode 100644 index 0000000..c7da792 --- /dev/null +++ b/demo/scenes/melting.h @@ -0,0 +1,70 @@ + +class Melting : public Scene +{ +public: + + Melting(const char* name) : Scene(name) {} + + virtual void Initialize() + { + g_params.radius = 0.1f; + + g_params.numIterations = 2; + g_params.dynamicFriction = 0.25f; + g_params.dissipation = 0.0f; + g_params.viscosity = 0.0f; + g_params.fluid = true; + g_params.cohesion = 0.0f; + g_params.fluidRestDistance = g_params.radius*0.6f; + g_params.anisotropyScale = 4.0f / g_params.radius; + g_params.smoothing = 0.5f; + + const float spacing = g_params.radius*0.5f; + + Mesh* mesh = ImportMesh(GetFilePathByPlatform("../../data/bunny.ply").c_str()); + + int phase = NvFlexMakePhase(0, eNvFlexPhaseSelfCollide | eNvFlexPhaseFluid); + float size = 1.2f; + + for (int i = 0; i < 1; ++i) + for (int j = 0; j < 3; ++j) + CreateParticleShape(mesh, Vec3(-2.0f + j*size, 3.0f + j*size, i*size), size, 0.0f, spacing, Vec3(0.0f, 0.0f, 0.0f), 1.0f, true, 1.f, phase, false, 0.0f); + + delete mesh; + + // plinth + AddBox(2.0f, Vec3(0.0f, 1.0f, 0.0f)); + + g_numSubsteps = 2; + + // draw options + g_drawPoints = true; + g_drawMesh = false; + + mFrame = 0; + } + + virtual void Update() + { + const int start = 130; + + if (mFrame >= start) + { + float stiffness = max(0.0f, 1.0f - (mFrame - start) / 100.0f); + + for (int i = 0; i < g_buffers->rigidCoefficients.size(); ++i) + g_buffers->rigidCoefficients[i] = stiffness; + + g_params.cohesion = Lerp(0.05f, 0.0f, stiffness); + } + + ++mFrame; + } + + virtual void Sync() + { + NvFlexSetRigids(g_flex, g_buffers->rigidOffsets.buffer, g_buffers->rigidIndices.buffer, g_buffers->rigidLocalPositions.buffer, g_buffers->rigidLocalNormals.buffer, g_buffers->rigidCoefficients.buffer, g_buffers->rigidRotations.buffer, g_buffers->rigidTranslations.buffer, g_buffers->rigidOffsets.size() - 1, g_buffers->rigidIndices.size()); + } + + int mFrame; +};
\ No newline at end of file diff --git a/demo/scenes/mixedpile.h b/demo/scenes/mixedpile.h new file mode 100644 index 0000000..61bc5a5 --- /dev/null +++ b/demo/scenes/mixedpile.h @@ -0,0 +1,221 @@ + +/* +class MixedPile : public Scene +{ +public: + + MixedPile(const char* name) : Scene(name) + { + } + + + std::vector<ClothMesh*> mCloths; + std::vector<float> mRestVolume; + std::vector<int> mTriOffset; + std::vector<int> mTriCount; + std::vector<float> mOverPressure; + std::vector<float> mConstraintScale; + std::vector<float> mSplitThreshold; + + void AddInflatable(const Mesh* mesh, float overPressure, int phase, float invmass=1.0f) + { + const int startVertex = g_buffers->positions.size(); + + // add mesh 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->velocities.push_back(0.0f); + g_buffers->phases.push_back(phase); + } + + int triOffset = g_buffers->triangles.size(); + int triCount = mesh->GetNumFaces(); + + mTriOffset.push_back(triOffset/3); + mTriCount.push_back(mesh->GetNumFaces()); + mOverPressure.push_back(overPressure); + + 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 + startVertex); + g_buffers->triangles.push_back(b + startVertex); + g_buffers->triangles.push_back(c + startVertex); + } + + // create a cloth mesh using the global positions / indices + ClothMesh* cloth = new ClothMesh(&g_buffers->positions[0], g_buffers->positions.size(), &g_buffers->triangles[triOffset],triCount*3, 0.8f, 1.0f); + + for (size_t i=0; i < cloth->mConstraintIndices.size(); ++i) + g_buffers->springIndices.push_back(cloth->mConstraintIndices[i]); + + for (size_t i=0; i < cloth->mConstraintCoefficients.size(); ++i) + g_buffers->springStiffness.push_back(cloth->mConstraintCoefficients[i]); + + for (size_t i=0; i < cloth->mConstraintRestLengths.size(); ++i) + g_buffers->springLengths.push_back(cloth->mConstraintRestLengths[i]); + + mCloths.push_back(cloth); + + // add inflatable params + mRestVolume.push_back(cloth->mRestVolume); + mConstraintScale.push_back(cloth->mConstraintScale); + } + + + virtual void Initialize() + { + + Vec3 start(0.0f, 0.5f + g_params.radius*0.25f, 0.0f); + + float radius = g_params.radius; + + int group = 1; + + if (1) + { + mCloths.resize(0); + mRestVolume.resize(0); + mTriOffset.resize(0); + mTriCount.resize(0); + mOverPressure.resize(0); + mConstraintScale.resize(0); + mSplitThreshold.resize(0); + + Vec3 lower(0.0f), upper(0.0f); + float size = 1.0f + radius; + + for (int i=0; i < 9; ++i) + { + Mesh* mesh = ImportMesh(GetFilePathByPlatform("../../data/sphere.ply").c_str()); + mesh->Normalize(); + mesh->Transform(TranslationMatrix(Point3(lower.x + i%3*size, upper.y + 2.0f, (upper.z+lower.z)*0.5f + i/3*size))); + + AddInflatable(mesh, 1.0f, NvFlexMakePhase(group++, 0), 2.0f); + delete mesh; + } + } + + + if (1) + { + const int minSize[3] = { 2, 1, 3 }; + const int maxSize[3] = { 4, 3, 6 }; + + Vec4 color = Vec4(SrgbToLinear(Colour(Vec4(201.0f, 158.0f, 106.0f, 255.0f)/255.0f))); + + Vec3 lower(0.0f), upper(5.0f); + GetParticleBounds(lower,upper); + + int dimx = 3; + int dimy = 10; + int dimz = 3; + + for (int y=0; y < dimy; ++y) + { + for (int z=0; z < dimz; ++z) + { + for (int x=0; x < dimx; ++x) + { + CreateParticleShape( + GetFilePathByPlatform("../../data/box.ply").c_str(), + Vec3(x + 0.5f,0,z+ 0.5f)*(1.0f+radius) + Vec3(0.0f, upper.y + (y+2.0f)*maxSize[1]*g_params.radius, 0.0f), + Vec3(float(Rand(minSize[0], maxSize[0])), + float(Rand(minSize[1], maxSize[1])), + float(Rand(minSize[2], maxSize[2])))*g_params.radius*0.9f, 0.0f, g_params.radius*0.9f, Vec3(0.0f), 1.0f, true, 1.0f, NvFlexMakePhase(group++, 0), true,0.0f,0.0f, 0.0f, color); + } + } + } + } + + + if (1) + { + Vec3 lower, upper; + GetParticleBounds(lower,upper); + Vec3 center = (upper+lower)*0.5f; + center.y = upper.y; + + for (int i=0; i < 20; ++i) + { + Rope r; + Vec3 offset = Vec3(sinf(k2Pi*float(i)/20), 0.0f, cosf(k2Pi*float(i)/20)); + + CreateRope(r, center + offset, Normalize(offset + Vec3(0.0f, 4.0f, 0.0f)), 1.2f, 50, 50*radius, NvFlexMakePhase(group++, eNvFlexPhaseSelfCollide), 0.0f, 10.0f, 0.0f); + g_ropes.push_back(r); + } + } + + Vec3 lower, upper; + GetParticleBounds(lower, upper); + + Vec3 center = (lower+upper)*0.5f; + center.y = 0.0f; + + float width = (upper-lower).x; + float edge = 0.25f; + float height = 1.0f; + AddBox(Vec3(edge, height, width), center + Vec3(-width, height/2.0f, 0.0f)); + AddBox(Vec3(edge, height, width), center + Vec3(width, height/2.0f, 0.0f)); + + AddBox(Vec3(width-edge, height, edge), center + Vec3(0.0f, height/2.0f, width-edge)); + AddBox(Vec3(width-edge, height, edge), center + Vec3(0.0f, height/2.0f, -(width-edge))); + + //g_numExtraParticles = 32*1024; + g_numSubsteps = 2; + g_params.numIterations = 7; + + g_params.radius *= 1.0f; + g_params.solidRestDistance = g_params.radius; + g_params.fluidRestDistance = g_params.radius*0.55f; + g_params.dynamicFriction = 0.6f; + g_params.staticFriction = 0.75f; + g_params.particleFriction = 0.3f; + g_params.dissipation = 0.0f; + g_params.particleCollisionMargin = g_params.radius*0.05f; + g_params.sleepThreshold = g_params.radius*0.125f; + g_params.shockPropagation = 0.0f; + g_params.restitution = 0.0f; + g_params.collisionDistance = g_params.radius*0.5f; + g_params.fluid = false; + g_params.maxSpeed = 2.0f*g_params.radius*g_numSubsteps/g_dt; + + // separte solid particle count + g_numSolidParticles = g_buffers->positions.size(); + // number of fluid particles to allocate + g_numExtraParticles = 32*1024; + + g_params.numPlanes = 1; + g_windStrength = 0.0f; + + g_lightDistance *= 0.5f; + + // draw options + g_drawPoints = true; + g_expandCloth = g_params.radius*0.5f; + + g_emitters[0].mEnabled = true; + g_emitters[0].mSpeed = (g_params.radius*0.5f/g_dt); + g_emitters[0].mSpeed = (g_params.radius/g_dt); + + extern Colour gColors[]; + gColors[0] = Colour(0.805f, 0.702f, 0.401f); + } + + virtual void Update() + { + NvFlexSetInflatables(g_flex, &mTriOffset[0], &mTriCount[0], &mRestVolume[0], &mOverPressure[0], &mConstraintScale[0], mCloths.size(), eFlexMemoryHost); + } + + int mHeight; +}; +*/ diff --git a/demo/scenes/nonconvex.h b/demo/scenes/nonconvex.h new file mode 100644 index 0000000..37a5a6d --- /dev/null +++ b/demo/scenes/nonconvex.h @@ -0,0 +1,47 @@ + + +class NonConvex : public Scene +{ +public: + + NonConvex(const char* name) : Scene(name) + { + } + + virtual void Initialize() + { + float radius = 0.15f; + int group = 0; + + for (int i = 0; i < 1; ++i) + CreateParticleShape(GetFilePathByPlatform("../../data/bowl.obj").c_str(), Vec3(0.0f, 1.0f + 0.5f*i + radius*0.5f, 0.0f), Vec3(1.5f), 0.0f, radius*0.8f, Vec3(0.0f), 1.0f, true, 1.0f, NvFlexMakePhase(group++, 0), true, 0.0f, Vec3(0.0f)); + + for (int i = 0; i < 50; ++i) + CreateParticleShape(GetFilePathByPlatform("../../data/banana.obj").c_str(), Vec3(0.4f, 2.5f + i*0.25f, 0.25f) + RandomUnitVector()*radius*0.25f, Vec3(1), 0.0f, radius, Vec3(0.0f), 1.0f, true, 0.5f, NvFlexMakePhase(group++, 0), true, radius*0.1f, 0.0f, 0.0f, 1.25f*Vec4(0.875f, 0.782f, 0.051f, 1.0f)); + + AddBox(); + + g_numSubsteps = 3; + g_params.numIterations = 3; + + g_params.radius *= 1.0f; + g_params.dynamicFriction = 0.35f; + g_params.dissipation = 0.0f; + g_params.particleCollisionMargin = g_params.radius*0.05f; + g_params.sleepThreshold = g_params.radius*0.2f; + g_params.shockPropagation = 3.0f; + g_params.gravity[1] *= 1.0f; + g_params.restitution = 0.01f; + g_params.damping = 0.25f; + + // draw options + g_drawPoints = false; + + g_emitters[0].mEnabled = true; + g_emitters[0].mSpeed = (g_params.radius*2.0f / g_dt); + } + + virtual void Update() + { + } +};
\ No newline at end of file diff --git a/demo/scenes/parachutingbunnies.h b/demo/scenes/parachutingbunnies.h new file mode 100644 index 0000000..04f2052 --- /dev/null +++ b/demo/scenes/parachutingbunnies.h @@ -0,0 +1,167 @@ + +class ParachutingBunnies : public Scene +{ +public: + + ParachutingBunnies(const char* name) : Scene(name) {} + + void Initialize() + { + float stretchStiffness = 1.0f; + float bendStiffness = 0.8f; + float shearStiffness = 0.8f; + + int dimx = 32; + int dimy = 32; + float radius = 0.055f; + + float height = 10.0f; + float spacing = 1.5f; + int numBunnies = 2; + int group = 0; + + for (int i=0; i < numBunnies; ++i) + { + CreateSpringGrid(Vec3(i*dimx*radius, height + i*spacing, 0.0f), dimx, dimy, 1, radius, NvFlexMakePhase(group++, eNvFlexPhaseSelfCollide), stretchStiffness, bendStiffness, shearStiffness, Vec3(0.0f), 1.1f); + + const int startIndex = i*dimx*dimy; + + int corner0 = startIndex + 0; + int corner1 = startIndex + dimx-1; + int corner2 = startIndex + dimx*(dimy-1); + int corner3 = startIndex + dimx*dimy-1; + + CreateSpring(corner0, corner1, 1.f,-0.1f); + CreateSpring(corner1, corner3, 1.f,-0.1f); + CreateSpring(corner3, corner2, 1.f,-0.1f); + CreateSpring(corner0, corner2, 1.f,-0.1f); + } + + for (int i=0; i < numBunnies; ++i) + { + Vec3 velocity = RandomUnitVector()*1.0f; + float size = radius*8.5f; + + CreateParticleShape(GetFilePathByPlatform("../../data/bunny.ply").c_str(), Vec3(i*dimx*radius + radius*0.5f*dimx - 0.5f*size, height + i*spacing-0.5f, radius*0.5f*dimy - 0.5f), size, 0.0f, radius, velocity, 0.15f, true, 1.0f, NvFlexMakePhase(group++, 0), true, 0.0f); + + const int startIndex = i*dimx*dimy; + const int attachIndex = g_buffers->positions.size()-1; + g_buffers->positions[attachIndex].w = 2.0f; + + int corner0 = startIndex + 0; + int corner1 = startIndex + dimx-1; + int corner2 = startIndex + dimx*(dimy-1); + int corner3 = startIndex + dimx*dimy-1; + + Vec3 attachPosition = (Vec3(g_buffers->positions[corner0]) + Vec3(g_buffers->positions[corner1]) + Vec3(g_buffers->positions[corner2]) + Vec3(g_buffers->positions[corner3]))*0.25f; + attachPosition.y = height + i*spacing-0.5f; + + if (1) + { + int c[4] = {corner0, corner1, corner2, corner3}; + + for (int i=0; i < 4; ++i) + { + Rope r; + + int start = g_buffers->positions.size(); + + r.mIndices.push_back(attachIndex); + + Vec3 d0 = Vec3(g_buffers->positions[c[i]])-attachPosition; + CreateRope(r, attachPosition, Normalize(d0), 1.2f, int(Length(d0)/radius*1.1f), Length(d0), NvFlexMakePhase(group++, 0), 0.0f, 0.5f, 0.0f); + + r.mIndices.push_back(c[i]); + g_ropes.push_back(r); + + int end = g_buffers->positions.size()-1; + + + CreateSpring(attachIndex, start, 1.2f, -0.5f); + CreateSpring(c[i], end, 1.0f); + } + } + } + + if (1) + { + // falling objects + Vec3 lower, upper; + GetParticleBounds(lower, upper); + + Vec3 center = (lower+upper)*0.5f; + center.y = 0.0f; + + float width = (upper-lower).x*0.5f; + float edge = 0.125f; + float height = 0.5f; + + // big blocks + for (int i=0; i < 3; ++i) + CreateParticleShape(GetFilePathByPlatform("../../data/box.ply").c_str(), center + Vec3(float(i)-1.0f, 5.0f, 0.0f), radius*9, 0.0f, radius*0.9f, Vec3(0.0f), 0.5f, true, 1.0f, NvFlexMakePhase(group++, 0), true, 0.0f, 0.0f, -radius*1.5f); + + // small blocks + for (int j=0; j < 2; ++j) + for (int i=0; i < 8; ++i) + CreateParticleShape(GetFilePathByPlatform("../../data/box.ply").c_str(), Vec3(lower.x + 0.5f, 0.0f, lower.z - 0.5f) + Vec3(float(i/3), 6.0f + float(j), float(i%3)) + RandomUnitVector()*0.5f, radius*4, 0.0f, radius*0.9f, Vec3(0.0f), 1.f, true, 1.0f, NvFlexMakePhase(group++, 0), true, 0.0f, 0.0f, -radius*2.0f); + + g_numSolidParticles = g_buffers->positions.size(); + + { + AddBox(Vec3(edge, height, width+edge*2.0f), center + Vec3(-width - edge, height/2.0f, 0.0f)); + AddBox(Vec3(edge, height, width+edge*2.0f), center + Vec3(width + edge, height/2.0f, 0.0f)); + + AddBox(Vec3(width+2.0f*edge, height, edge), center + Vec3(0.0f, height/2.0f, -(width+edge))); + AddBox(Vec3(width+2.0f*edge, height, edge), center + Vec3(0.0f, height/2.0f, width+edge)); + + float fluidWidth = width; + float fluidHeight = height*1.25f; + + int particleWidth = int(2.0f*fluidWidth/radius); + int particleHeight = int(fluidHeight/radius); + + CreateParticleGrid(center - Vec3(fluidWidth, 0.0f, fluidWidth), particleWidth, particleHeight, particleWidth, radius, Vec3(0.0f), 2.0f, false, 0.0f, NvFlexMakePhase(group++, eNvFlexPhaseSelfCollide | eNvFlexPhaseFluid)); + } + } + + g_params.fluid = true; + g_params.radius = 0.1f; + g_params.fluidRestDistance = radius; + g_params.numIterations = 4; + g_params.viscosity = 1.0f; + g_params.dynamicFriction = 0.05f; + g_params.staticFriction = 0.0f; + g_params.particleCollisionMargin = 0.0f; + g_params.collisionDistance = g_params.fluidRestDistance*0.5f; + g_params.vorticityConfinement = 120.0f; + g_params.cohesion = 0.0025f; + g_params.drag = 0.06f; + g_params.lift = 0.f; + g_params.solidPressure = 0.0f; + g_params.anisotropyScale = 22.0f; + g_params.smoothing = 1.0f; + g_params.relaxationFactor = 1.0f; + + g_maxDiffuseParticles = 64*1024; + g_diffuseScale = 0.25f; + g_diffuseShadow = false; + g_diffuseColor = 2.5f; + g_diffuseMotionScale = 1.5f; + g_params.diffuseThreshold *= 0.01f; + g_params.diffuseBallistic = 35; + + g_windStrength = 0.0f; + g_windFrequency = 0.0f; + + g_numSubsteps = 2; + + // draw options + g_drawEllipsoids = true; + g_drawPoints = false; + g_drawDiffuse = true; + g_drawSprings = 0; + + g_ropeScale = 0.2f; + g_warmup = false; + } +}; diff --git a/demo/scenes/pasta.h b/demo/scenes/pasta.h new file mode 100644 index 0000000..3852029 --- /dev/null +++ b/demo/scenes/pasta.h @@ -0,0 +1,47 @@ + +class Pasta : public Scene +{ +public: + + Pasta(const char* name) : Scene(name) {} + + virtual void Initialize() + { + float radius = 0.1f; + float length = 15.0f; + int n = 20; + + for (int i = 0; i < n; ++i) + { + float theta = k2Pi*float(i) / n; + + Rope r; + CreateRope(r, 0.5f*Vec3(cosf(theta), 2.0f, sinf(theta)), Vec3(0.0f, 1.0f, 0.0f), 0.25f, int(length / radius), length, NvFlexMakePhase(0, eNvFlexPhaseSelfCollide)); + g_ropes.push_back(r); + } + + g_numSubsteps = 3; + + Mesh* bowl = ImportMesh(GetFilePathByPlatform("../../data/bowl.obj").c_str()); + bowl->Normalize(2.0f); + bowl->CalculateNormals(); + bowl->Transform(TranslationMatrix(Point3(-1.0f, 0.0f, -1.0f))); + + NvFlexTriangleMeshId mesh = CreateTriangleMesh(bowl); + AddTriangleMesh(mesh, Vec3(), Quat(), 1.0f); + + delete bowl; + + g_params.numIterations = 6; + g_params.radius = radius; + g_params.dynamicFriction = 0.4f; + g_params.dissipation = 0.001f; + g_params.sleepThreshold = g_params.radius*0.2f; + g_params.relaxationFactor = 1.3f; + g_params.restitution = 0.0f; + g_params.shapeCollisionMargin = 0.01f; + + g_lightDistance *= 0.5f; + g_drawPoints = false; + } +};
\ No newline at end of file diff --git a/demo/scenes/plasticbody.h b/demo/scenes/plasticbody.h new file mode 100644 index 0000000..d5337d2 --- /dev/null +++ b/demo/scenes/plasticbody.h @@ -0,0 +1,271 @@ + + +class PlasticBody : public Scene +{ +public: + + PlasticBody(const char* name, const char* mesh) : + Scene(name), + mFile(mesh), + mScale(2.0f), + mOffset(0.0f, 1.0f, 0.0f), + mRadius(0.1f), + mClusterSpacing(1.0f), + mClusterRadius(0.0f), + mClusterStiffness(0.5f), + mLinkRadius(0.0f), + mLinkStiffness(1.0f), + mGlobalStiffness(1.0f), + mSurfaceSampling(0.0f), + mVolumeSampling(4.0f), + mSkinningFalloff(2.0f), + mSkinningMaxDistance(100.0f) + { + mStack[0] = 1; + mStack[1] = 1; + mStack[2] = 1; + } + + virtual void Initialize() + { + float radius = mRadius; + + g_params.radius = radius; + g_params.dynamicFriction = 0.35f; + g_params.particleFriction = 0.25f; + g_params.dissipation = 0.0f; + g_params.numIterations = 4; + g_params.viscosity = 0.0f; + g_params.drag = 0.0f; + g_params.lift = 0.0f; + g_params.collisionDistance = radius*0.75f; + + g_params.plasticThreshold = 0.0015f; + g_params.plasticCreep = 0.125f; + + g_params.relaxationFactor = 0.6f; + + g_windStrength = 0.0f; + + g_numSubsteps = 2; + + // draw options + g_drawPoints = false; + g_wireframe = false; + g_drawSprings = false; + g_drawBases = false; + + g_buffers->rigidOffsets.push_back(0); + + mInstances.resize(0); + + + CreateBodies(); + + AddPlinth(); + + // fix any particles below the ground plane in place + for (int i = 0; i < int(g_buffers->positions.size()); ++i) + if (g_buffers->positions[i].y < 0.0f) + g_buffers->positions[i].w = 0.0f; + + // expand radius for better self collision + g_params.radius *= 1.5f; + + g_lightDistance *= 1.5f; + } + + virtual void CreateBodies() + { + // build soft body + for (int x = 0; x < mStack[0]; ++x) + { + for (int y = 0; y < mStack[1]; ++y) + { + for (int z = 0; z < mStack[2]; ++z) + { + CreatePlasticBody(mRadius, mOffset + Vec3(x*(mScale.x + 1), y*(mScale.y + 1), z*(mScale.z + 1))*mRadius, mClusterStiffness, mInstances.size()); + } + } + } + } + + void CreatePlasticBody(float radius, Vec3 position, float clusterStiffness, int group = 0) + { + Instance instance; + + Mesh* mesh = ImportMesh(GetFilePathByPlatform(mFile).c_str()); + mesh->Normalize(); + mesh->Transform(TranslationMatrix(Point3(position))*ScaleMatrix(mScale*radius)); + + instance.mMesh = mesh; + instance.mColor = Vec3(0.5f, 0.5f, 1.0f); + instance.mOffset = g_buffers->rigidTranslations.size(); + + double createStart = GetSeconds(); + + // create soft body definition + NvFlexExtAsset* asset = NvFlexExtCreateSoftFromMesh( + (float*)&instance.mMesh->m_positions[0], + instance.mMesh->m_positions.size(), + (int*)&instance.mMesh->m_indices[0], + instance.mMesh->m_indices.size(), + radius, + mVolumeSampling, + mSurfaceSampling, + mClusterSpacing*radius, + mClusterRadius*radius, + clusterStiffness, + mLinkRadius*radius, + mLinkStiffness, + mGlobalStiffness); + + double createEnd = GetSeconds(); + + // create skinning + const int maxWeights = 4; + + instance.mSkinningIndices.resize(instance.mMesh->m_positions.size()*maxWeights); + instance.mSkinningWeights.resize(instance.mMesh->m_positions.size()*maxWeights); + + for (int i = 0; i < asset->numShapes; ++i) + instance.mRigidRestPoses.push_back(Vec3(&asset->shapeCenters[i * 3])); + + double skinStart = GetSeconds(); + + NvFlexExtCreateSoftMeshSkinning( + (float*)&instance.mMesh->m_positions[0], + instance.mMesh->m_positions.size(), + asset->shapeCenters, + asset->numShapes, + mSkinningFalloff, + mSkinningMaxDistance, + &instance.mSkinningWeights[0], + &instance.mSkinningIndices[0]); + + double skinEnd = GetSeconds(); + + printf("Created soft in %f ms Skinned in %f\n", (createEnd - createStart)*1000.0f, (skinEnd - skinStart)*1000.0f); + + const int particleOffset = g_buffers->positions.size(); + const int indexOffset = g_buffers->rigidOffsets.back(); + + // add particle data to solver + for (int i = 0; i < asset->numParticles; ++i) + { + g_buffers->positions.push_back(&asset->particles[i * 4]); + g_buffers->velocities.push_back(0.0f); + + const int phase = NvFlexMakePhase(group, eNvFlexPhaseSelfCollide | eNvFlexPhaseSelfCollideFilter); + g_buffers->phases.push_back(phase); + } + + // add shape data to solver + for (int i = 0; i < asset->numShapeIndices; ++i) + g_buffers->rigidIndices.push_back(asset->shapeIndices[i] + particleOffset); + + for (int i = 0; i < asset->numShapes; ++i) + { + g_buffers->rigidOffsets.push_back(asset->shapeOffsets[i] + indexOffset); + g_buffers->rigidTranslations.push_back(Vec3(&asset->shapeCenters[i * 3])); + g_buffers->rigidRotations.push_back(Quat()); + g_buffers->rigidCoefficients.push_back(asset->shapeCoefficients[i]); + } + + // add link data to the solver + for (int i = 0; i < asset->numSprings; ++i) + { + g_buffers->springIndices.push_back(asset->springIndices[i * 2 + 0]); + g_buffers->springIndices.push_back(asset->springIndices[i * 2 + 1]); + + g_buffers->springStiffness.push_back(asset->springCoefficients[i]); + g_buffers->springLengths.push_back(asset->springRestLengths[i]); + } + + NvFlexExtDestroyAsset(asset); + + mInstances.push_back(instance); + } + + virtual void Draw(int pass) + { + if (!g_drawMesh) + return; + + for (int s = 0; s < int(mInstances.size()); ++s) + { + const Instance& instance = mInstances[s]; + + Mesh m; + m.m_positions.resize(instance.mMesh->m_positions.size()); + m.m_normals.resize(instance.mMesh->m_normals.size()); + m.m_indices = instance.mMesh->m_indices; + + for (int i = 0; i < int(instance.mMesh->m_positions.size()); ++i) + { + Vec3 softPos; + Vec3 softNormal; + + for (int w = 0; w < 4; ++w) + { + const int cluster = instance.mSkinningIndices[i * 4 + w]; + const float weight = instance.mSkinningWeights[i * 4 + w]; + + if (cluster > -1) + { + // offset in the global constraint array + int rigidIndex = cluster + instance.mOffset; + + Vec3 localPos = Vec3(instance.mMesh->m_positions[i]) - instance.mRigidRestPoses[cluster]; + + Vec3 skinnedPos = g_buffers->rigidTranslations[rigidIndex] + Rotate(g_buffers->rigidRotations[rigidIndex], localPos); + Vec3 skinnedNormal = Rotate(g_buffers->rigidRotations[rigidIndex], instance.mMesh->m_normals[i]); + + softPos += skinnedPos*weight; + softNormal += skinnedNormal*weight; + } + } + + m.m_positions[i] = Point3(softPos); + m.m_normals[i] = softNormal; + } + + DrawMesh(&m, instance.mColor); + } + } + + struct Instance + { + Mesh* mMesh; + std::vector<int> mSkinningIndices; + std::vector<float> mSkinningWeights; + vector<Vec3> mRigidRestPoses; + Vec3 mColor; + int mOffset; + }; + + std::vector<Instance> mInstances; + + const char* mFile; + Vec3 mScale; + Vec3 mOffset; + + float mRadius; + + float mClusterSpacing; + float mClusterRadius; + float mClusterStiffness; + + float mLinkRadius; + float mLinkStiffness; + + float mGlobalStiffness; + + float mSurfaceSampling; + float mVolumeSampling; + + float mSkinningFalloff; + float mSkinningMaxDistance; + + int mStack[3]; +};
\ No newline at end of file diff --git a/demo/scenes/plasticstack.h b/demo/scenes/plasticstack.h new file mode 100644 index 0000000..e1543ca --- /dev/null +++ b/demo/scenes/plasticstack.h @@ -0,0 +1,50 @@ + +class PlasticStack : public Scene +{ +public: + + PlasticStack(const char* name) : Scene(name) {} + + virtual void Initialize() + { + g_params.radius = 0.225f; + + g_params.numIterations = 2; + g_params.dynamicFriction = 0.5f; + g_params.particleFriction = 0.15f; + g_params.dissipation = 0.0f; + g_params.viscosity = 0.0f; + + AddPlinth(); + + const float rotation = -kPi*0.5f; + const float spacing = g_params.radius*0.5f; + + // alternative box and sphere shapes + const char* mesh[] = + { + "../../data/box_high.ply", + "../../data/sphere.ply" + }; + + Vec3 lower = Vec3(4.0f, 1.0f, 0.0f); + float sizeInc = 0.0f; + float size = 1.0f; + int group = 0; + + for (int i=0; i < 8; ++i) + { + CreateParticleShape(GetFilePathByPlatform(mesh[i%2]).c_str(), lower, size + i*sizeInc, rotation, spacing, Vec3(.0f, 0.0f, 0.0f), 1.0f, true, 1.0f, NvFlexMakePhase(group++, 0), true, 0.0f, 0.0f, g_params.radius*0.5f); + + lower += Vec3(0.0f, size + i*sizeInc + 0.2f, 0.0f); + } + + g_params.plasticThreshold = 0.00025f; + g_params.plasticCreep = 0.165f; + + g_numSubsteps = 4; + + // draw options + g_drawPoints = false; + } +}; diff --git a/demo/scenes/player.h b/demo/scenes/player.h new file mode 100644 index 0000000..83407ac --- /dev/null +++ b/demo/scenes/player.h @@ -0,0 +1,290 @@ + + +/* +class Player : public Scene +{ +public: + + Player(const char* filename) : Scene("Player"), mFilename(filename), mRecording(NULL) + { + } + + virtual void Initialize() + { + if (!mRecording) + mRecording = fopen(mFilename, "rb"); + + if (mRecording) + fseek(mRecording, 0, SEEK_SET); + + // read first frame + ReadFrame(); + + g_lightDistance = 100.0f; + g_fogDistance = 0.0f; + + g_camSpeed *= 100.0f; + g_camNear *= 100.0f; + g_camFar *= 100.0f; + g_pause = true; + + g_dt = 1.0f/30.0f; + g_numSubsteps = 2; + + g_drawPoints = true; + + mInitialActive = g_buffers->activeIndices; + } + + virtual void PostInitialize() + { + g_buffers->activeIndices = mInitialActive; + + NvFlexSetActive(g_flex, &mInitialActive[0], mInitialActive.size(), eFlexMemoryHost); + } + + virtual Matrix44 GetBasis() + { + // Coordinate fip for Unreal captures + + Matrix44 flip = Matrix44::kIdentity; + flip.SetCol(1, Vec4(0.0f, 0.0f, -1.0f, 0.0f)); + flip.SetCol(2, Vec4(0.0f, 1.0f, 0.0f, 0.0f)); + + return flip; + } + + template<typename Element> + void ReadArray(std::vector<Element>& dest, bool enable=true) + { + if (feof(mRecording)) + return; + + int length; + int r; + r = fread(&length, sizeof(int), 1, mRecording); + + if (feof(mRecording)) + return; + + if (enable) + { + int numElements = length/sizeof(Element); + + dest.resize(numElements); + r = fread(&dest[0], length, 1, mRecording); + } + else + r = fseek(mRecording, length, SEEK_CUR); + + (void)r; + } + + virtual void KeyDown(int key) + { + if (key == '[') + { + Vec3 lower(FLT_MAX), upper(-FLT_MAX); + + // particle bounds + for (int i=0; i < int(g_buffers->activeIndices.size()); ++i) + { + int index = g_buffers->activeIndices[i]; + + lower = Min(Vec3(g_buffers->positions[index]), lower); + upper = Max(Vec3(g_buffers->positions[index]), upper); + } + + // center camera + g_camPos = (lower+upper)*0.5f; + g_camPos = GetBasis()*g_camPos; + } + } + + bool VerifyArray(float* ptr, int n) + { + for (int i=0; i < n; ++i) + if (!isfinite(ptr[i])) + return false; + + return true; + } + + template <typename Element> + void ReadValue(Element& e, bool enable=true) + { + if (feof(mRecording)) + return; + + int r; + if (enable) + r = fread(&e, sizeof(e), 1, mRecording); + else + r = fseek(mRecording, sizeof(e), SEEK_CUR); + + (void)r; + } + + void ReadFrame() + { + if (!mRecording) + return; + + if (feof(mRecording)) + return; + + // params + ReadValue(g_params, true); + + // particle data + //ReadArray(g_buffers->positions, true); + + if (true) + { + for (int i=0; i < int(g_buffers->positions.size()); ++i) + { + if (!isfinite(g_buffers->positions[i].x) || + !isfinite(g_buffers->positions[i].y) || + !isfinite(g_buffers->positions[i].z)) + printf("particles failed at frame %d\n", g_frame); + } + } + + ReadArray(g_buffers->restPositions, true); + ReadArray(g_buffers->velocities, true); + ReadArray(g_buffers->phases, true); + ReadArray(g_buffers->activeIndices, true); + + // spring data + ReadArray(g_buffers->springIndices, true); + ReadArray(g_buffers->springLengths, true); + ReadArray(g_buffers->springStiffness, true); + + // shape data + ReadArray(g_buffers->rigidIndices, true); + ReadArray(g_buffers->rigidLocalPositions, true); + ReadArray(g_buffers->rigidLocalNormals, true); + + ReadArray(g_buffers->rigidCoefficients, true); + ReadArray(g_buffers->rigidOffsets, true); + ReadArray(g_buffers->rigidRotations, true); + ReadArray(g_buffers->rigidTranslations, true); + + if (true) + { + + if (!VerifyArray((float*)&g_buffers->rigidLocalPositions[0], g_buffers->rigidLocalPositions.size()*3)) + printf("rigid local pos failed\n"); + + if (!VerifyArray((float*)&g_buffers->rigidTranslations[0], g_buffers->rigidTranslations.size()*3)) + printf("rigid translations failed\n"); + + if (!VerifyArray((float*)&g_buffers->rigidRotations[0], g_buffers->rigidRotations.size()*3)) + printf("rigid rotations failed\n"); + } + + // triangle data + ReadArray(g_buffers->triangles, true); + ReadArray(g_buffers->triangleNormals, true); + + // convex shapes + ReadArray(g_buffers->shapeGeometry, true); + ReadArray(g_buffers->shapeAabbMin, true); + ReadArray(g_buffers->shapeAabbMax, true); + ReadArray(g_buffers->shapeStarts, true); + ReadArray(g_buffers->shapePositions, true); + ReadArray(g_buffers->shapeRotations, true); + ReadArray(g_buffers->shapePrevPositions, true); + ReadArray(g_buffers->shapePrevRotations, true); + ReadArray(g_buffers->shapeFlags, true); + + if (true) + { + if (!VerifyArray((float*)&g_buffers->shapePositions[0], g_buffers->shapePositions.size()*4)) + printf("shapes translations invalid\n"); + + if (!VerifyArray((float*)&g_buffers->shapeRotations[0], g_buffers->shapeRotations.size()*4)) + printf("shapes rotations invalid\n"); + } + + int numMeshes = 0; + ReadValue(numMeshes); + + // map serialized mesh ptrs to current meshes + std::map<NvFlexTriangleMeshId, NvFlexTriangleMeshId> originalToNewMeshMap; + + for (int i=0; i < numMeshes; ++i) + { + Mesh m; + + NvFlexTriangleMeshId originalPtr; + ReadValue(originalPtr); + + ReadArray(m.m_positions); + ReadArray(m.m_indices); + + if (!VerifyArray((float*)&m.m_positions[0], m.m_positions.size()*3)) + printf("mesh vertices invalid\n"); + + printf("Creating mesh: %d faces %d vertices\n", m.GetNumFaces(), m.GetNumVertices()); + + Vec3 lower, upper; + m.GetBounds(lower, upper); + m.CalculateNormals(); + + NvFlexTriangleMeshId collisionMesh = NvFlexCreateTriangleMesh(); + NvFlexUpdateTriangleMesh(collisionMesh, (float*)&m.m_positions[0], (int*)&m.m_indices[0], int(m.m_positions.size()), int(m.m_indices.size())/3, lower, upper, eFlexMemoryHost); + + // create a render mesh + g_meshes[collisionMesh] = CreateGpuMesh(&m); + + // create map from captured triangle mesh pointer to our recreated version + originalToNewMeshMap[originalPtr] = collisionMesh; + } + + int numTriMeshInstances = 0; + + // remap shape ptrs + for (int i=0; i < int(g_buffers->shapeFlags.size()); ++i) + { + if ((g_buffers->shapeFlags[i]&eNvFlexShapeFlagTypeMask) == eNvFlexShapeTriangleMesh) + { + numTriMeshInstances++; + + NvFlexCollisionGeometry geo = g_buffers->shapeGeometry[g_buffers->shapeStarts[i]]; + + if (originalToNewMeshMap.find(geo.triMesh.mesh) == originalToNewMeshMap.end()) + { + printf("Missing mesh for geometry entry\n"); + assert(0); + } + else + { + g_buffers->shapeGeometry[g_buffers->shapeStarts[i]].mTriMesh.mMesh = originalToNewMeshMap[geo.triMesh.mesh]; + } + } + } + + printf("Num Tri Meshes: %d Num Tri Mesh Instances: %d\n", int(g_meshes.size()), numTriMeshInstances); + + } + + virtual void Draw(int pass) + { + } + + virtual void DoGui() + { + } + + virtual void Update() + { + + } + + const char* mFilename; + FILE* mRecording; + + std::vector<int> mInitialActive; +}; +*/ diff --git a/demo/scenes/potpourri.h b/demo/scenes/potpourri.h new file mode 100644 index 0000000..338a09a --- /dev/null +++ b/demo/scenes/potpourri.h @@ -0,0 +1,117 @@ + +class PotPourri : public Scene +{ +public: + + PotPourri(const char* name) : Scene(name) + { + } + + virtual void Initialize() + { + int sx = 2; + int sy = 2; + int sz = 2; + + Vec3 lower(0.0f, 4.2f + g_params.radius*0.25f, 0.0f); + + int dimx = 5; + int dimy = 10; + int dimz = 5; + + float radius = g_params.radius; + int group = 0; + + if (1) + { + // create a basic grid + for (int y=0; y < dimy; ++y) + for (int z=0; z < dimz; ++z) + for (int x=0; x < dimx; ++x) + CreateParticleShape( + GetFilePathByPlatform("../../data/box.ply").c_str(), + (g_params.radius*0.905f)*Vec3(float(x*sx), float(y*sy), float(z*sz)) + (g_params.radius*0.1f)*Vec3(float(x),float(y),float(z)) + lower, + g_params.radius*0.9f*Vec3(float(sx), float(sy), float(sz)), 0.0f, g_params.radius*0.9f, Vec3(0.0f), 1.0f, true, 1.0f, NvFlexMakePhase(group++, 0), true, 0.001f); + + AddPlinth(); + } + + if (1) + { + int dimx = 60; + int dimy = 40; + + float stretchStiffness = 1.0f; + float bendStiffness = 0.5f; + float shearStiffness = 0.7f; + + int clothStart = g_buffers->positions.size(); + + CreateSpringGrid(Vec3(0.0f, 0.0f, -1.0f), dimx, dimy, 1, radius*0.5f, NvFlexMakePhase(group++, 0), stretchStiffness, bendStiffness, shearStiffness, Vec3(0.0f), 1.0f); + + int corner0 = clothStart + 0; + int corner1 = clothStart + dimx-1; + int corner2 = clothStart + dimx*(dimy-1); + int corner3 = clothStart + dimx*dimy-1; + + g_buffers->positions[corner0].w = 0.0f; + g_buffers->positions[corner1].w = 0.0f; + g_buffers->positions[corner2].w = 0.0f; + g_buffers->positions[corner3].w = 0.0f; + + // add tethers + for (int i=clothStart; i < int(g_buffers->positions.size()); ++i) + { + float x = g_buffers->positions[i].x; + g_buffers->positions[i].y = 4.0f - sinf(DegToRad(15.0f))*x; + g_buffers->positions[i].x = cosf(DegToRad(25.0f))*x; + + if (i != corner0 && i != corner1 && i != corner2 && i != corner3) + { + float stiffness = -0.5f; + float give = 0.05f; + + CreateSpring(corner0, i, stiffness, give); + CreateSpring(corner1, i, stiffness, give); + CreateSpring(corner2, i, stiffness, give); + CreateSpring(corner3, i, stiffness, give); + } + } + + g_buffers->positions[corner1] = g_buffers->positions[corner0] + (g_buffers->positions[corner1]-g_buffers->positions[corner0])*0.9f; + g_buffers->positions[corner2] = g_buffers->positions[corner0] + (g_buffers->positions[corner2]-g_buffers->positions[corner0])*0.9f; + g_buffers->positions[corner3] = g_buffers->positions[corner0] + (g_buffers->positions[corner3]-g_buffers->positions[corner0])*0.9f; + } + + + for (int i=0; i < 50; ++i) + CreateParticleShape(GetFilePathByPlatform("../../data/banana.obj").c_str(), Vec3(0.4f, 8.5f + i*0.25f, 0.25f) + RandomUnitVector()*radius*0.25f, Vec3(1), 0.0f, radius, Vec3(0.0f), 1.0f, true, 0.5f, NvFlexMakePhase(group++, 0), true, radius*0.1f, 0.0f, 0.0f, 1.25f*Vec4(0.875f, 0.782f, 0.051f, 1.0f)); + + + //g_numExtraParticles = 32*1024; + g_numSubsteps = 2; + g_params.numIterations = 4; + + g_params.radius *= 1.0f; + g_params.staticFriction = 0.7f; + g_params.dynamicFriction = 0.75f; + g_params.dissipation = 0.01f; + g_params.particleCollisionMargin = g_params.radius*0.05f; + g_params.sleepThreshold = g_params.radius*0.25f; + g_params.damping = 0.25f; + g_params.maxAcceleration = 400.0f; + + g_windStrength = 0.0f; + + // draw options + g_drawPoints = false; + + g_emitters[0].mEnabled = true; + g_emitters[0].mSpeed = (g_params.radius*2.0f/g_dt); + } + + virtual void Update() + { + + } +}; diff --git a/demo/scenes/rayleightaylor.h b/demo/scenes/rayleightaylor.h new file mode 100644 index 0000000..f07fb46 --- /dev/null +++ b/demo/scenes/rayleightaylor.h @@ -0,0 +1,143 @@ + +class RayleighTaylor3D : public Scene +{ +public: + + RayleighTaylor3D(const char* name) : Scene(name) {} + + int base; + int width; + int height; + int depth; + + virtual void Initialize() + { + float radius = 0.05f; + float restDistance = radius*0.5f; + + width = 128; + height = 24; + depth = 24; + + base = 4; + + float sep = restDistance*0.9f; + int group = 0; + + CreateParticleGrid(Vec3(0.0f, 0.0f, 0.0f), width, base, depth, sep, Vec3(0.0f), 0.0f, false, 0.0f, NvFlexMakePhase(group++, 0), 0.0f); + CreateParticleGrid(Vec3(0.0f, base*sep, 0.0f), width, height, depth, sep, Vec3(0.0f), 0.24f, false, 0.0f, NvFlexMakePhase(group++, eNvFlexPhaseSelfCollide | eNvFlexPhaseFluid), restDistance*0.01f); + CreateParticleGrid(Vec3(0.0f, sep*height + base*sep, 0.0f), width, height, depth, sep, Vec3(0.0f), 0.25f, false, 0.0f, NvFlexMakePhase(group++, eNvFlexPhaseSelfCollide | eNvFlexPhaseFluid), restDistance*0.01f); + + g_params.gravity[1] = -9.f; + g_params.radius = radius; + g_params.dynamicFriction = 0.00f; + g_params.fluid = true; + g_params.viscosity = 2.0f; + g_params.numIterations = 10; + g_params.vorticityConfinement = 0.0f; + g_params.anisotropyScale = 50.0f; + g_params.smoothing = 1.f; + g_params.fluidRestDistance = restDistance; + g_params.numPlanes = 5; + g_params.cohesion = 0.0002125f; + g_params.surfaceTension = 0.0f; + g_params.collisionDistance = 0.001f;//restDistance*0.5f; + //g_params.solidPressure = 0.2f; + + g_params.relaxationFactor = 20.0f; + g_numSubsteps = 5; + + g_fluidColor = Vec4(0.2f, 0.6f, 0.9f, 1.0f); + + g_lightDistance *= 0.85f; + + // draw options + g_drawDensity = true; + g_drawDiffuse = false; + g_drawEllipsoids = false; + g_drawPoints = true; + + g_blur = 2.0f; + + g_warmup = true; + } + + virtual void Update() + { + if (g_params.numPlanes == 4) + g_params.dynamicFriction = 0.2f; + + if (g_frame == 32) + { + int layer1start = width*depth*base; + int layer1end = layer1start + width*height*depth; + for (int i = layer1start; i < layer1end; ++i) + g_buffers->positions[i].w = 1.0f; + } + } +}; + +class RayleighTaylor2D : public Scene +{ +public: + + RayleighTaylor2D(const char* name) : Scene(name) {} + + int base; + int width; + int height; + int depth; + + virtual void Initialize() + { + float radius = 0.05f; + float restDistance = radius*0.5f; + + width = 128; + height = 24; + depth = 1; + + base = 4; + + float sep = restDistance*0.7f; + int group = 0; + + CreateParticleGrid(Vec3(0.0f, 0.0f, 0.0f), width, base, depth, sep, Vec3(0.0f), 0.0f, false, 0.0f, NvFlexMakePhase(group++, 0), 0.0f); + CreateParticleGrid(Vec3(0.0f, base*sep, 0.0f), width, height, depth, sep, Vec3(0.0f), 1.0f, false, 0.0f, NvFlexMakePhase(group++, eNvFlexPhaseSelfCollide | eNvFlexPhaseFluid), restDistance*0.01f); + CreateParticleGrid(Vec3(0.0f, sep*height + base*sep, 0.0f), width, height, depth, sep, Vec3(0.0f), 0.25f, false, 0.0f, NvFlexMakePhase(group++, eNvFlexPhaseSelfCollide | eNvFlexPhaseFluid), restDistance*0.01f); + + g_params.gravity[1] = -9.f; + g_params.radius = radius; + g_params.dynamicFriction = 0.00f; + g_params.fluid = true; + g_params.viscosity = 0.0f; + g_params.numIterations = 10; + g_params.vorticityConfinement = 0.0f; + g_params.anisotropyScale = 50.0f; + g_params.smoothing = 1.f; + g_params.fluidRestDistance = restDistance; + g_params.numPlanes = 5; + g_params.cohesion = 0.0025f; + g_params.surfaceTension = 0.0f; + g_params.collisionDistance = 0.001f; + g_params.restitution = 0.0f; + + g_params.relaxationFactor = 1.0f; + g_numSubsteps = 10; + + g_fluidColor = Vec4(0.2f, 0.6f, 0.9f, 1.0f); + + g_lightDistance *= 0.85f; + + // draw options + g_drawDensity = false; + g_drawDiffuse = false; + g_drawEllipsoids = false; + g_drawPoints = true; + + g_pointScale = 0.9f; + g_blur = 2.0f; + + g_warmup = true; + } +};
\ No newline at end of file diff --git a/demo/scenes/restitution.h b/demo/scenes/restitution.h new file mode 100644 index 0000000..521f526 --- /dev/null +++ b/demo/scenes/restitution.h @@ -0,0 +1,27 @@ + + + +class Restitution : public Scene +{ +public: + + Restitution(const char* name) : Scene(name) {} + + void Initialize() + { + float radius = 0.05f; + CreateParticleGrid(Vec3(0.0f, 1.0f, 0.0f), 1, 1, 1, radius, Vec3(0.0f), 1.0f, false, 0.0f, NvFlexMakePhase(0, eNvFlexPhaseSelfCollide), 0.0f); + + g_params.radius = radius; + g_params.dynamicFriction = 0.025f; + g_params.dissipation = 0.0f; + g_params.restitution = 1.0; + g_params.numIterations = 4; + + g_numSubsteps = 4; + + // draw options + g_drawPoints = true; + } + +}; diff --git a/demo/scenes/ridigbody.h b/demo/scenes/ridigbody.h new file mode 100644 index 0000000..a6fd7c0 --- /dev/null +++ b/demo/scenes/ridigbody.h @@ -0,0 +1,139 @@ +class RigidBody : public Scene +{ +public: + + RigidBody(const char* name, const char* mesh) : + Scene(name), + mFile(mesh), + mScale(2.0f), + mOffset(0.0f, 1.0f, 0.0f), + mRadius(0.1f) + { + mStack[0] = 1; + mStack[1] = 1; + mStack[2] = 1; + } + + virtual void Initialize() + { + float radius = mRadius; + + g_params.radius = radius; + g_params.dynamicFriction = 0.35f; + g_params.particleFriction = 0.25f; + g_params.numIterations = 4; + g_params.collisionDistance = radius*0.75f; + + g_numSubsteps = 2; + + // draw options + g_drawPoints = true; + g_wireframe = false; + g_drawSprings = false; + g_drawBases = true; + + g_buffers->rigidOffsets.push_back(0); + + mInstances.resize(0); + + + CreateBodies(); + + // fix any particles below the ground plane in place + for (int i = 0; i < int(g_buffers->positions.size()); ++i) + if (g_buffers->positions[i].y < 0.0f) + g_buffers->positions[i].w = 0.0f; + + // expand radius for better self collision + g_params.radius *= 1.5f; + + g_lightDistance *= 1.5f; + } + + virtual void CreateBodies() + { + // build hard body + for (int x = 0; x < mStack[0]; ++x) + { + for (int y = 0; y < mStack[1]; ++y) + { + for (int z = 0; z < mStack[2]; ++z) + { + CreateRigidBody(mRadius, mOffset + Vec3(x*(mScale.x + 1), y*(mScale.y + 1), z*(mScale.z + 1))*mRadius); + } + } + } + } + + void CreateRigidBody(float radius, Vec3 position, int group = 0) + { + Instance instance; + + Mesh* mesh = ImportMesh(GetFilePathByPlatform(mFile).c_str()); + mesh->Normalize(); + mesh->Transform(TranslationMatrix(Point3(position))*ScaleMatrix(mScale*radius)); + + instance.mMesh = mesh; + instance.mColor = Vec3(0.5f, 0.5f, 1.0f); + + double createStart = GetSeconds(); + + //const float spacing = radius; + const float spacing = radius*0.5f; + + NvFlexExtAsset* asset = NvFlexExtCreateRigidFromMesh( + (float*)&mesh->m_positions[0], + int(mesh->m_positions.size()), + (int*)&mesh->m_indices[0], + mesh->m_indices.size(), + spacing, + -spacing*0.5f); + + double createEnd = GetSeconds(); + + const int particleOffset = g_buffers->positions.size(); + const int indexOffset = g_buffers->rigidOffsets.back(); + + // add particle data to solver + for (int i = 0; i < asset->numParticles; ++i) + { + g_buffers->positions.push_back(&asset->particles[i * 4]); + g_buffers->velocities.push_back(0.0f); + + const int phase = NvFlexMakePhase(group, eNvFlexPhaseSelfCollide | eNvFlexPhaseSelfCollideFilter); + g_buffers->phases.push_back(phase); + } + + // add shape data to solver + for (int i = 0; i < asset->numShapeIndices; ++i) + g_buffers->rigidIndices.push_back(asset->shapeIndices[i] + particleOffset); + + for (int i = 0; i < asset->numShapes; ++i) + { + g_buffers->rigidOffsets.push_back(asset->shapeOffsets[i] + indexOffset); + g_buffers->rigidTranslations.push_back(Vec3(&asset->shapeCenters[i * 3])); + g_buffers->rigidRotations.push_back(Quat()); + g_buffers->rigidCoefficients.push_back(asset->shapeCoefficients[i]); + } + + NvFlexExtDestroyAsset(asset); + + mInstances.push_back(instance); + } + + struct Instance + { + Mesh* mMesh; + Vec3 mColor; + }; + + std::vector<Instance> mInstances; + + const char* mFile; + Vec3 mScale; + Vec3 mOffset; + + float mRadius; + + int mStack[3]; +};
\ No newline at end of file diff --git a/demo/scenes/rigidfluidcoupling.h b/demo/scenes/rigidfluidcoupling.h new file mode 100644 index 0000000..b978eb8 --- /dev/null +++ b/demo/scenes/rigidfluidcoupling.h @@ -0,0 +1,61 @@ + +class RigidFluidCoupling : public Scene +{ +public: + + RigidFluidCoupling(const char* name) : Scene(name) {} + + virtual void Initialize() + { + float minSize = 0.5f; + float maxSize = 1.0f; + + float radius = 0.1f; + int group = 0; + + Randf(); + + for (int i=0; i < 5; i++) + AddRandomConvex(10, Vec3(i*2.0f, 0.0f, Randf(0.0f, 2.0f)), minSize, maxSize, Vec3(0.0f, 1.0f, 0.0f), Randf(0.0f, k2Pi*10.0f)); + + for (int z=0; z < 10; ++z) + for (int x=0; x < 50; ++x) + CreateParticleShape( + GetFilePathByPlatform("../../data/box.ply").c_str(), + Vec3(x*radius*2 - 1.0f, 1.0f + radius, 1.f + z*2.0f*radius) + 0.5f*Vec3(Randf(radius), 0.0f, Randf(radius)), + Vec3(2.0f, 2.0f + Randf(0.0f, 4.0f), 2.0f)*radius*0.5f, + 0.0f, + radius*0.5f, + Vec3(0.0f), + 1.0f, + true, + 1.0f, + NvFlexMakePhase(group++, 0), + true, + 0.0f); + + + // separte solid particle count + g_numSolidParticles = g_buffers->positions.size(); + + // number of fluid particles to allocate + g_numExtraParticles = 64*1024; + + g_params.radius = radius; + g_params.dynamicFriction = 0.5f; + g_params.fluid = true; + g_params.viscosity = 0.1f; + g_params.numIterations = 3; + g_params.vorticityConfinement = 0.0f; + g_params.anisotropyScale = 25.0f; + g_params.fluidRestDistance = g_params.radius*0.55f; + + + g_emitters[0].mEnabled = true; + g_emitters[0].mSpeed = 2.0f*(g_params.fluidRestDistance)/g_dt; + + // draw options + g_drawPoints = false; + g_drawEllipsoids = true; + } +};
\ No newline at end of file diff --git a/demo/scenes/rigidpile.h b/demo/scenes/rigidpile.h new file mode 100644 index 0000000..dcd1282 --- /dev/null +++ b/demo/scenes/rigidpile.h @@ -0,0 +1,129 @@ + +class RigidPile : public Scene +{ +public: + + RigidPile(const char* name, int brickHeight) : Scene(name), mHeight(brickHeight) + { + } + + virtual void Initialize() + { + int sx = 2; + int sy = mHeight; + int sz = 2; + + Vec3 lower(0.0f, 1.5f + g_params.radius*0.25f, 0.0f); + + int dimx = 10; + int dimy = 10; + int dimz = 10; + + float radius = g_params.radius; + + if (1) + { + Mesh* mesh = ImportMesh(GetFilePathByPlatform("../../data/box.ply").c_str()); + + // create a basic grid + for (int y=0; y < dimy; ++y) + for (int z=0; z < dimz; ++z) + for (int x=0; x < dimx; ++x) + CreateParticleShape( + mesh, + (g_params.radius*0.905f)*Vec3(float(x*sx), float(y*sy), float(z*sz)) + (g_params.radius*0.1f)*Vec3(float(x),float(y),float(z)) + lower, + g_params.radius*0.9f*Vec3(float(sx), float(sy), float(sz)), 0.0f, g_params.radius*0.9f, Vec3(0.0f), 1.0f, true, 1.0f, NvFlexMakePhase(g_buffers->rigidOffsets.size()+1, 0), true, 0.002f);// 0.002f); + + + delete mesh; + + AddPlinth(); + } + else + { + // brick work + int wdimx = 10; + int wdimy = 10; + + int bdimx = 4; + int bdimy = 2; + int bdimz = 2; + + for (int y=0; y < wdimy; ++y) + { + for (int x=0; x < wdimx; ++x) + { + Vec3 lower = Vec3(x*bdimx*radius + 0.5f*radius, 0.93f*bdimy*y*radius, 0.0f); + + if (y&1) + lower += Vec3(bdimx*0.25f*radius + 0.5f*radius, 0.0f, 0.0f); + + //CreateParticleGrid(lower, bdimx, bdimy, bdimz, radius, Vec3(0.0f), 1.0f, true, g_buffers->rigidOffsets.size()+1, 0.0f); + CreateParticleShape(GetFilePathByPlatform("../../data/box.ply").c_str(), lower + RandomUnitVector()*Vec3(0.0f, 0.0f, 0.0f), Vec3(bdimx*radius, bdimy*radius, bdimz*radius), 0.0f, radius, Vec3(0.0f), 1.0f, true, 1.0f, NvFlexMakePhase(g_buffers->rigidOffsets.size()+1, 0), true, 0.0f, Vec3(0.0f, 0.0f, y*0.0001f)); + } + } + + if (0) + { + // create a basic grid + for (int y=0; y < dimy; ++y) + for (int z=0; z < 1; ++z) + for (int x=0; x < 1; ++x) + CreateParticleShape( + GetFilePathByPlatform("../../data/box.ply").c_str(), + 0.99f*(g_params.radius)*Vec3(float(x*sx), float(y*sy), float(z*sz)), + g_params.radius*Vec3(float(sx), float(sy), float(sz)), 0.0f, g_params.radius, Vec3(0.0f), 1.0f, true, 1.0f, NvFlexMakePhase(g_buffers->rigidOffsets.size()+1, 0), true, 0.0f); + + // create a basic grid + for (int y=0; y < dimy; ++y) + for (int z=0; z < 1; ++z) + for (int x=0; x < 1; ++x) + CreateParticleShape( + GetFilePathByPlatform("../../data/box.ply").c_str(), + 0.99f*(g_params.radius)*Vec3(float(sx*2 + x*sx), float(y*sy), float(z*sz)), + g_params.radius*Vec3(float(sx), float(sy), float(sz)), 0.0f, g_params.radius, Vec3(0.0f), 1.0f, true, 1.0f, NvFlexMakePhase(g_buffers->rigidOffsets.size()+1, 0), true, 0.0f); + } + + } + + + if (0) + { + float stretchStiffness = 1.0f; + float bendStiffness = 0.5f; + float shearStiffness = 0.7f; + + int dimx = 40; + int dimy = 40; + + CreateSpringGrid(Vec3(-1.0f, 1.0f + g_params.radius*0.5f, -1.0f), dimx, dimy, 1, g_params.radius*0.9f, NvFlexMakePhase(0, eNvFlexPhaseSelfCollide), stretchStiffness, bendStiffness, shearStiffness, Vec3(0.0f), 1.0f); + } + + + //g_numExtraParticles = 32*1024; + g_numSubsteps = 2; + g_params.numIterations = 8; + + g_params.radius *= 1.0f; + g_params.dynamicFriction = 0.4f; + g_params.dissipation = 0.01f; + g_params.particleCollisionMargin = g_params.radius*0.05f; + g_params.sleepThreshold = g_params.radius*0.25f; + g_params.shockPropagation = 3.f; + + g_windStrength = 0.0f; + + // draw options + g_drawPoints = false; + + g_emitters[0].mEnabled = true; + g_emitters[0].mSpeed = (g_params.radius*2.0f/g_dt); + } + + virtual void Update() + { + + } + + int mHeight; +}; diff --git a/demo/scenes/rigidrotation.h b/demo/scenes/rigidrotation.h new file mode 100644 index 0000000..8abcb98 --- /dev/null +++ b/demo/scenes/rigidrotation.h @@ -0,0 +1,56 @@ + + +class RigidRotation : public Scene +{ +public: + + RigidRotation(const char* name) : Scene(name) + { + } + + void Initialize() + { + float radius = 0.1f; + + float dimx = 1.0f; + float dimy = 5.0f; + float dimz = 1.0f; + + CreateParticleShape(GetFilePathByPlatform("../../data/box.ply").c_str(), Vec3(0.0f, 1.0f, 0.0f), Vec3(dimx, dimy, dimz)*radius, 0.0f, radius, Vec3(0.0f), 1.0f, true, 1.0f, 0, true, 0.0f, 0.0f, 0.0f); + + g_params.radius = radius; + g_params.gravity[1] = 0; + + g_params.numIterations = 1; + g_numSubsteps = 1; + + g_pause = true; + + g_drawBases = true; + } + + void Update() + { + if (g_frame == 0) + { + // rotate particles by 90 degrees + Vec3 lower, upper; + GetParticleBounds(lower, upper); + + Vec3 center = (lower + upper)*0.5f; + + Matrix44 rotation = RotationMatrix(DegToRad(95.0f), Vec3(0.0f, 0.0f, 1.0f)); + + for (int i = 0; i < int(g_buffers->positions.size()); ++i) + { + Vec3 delta = Vec3(g_buffers->positions[i]) - center; + + delta = Vec3(rotation*Vec4(delta, 1.0f)); + + g_buffers->positions[i].x = center.x + delta.x; + g_buffers->positions[i].y = center.y + delta.y; + g_buffers->positions[i].z = center.z + delta.z; + } + } + } +};
\ No newline at end of file diff --git a/demo/scenes/rockpool.h b/demo/scenes/rockpool.h new file mode 100644 index 0000000..e7c0034 --- /dev/null +++ b/demo/scenes/rockpool.h @@ -0,0 +1,78 @@ + + + +class RockPool: public Scene +{ +public: + + RockPool(const char* name) : Scene(name) {} + + void Initialize() + { + float radius = 0.1f; + + // convex rocks + float minSize = 0.1f; + float maxSize = 0.5f; + + for (int i=0; i < 4; i++) + for (int j=0; j < 2; j++) + AddRandomConvex(10, Vec3(48*radius*0.5f + i*maxSize*2.0f, 0.0f, j*maxSize*2.0f), minSize, maxSize, Vec3(0.0f, 1.0f, 0.0f), Randf(0.0f, k2Pi)); + + CreateParticleGrid(Vec3(0.0f, radius*0.5f, -1.0f), 32, 32, 32, radius*0.55f, Vec3(0.0f), 1.0f, false, 0.0f, NvFlexMakePhase(0, eNvFlexPhaseSelfCollide | eNvFlexPhaseFluid), 0.005f); + + g_numSubsteps = 2; + + g_params.radius = radius; + g_params.dynamicFriction = 0.00f; + g_params.fluid = true; + g_params.viscosity = 0.01f; + g_params.numIterations = 2; + g_params.vorticityConfinement = 75.0f; + g_params.anisotropyScale = 30.0f; + g_params.fluidRestDistance = radius*0.6f; + g_params.relaxationFactor = 1.0f; + g_params.smoothing = 0.5f; + g_params.diffuseThreshold *= 0.25f; + g_params.cohesion = 0.05f; + + g_maxDiffuseParticles = 64*1024; + g_diffuseScale = 0.5f; + g_params.diffuseBallistic = 16; + g_params.diffuseBuoyancy = 1.0f; + g_params.diffuseDrag = 1.0f; + + g_emitters[0].mEnabled = false; + + g_params.numPlanes = 5; + + g_waveFloorTilt = 0.0f; + g_waveFrequency = 1.5f; + g_waveAmplitude = 2.0f; + + // draw options + g_drawPoints = false; + g_drawEllipsoids = true; + g_drawDiffuse = true; + g_lightDistance = 1.8f; + + g_numExtraParticles = 80*1024; + + Emitter e1; + e1.mDir = Vec3(-1.0f, 0.0f, 0.0f); + e1.mRight = Vec3(0.0f, 0.0f, 1.0f); + e1.mPos = Vec3(3.8f, 1.f, 1.f) ; + e1.mSpeed = (g_params.fluidRestDistance/g_dt)*2.0f; // 2 particle layers per-frame + e1.mEnabled = true; + + Emitter e2; + e2.mDir = Vec3(1.0f, 0.0f, 0.0f); + e2.mRight = Vec3(0.0f, 0.0f, -1.0f); + e2.mPos = Vec3(2.f, 1.f, -0.f); + e2.mSpeed = (g_params.fluidRestDistance/g_dt)*2.0f; // 2 particle layers per-frame + e2.mEnabled = true; + + g_emitters.push_back(e1); + g_emitters.push_back(e2); + } +}; diff --git a/demo/scenes/sdfcollision.h b/demo/scenes/sdfcollision.h new file mode 100644 index 0000000..aab2182 --- /dev/null +++ b/demo/scenes/sdfcollision.h @@ -0,0 +1,54 @@ + +class SDFCollision : public Scene +{ +public: + + SDFCollision(const char* name) : Scene(name) + { + } + + virtual void Initialize() + { + const int dim = 128; + + NvFlexDistanceFieldId sdf = CreateSDF(GetFilePathByPlatform("../../data/bunny.ply").c_str(), dim); + + AddSDF(sdf, Vec3(-1.f, 0.0f, 0.0f), QuatFromAxisAngle(Vec3(0.0f, 1.0f, 0.0f), DegToRad(-45.0f)), 0.5f); + AddSDF(sdf, Vec3(0.0f, 0.0f, 0.0f), QuatFromAxisAngle(Vec3(0.0f, 1.0f, 0.0f), DegToRad(0.0f)), 1.0f); + AddSDF(sdf, Vec3(1.0f, 0.0f, 0.0f), QuatFromAxisAngle(Vec3(0.0f, 1.0f, 0.0f), DegToRad(45.0f)), 2.0f); + + float stretchStiffness = 1.0f; + float bendStiffness = 0.8f; + float shearStiffness = 0.5f; + + int dimx = 64; + int dimz = 64; + float radius = 0.05f; + int phase = NvFlexMakePhase(0, eNvFlexPhaseSelfCollide | eNvFlexPhaseSelfCollideFilter); + + CreateSpringGrid(Vec3(-0.6f, 2.9f, -0.6f), dimx, dimz, 1, radius*0.75f, phase, stretchStiffness, bendStiffness, shearStiffness, 0.0f, 1.0f); + + Vec3 lower, upper; + GetParticleBounds(lower, upper); + + g_params.radius = radius*1.0f; + g_params.dynamicFriction = 0.4f; + g_params.staticFriction = 0.4f; + g_params.particleFriction = 0.25f; + g_params.dissipation = 0.0f; + g_params.numIterations = 8; + g_params.viscosity = 0.0f; + g_params.drag = 0.02f; + g_params.lift = 0.1f; + g_params.collisionDistance = radius*0.5f; + g_params.relaxationFactor = 1.3f; + + g_numSubsteps = 3; + + g_windStrength = 0.0f; + + // draw options + g_drawPoints = false; + g_drawSprings = false; + } +}; diff --git a/demo/scenes/shapecollision.h b/demo/scenes/shapecollision.h new file mode 100644 index 0000000..07409b5 --- /dev/null +++ b/demo/scenes/shapecollision.h @@ -0,0 +1,101 @@ + + +class ShapeCollision : public Scene +{ +public: + + ShapeCollision(const char* name) : Scene(name) {} + + void Initialize() + { + float maxShapeRadius = 0.25f; + float minShapeRadius = 0.1f; + + int dimx = 4; + int dimy = 4; + int dimz = 4; + + float radius = 0.05f; + int phase = NvFlexMakePhase(0, eNvFlexPhaseSelfCollide); + + g_numSubsteps = 2; + + g_params.radius = radius; + g_params.dynamicFriction = 0.25f; + g_params.dissipation = 0.0f; + g_params.restitution = 0.0; + g_params.numIterations = 2; + g_params.particleCollisionMargin = g_params.radius*0.5f; + g_params.shapeCollisionMargin = g_params.radius*0.5f; + g_params.maxSpeed = 0.5f*radius*float(g_numSubsteps)/g_dt; + + CreateParticleGrid(Vec3(0.0f, 1.0f + dimy*maxShapeRadius*2.0f, 0.0f), 30, 50, 30, radius, Vec3(0.0f), 1.0f, false, 0.0f, phase, 0.0f); + + Mesh* box = ImportMesh(GetFilePathByPlatform("../../data/box.ply").c_str()); + box->Normalize(1.0f); + + NvFlexTriangleMeshId mesh = CreateTriangleMesh(box); + delete box; + + NvFlexDistanceFieldId sdf = CreateSDF(GetFilePathByPlatform("../../data/bunny.ply").c_str(), 128); + + for (int i=0; i < dimx; ++i) + { + for (int j=0; j < dimy; ++j) + { + for (int k=0; k < dimz; ++k) + { + int type = Rand()%6; + + Vec3 shapeTranslation = Vec3(float(i),float(j) + 0.5f,float(k))*maxShapeRadius*2.0f; + Quat shapeRotation = QuatFromAxisAngle(UniformSampleSphere(), Randf()*k2Pi); + + switch(type) + { + case 0: + { + AddSphere(Randf(minShapeRadius, maxShapeRadius), shapeTranslation, shapeRotation); + break; + } + case 1: + { + AddCapsule(Randf(minShapeRadius, maxShapeRadius)*0.5f, Randf()*maxShapeRadius, shapeTranslation, shapeRotation); + break; + } + case 2: + { + Vec3 extents = 0.75f*Vec3(Randf(minShapeRadius, maxShapeRadius), + Randf(minShapeRadius, maxShapeRadius), + Randf(minShapeRadius, maxShapeRadius)); + + AddBox(extents, shapeTranslation, shapeRotation); + break; + } + case 3: + { + AddRandomConvex(6 + Rand()%6, shapeTranslation, minShapeRadius, maxShapeRadius, UniformSampleSphere(), Randf()*k2Pi); + break; + } + case 4: + { + AddTriangleMesh(mesh, shapeTranslation, shapeRotation, Randf(0.5f, 1.0f)*maxShapeRadius); + break; + } + case 5: + { + AddSDF(sdf, shapeTranslation, shapeRotation, maxShapeRadius*2.0f); + break; + } + }; + } + } + } + } + + virtual void CenterCamera() + { + g_camPos.y = 2.0f; + g_camPos.z = 6.0f; + } + +};
\ No newline at end of file diff --git a/demo/scenes/softbody.h b/demo/scenes/softbody.h new file mode 100644 index 0000000..c12680c --- /dev/null +++ b/demo/scenes/softbody.h @@ -0,0 +1,325 @@ + + +class SoftBody : public Scene +{ +public: + + SoftBody(const char* name, const char* mesh) : + Scene(name), + mFile(mesh), + mScale(2.0f), + mOffset(0.0f, 1.0f, 0.0f), + mRadius(0.1f), + mClusterSpacing(1.0f), + mClusterRadius(0.0f), + mClusterStiffness(0.5f), + mLinkRadius(0.0f), + mLinkStiffness(1.0f), + mGlobalStiffness(0.0f), + mSurfaceSampling(0.0f), + mVolumeSampling(4.0f), + mSkinningFalloff(2.0f), + mSkinningMaxDistance(100.0f), + mPlasticThreshold(0.0f), + mPlasticCreep(0.0f), + mRelaxationFactor(1.0f), + mPlinth(false) + { + mStack[0] = 1; + mStack[1] = 1; + mStack[2] = 1; + } + + virtual void Initialize() + { + float radius = mRadius; + + g_params.radius = radius; + g_params.dynamicFriction = 0.35f; + g_params.particleFriction = 0.25f; + g_params.dissipation = 0.0f; + g_params.numIterations = 4; + g_params.viscosity = 0.0f; + g_params.drag = 0.0f; + g_params.lift = 0.0f; + g_params.collisionDistance = radius*0.75f; + + g_params.plasticThreshold = mPlasticThreshold; + g_params.plasticCreep = mPlasticCreep; + + g_params.relaxationFactor = mRelaxationFactor; + + g_windStrength = 0.0f; + + g_numSubsteps = 2; + + // draw options + g_drawPoints = false; + g_wireframe = false; + g_drawSprings = false; + g_drawBases = false; + + g_buffers->rigidOffsets.push_back(0); + + mInstances.resize(0); + + + CreateBodies(); + + if (mPlinth) { + AddPlinth(); + } + + // fix any particles below the ground plane in place + for (int i = 0; i < int(g_buffers->positions.size()); ++i) + if (g_buffers->positions[i].y < 0.0f) + g_buffers->positions[i].w = 0.0f; + + // expand radius for better self collision + g_params.radius *= 1.5f; + + g_lightDistance *= 1.5f; + } + + virtual void CreateBodies() + { + // build soft body + for (int x = 0; x < mStack[0]; ++x) + { + for (int y = 0; y < mStack[1]; ++y) + { + for (int z = 0; z < mStack[2]; ++z) + { + CreateSoftBody(mRadius, mOffset + Vec3(x*(mScale.x + 1), y*(mScale.y + 1), z*(mScale.z + 1))*mRadius, mClusterStiffness, mInstances.size()); + } + } + } + } + + void CreateSoftBody(float radius, Vec3 position, float clusterStiffness, int group = 0) + { + Instance instance; + + Mesh* mesh = ImportMesh(GetFilePathByPlatform(mFile).c_str()); + mesh->Normalize(); + mesh->Transform(TranslationMatrix(Point3(position))*ScaleMatrix(mScale*radius)); + + instance.mMesh = mesh; + instance.mColor = Vec3(0.5f, 0.5f, 1.0f); + instance.mOffset = g_buffers->rigidTranslations.size(); + + double createStart = GetSeconds(); + + // create soft body definition + NvFlexExtAsset* asset = NvFlexExtCreateSoftFromMesh( + (float*)&instance.mMesh->m_positions[0], + instance.mMesh->m_positions.size(), + (int*)&instance.mMesh->m_indices[0], + instance.mMesh->m_indices.size(), + radius, + mVolumeSampling, + mSurfaceSampling, + mClusterSpacing*radius, + mClusterRadius*radius, + clusterStiffness, + mLinkRadius*radius, + mLinkStiffness, + mGlobalStiffness); + + double createEnd = GetSeconds(); + + // create skinning + const int maxWeights = 4; + + instance.mSkinningIndices.resize(instance.mMesh->m_positions.size()*maxWeights); + instance.mSkinningWeights.resize(instance.mMesh->m_positions.size()*maxWeights); + + for (int i = 0; i < asset->numShapes; ++i) + instance.mRigidRestPoses.push_back(Vec3(&asset->shapeCenters[i * 3])); + + double skinStart = GetSeconds(); + + NvFlexExtCreateSoftMeshSkinning( + (float*)&instance.mMesh->m_positions[0], + instance.mMesh->m_positions.size(), + asset->shapeCenters, + asset->numShapes, + mSkinningFalloff, + mSkinningMaxDistance, + &instance.mSkinningWeights[0], + &instance.mSkinningIndices[0]); + + double skinEnd = GetSeconds(); + + printf("Created soft in %f ms Skinned in %f\n", (createEnd - createStart)*1000.0f, (skinEnd - skinStart)*1000.0f); + + const int particleOffset = g_buffers->positions.size(); + const int indexOffset = g_buffers->rigidOffsets.back(); + + // add particle data to solver + for (int i = 0; i < asset->numParticles; ++i) + { + g_buffers->positions.push_back(&asset->particles[i * 4]); + g_buffers->velocities.push_back(0.0f); + + const int phase = NvFlexMakePhase(group, eNvFlexPhaseSelfCollide | eNvFlexPhaseSelfCollideFilter); + g_buffers->phases.push_back(phase); + } + + // add shape data to solver + for (int i = 0; i < asset->numShapeIndices; ++i) + g_buffers->rigidIndices.push_back(asset->shapeIndices[i] + particleOffset); + + for (int i = 0; i < asset->numShapes; ++i) + { + g_buffers->rigidOffsets.push_back(asset->shapeOffsets[i] + indexOffset); + g_buffers->rigidTranslations.push_back(Vec3(&asset->shapeCenters[i * 3])); + g_buffers->rigidRotations.push_back(Quat()); + g_buffers->rigidCoefficients.push_back(asset->shapeCoefficients[i]); + } + + // add link data to the solver + for (int i = 0; i < asset->numSprings; ++i) + { + g_buffers->springIndices.push_back(asset->springIndices[i * 2 + 0]); + g_buffers->springIndices.push_back(asset->springIndices[i * 2 + 1]); + + g_buffers->springStiffness.push_back(asset->springCoefficients[i]); + g_buffers->springLengths.push_back(asset->springRestLengths[i]); + } + + NvFlexExtDestroyAsset(asset); + + mInstances.push_back(instance); + } + + virtual void Draw(int pass) + { + if (!g_drawMesh) + return; + + for (int s = 0; s < int(mInstances.size()); ++s) + { + const Instance& instance = mInstances[s]; + + Mesh m; + m.m_positions.resize(instance.mMesh->m_positions.size()); + m.m_normals.resize(instance.mMesh->m_normals.size()); + m.m_indices = instance.mMesh->m_indices; + + for (int i = 0; i < int(instance.mMesh->m_positions.size()); ++i) + { + Vec3 softPos; + Vec3 softNormal; + + for (int w = 0; w < 4; ++w) + { + const int cluster = instance.mSkinningIndices[i * 4 + w]; + const float weight = instance.mSkinningWeights[i * 4 + w]; + + if (cluster > -1) + { + // offset in the global constraint array + int rigidIndex = cluster + instance.mOffset; + + Vec3 localPos = Vec3(instance.mMesh->m_positions[i]) - instance.mRigidRestPoses[cluster]; + + Vec3 skinnedPos = g_buffers->rigidTranslations[rigidIndex] + Rotate(g_buffers->rigidRotations[rigidIndex], localPos); + Vec3 skinnedNormal = Rotate(g_buffers->rigidRotations[rigidIndex], instance.mMesh->m_normals[i]); + + softPos += skinnedPos*weight; + softNormal += skinnedNormal*weight; + } + } + + m.m_positions[i] = Point3(softPos); + m.m_normals[i] = softNormal; + } + + DrawMesh(&m, instance.mColor); + } + } + + struct Instance + { + Mesh* mMesh; + std::vector<int> mSkinningIndices; + std::vector<float> mSkinningWeights; + vector<Vec3> mRigidRestPoses; + Vec3 mColor; + int mOffset; + }; + + std::vector<Instance> mInstances; + + const char* mFile; + Vec3 mScale; + Vec3 mOffset; + + float mRadius; + + float mClusterSpacing; + float mClusterRadius; + float mClusterStiffness; + + float mLinkRadius; + float mLinkStiffness; + + float mGlobalStiffness; + + float mSurfaceSampling; + float mVolumeSampling; + + float mSkinningFalloff; + float mSkinningMaxDistance; + + float mPlasticThreshold; + float mPlasticCreep; + + float mRelaxationFactor; + + bool mPlinth; + + int mStack[3]; +}; + + + + +class SoftBodyFixed : public SoftBody +{ +public: + + SoftBodyFixed(const char* name, const char* mesh) : SoftBody(name, mesh) {} + + virtual void Initialize() + { + SoftBody::Initialize(); + + // fix any particles in the wall + for (int i = 0; i < int(g_buffers->positions.size()); ++i) + if (g_buffers->positions[i].x < mRadius) + g_buffers->positions[i].w = 0.0f; + } + + virtual void CreateBodies() + { + int x = 0; + int y = 0; + + for (int z = 0; z < 4; ++z) + { + float stiffness = sqr(mClusterStiffness*(z + 1)); + + CreateSoftBody(mRadius, mOffset + Vec3(x*(mScale.x + 1), y*(mScale.y + 1), -z*(mScale.z + 1))*mRadius, stiffness, mInstances.size()); + } + } + + virtual void PostInitialize() + { + SoftBody::PostInitialize(); + + (Vec4&)g_params.planes[1] = Vec4(1.0f, 0.0f, 0.0f, 0.0f); + g_params.numPlanes = 2; + } +}; diff --git a/demo/scenes/spherecloth.h b/demo/scenes/spherecloth.h new file mode 100644 index 0000000..cab7f4d --- /dev/null +++ b/demo/scenes/spherecloth.h @@ -0,0 +1,85 @@ + + + +class SphereCloth : public Scene +{ +public: + + SphereCloth(const char* name) : + Scene(name) {} + + virtual void Initialize() + { + float stretchStiffness = 1.0f; + float bendStiffness = 0.5f; + float shearStiffness = 0.5f; + + float radius = 0.05f; + + int dimx = 70; + int dimz = 70; + int phase = NvFlexMakePhase(0, eNvFlexPhaseSelfCollide | eNvFlexPhaseSelfCollideFilter); + + float spacing = radius*0.8f; + + CreateSpringGrid(Vec3(-dimx*spacing*0.5f, 1.5f, -dimz*spacing*0.5f), dimx, dimz, 1, spacing, phase, stretchStiffness, bendStiffness, shearStiffness, 0.0f, 1.0f); + + g_params.radius = radius*1.0f; + g_params.dynamicFriction = 0.45f; + g_params.particleFriction = 0.45f; + g_params.dissipation = 0.0f; + g_params.numIterations = 8; + g_params.viscosity = 0.0f; + g_params.drag = 0.05f; + g_params.collisionDistance = radius*0.5f; + g_params.relaxationMode = eNvFlexRelaxationGlobal; + g_params.relaxationFactor = 0.25f; + g_params.numPlanes = 1; + + g_numSubsteps = 2; + + g_windStrength = 0.0f; + + // draw options + g_drawPoints = false; + g_drawSprings = false; + + g_lightDistance *= 1.5f; + + mTime = 0.0f; + } + + void Update() + { + ClearShapes(); + + mTime += g_dt; + + // let cloth settle on object + float startTime = 1.0f; + + float time = Max(0.0f, mTime-startTime); + float lastTime = Max(0.0f, time-g_dt); + + const float rotationSpeed = 1.0f; + const float translationSpeed = 0.0f; + + Vec3 pos = Vec3(translationSpeed*(1.0f-cosf(time)), 0.5f, 0.0f); + Vec3 prevPos = Vec3(translationSpeed*(1.0f-cosf(lastTime)), 0.5f, 0.0f); + + Quat rot = QuatFromAxisAngle(Vec3(0.0f, 1.0f, 0.0f), kPi*(1.0f-cosf(rotationSpeed*time))); + Quat prevRot = QuatFromAxisAngle(Vec3(0.0f, 1.0f, 0.0f), kPi*(1.0f-cosf(rotationSpeed*lastTime))); + + AddSphere(0.5f, pos, rot); + //AddCapsule(0.25f, 0.5f, pos, rot); + + g_buffers->shapePrevPositions[0] = Vec4(prevPos, 0.0f); + g_buffers->shapePrevRotations[0] = prevRot; + + UpdateShapes(); + } + + float mTime; + int mType; +}; + diff --git a/demo/scenes/surfacetension.h b/demo/scenes/surfacetension.h new file mode 100644 index 0000000..b22ad6d --- /dev/null +++ b/demo/scenes/surfacetension.h @@ -0,0 +1,57 @@ + +class SurfaceTension : public Scene +{ +public: + + SurfaceTension(const char* name, float surfaceTension) : Scene(name), surfaceTension(surfaceTension) {} + + virtual void Initialize() + { + mCounter = 0; + + float radius = 0.1f; + float restDistance = radius*0.55f; + int phase = NvFlexMakePhase(0, eNvFlexPhaseSelfCollide | eNvFlexPhaseFluid); + + CreateParticleGrid(Vec3(0.0f, 0.2f, -1.0f), 16, 64, 16, restDistance, Vec3(0.0f), 1.0f, false, 0.0f, phase, 0.005f); + + g_params.radius = radius; + + g_params.fluid = true; + g_params.numIterations = 3; + g_params.vorticityConfinement = 0.0f; + g_params.fluidRestDistance = restDistance; + g_params.anisotropyScale = 2.5f / radius; + g_params.smoothing = 0.5f; + g_params.relaxationFactor = 1.f; + g_params.restitution = 0.0f; + g_params.collisionDistance = 0.01f; + + g_params.dynamicFriction = 0.25f; + g_params.viscosity = 0.5f; + g_params.cohesion = 0.1f; + g_params.adhesion = 0.0f; + g_params.surfaceTension = surfaceTension; + + g_params.gravity[1] = 0.0f; + + g_numExtraParticles = 64 * 1024; + + g_emitters[0].mEnabled = true; + g_emitters[0].mSpeed = (g_params.fluidRestDistance*2.f / g_dt); + + g_lightDistance *= 2.0f; + + // draw options + g_drawEllipsoids = true; + } + + void Update() + { + if (g_frame == 300) + g_params.gravity[1] = -9.8f; + } + + int mCounter; + float surfaceTension; +}; diff --git a/demo/scenes/tearing.h b/demo/scenes/tearing.h new file mode 100644 index 0000000..c36ca7a --- /dev/null +++ b/demo/scenes/tearing.h @@ -0,0 +1,132 @@ + +class Tearing : public Scene +{ +public: + + Tearing(const char* name) : Scene(name) {} + + ~Tearing() + { + NvFlexExtDestroyTearingCloth(mCloth); + } + + void Initialize() + { + Mesh* mesh = ImportMesh(GetFilePathByPlatform("../../data/irregular_plane.obj").c_str()); + mesh->Transform(RotationMatrix(kPi, Vec3(0.0f, 1.0f, 0.0f))*RotationMatrix(kPi*0.5f, Vec3(1.0f, 0.0f, 0.0f))*ScaleMatrix(2.0f)); + + Vec3 lower, upper; + mesh->GetBounds(lower, upper); + + float radius = 0.065f; + int phase = NvFlexMakePhase(0, eNvFlexPhaseSelfCollide | eNvFlexPhaseSelfCollideFilter); + + for (size_t i = 0; i < mesh->GetNumVertices(); ++i) + { + Vec3 p = Vec3(mesh->m_positions[i]); + + float invMass = 1.0f; + + if (p.y == upper.y) + invMass = 0.0f; + + p += Vec3(0.0f, 1.5f, 0.0f); + + g_buffers->positions.push_back(Vec4(p.x, p.y, p.z, invMass)); + g_buffers->velocities.push_back(0.0f); + g_buffers->phases.push_back(phase); + } + + g_numExtraParticles = 1000; + + mCloth = NvFlexExtCreateTearingClothFromMesh((float*)&g_buffers->positions[0], int(g_buffers->positions.size()), int(g_buffers->positions.size()) + g_numExtraParticles, (int*)&mesh->m_indices[0], mesh->GetNumFaces(), 0.8f, 0.8f, 0.0f); + + g_buffers->triangles.assign((int*)&mesh->m_indices[0], mesh->m_indices.size()); + g_buffers->triangleNormals.resize(mesh->GetNumFaces(), Vec3(0.0f, 0.0f, 1.0f)); + + g_buffers->springIndices.assign(mCloth->springIndices, mCloth->numSprings * 2); + g_buffers->springStiffness.assign(mCloth->springCoefficients, mCloth->numSprings); + g_buffers->springLengths.assign(mCloth->springRestLengths, mCloth->numSprings); + + g_params.radius = radius; + g_params.dynamicFriction = 0.025f; + g_params.dissipation = 0.0f; + g_params.numIterations = 16; + g_params.particleCollisionMargin = g_params.radius*0.05f; + g_params.relaxationFactor = 1.0f; + g_params.drag = 0.03f; + + g_params.relaxationMode = eNvFlexRelaxationGlobal; + g_params.relaxationFactor = 0.35f; + + g_numSubsteps = 2; + + g_pause = false; + + // draw options + g_drawPoints = false; + } + + void Update() + { + g_params.wind[0] = 0.1f; + g_params.wind[1] = 0.1f; + g_params.wind[2] = -0.2f; + g_windStrength = 6.0f; + + const float maxStrain = 3.0f; + 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(mCloth->particles, &g_buffers->positions[0], sizeof(Vec4)*g_buffers->positions.size()); + + NvFlexExtTearClothMesh(mCloth, maxStrain, 4, particleCopies, &numParticleCopies, maxCopies, triangleEdits, &numTriangleEdits, maxEdits); + + // copy particles + for (int i = 0; i < numParticleCopies; ++i) + { + const int srcIndex = particleCopies[i].srcIndex; + const int destIndex = particleCopies[i].destIndex; + + g_buffers->positions[destIndex] = Vec4(Vec3(g_buffers->positions[srcIndex]), 1.0f); // override mass because picked particle has inf. mass + g_buffers->restPositions[destIndex] = g_buffers->restPositions[srcIndex]; + g_buffers->velocities[destIndex] = g_buffers->velocities[srcIndex]; + g_buffers->phases[destIndex] = g_buffers->phases[srcIndex]; + + g_buffers->activeIndices.push_back(destIndex); + } + + // apply triangle modifications to index buffer + for (int i = 0; i < numTriangleEdits; ++i) + { + const int index = triangleEdits[i].triIndex; + const int newValue = triangleEdits[i].newParticleIndex; + + g_buffers->triangles[index] = newValue; + } + + mCloth->numParticles += numParticleCopies; + + // update constraints + g_buffers->springIndices.assign(mCloth->springIndices, mCloth->numSprings * 2); + g_buffers->springStiffness.assign(mCloth->springCoefficients, mCloth->numSprings); + g_buffers->springLengths.assign(mCloth->springRestLengths, mCloth->numSprings); + } + + virtual void Sync() + { + // update solver data not already updated in the main loop + 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); + NvFlexSetRestParticles(g_flex, g_buffers->restPositions.buffer, g_buffers->restPositions.size()); + } + + NvFlexExtAsset* mCloth; +};
\ No newline at end of file diff --git a/demo/scenes/thinbox.h b/demo/scenes/thinbox.h new file mode 100644 index 0000000..a77f258 --- /dev/null +++ b/demo/scenes/thinbox.h @@ -0,0 +1,66 @@ + + +class ThinBox : public Scene +{ +public: + + ThinBox(const char* name) : Scene(name) {} + + int base; + int width; + int height; + int depth; + + virtual void Initialize() + { + float radius = 0.03f; + + width = 16; + height = 8; + depth = 8; + + base = 4; + + float sep = radius; + + CreateParticleGrid(Vec3(0.0f, radius, 0.0f), width, height, depth, sep, Vec3(0.0f), 1.0f, false, 0.0f, NvFlexMakePhase(0, eNvFlexPhaseSelfCollide), 0.0f); + + Vec3 upper; + Vec3 lower; + GetParticleBounds(lower, upper); + lower -= Vec3(radius*0.5f); + upper += Vec3(radius*0.5f); + + Vec3 center = 0.5f*(upper + lower); + + float width = (upper - lower).x*0.5f; + float depth = (upper - lower).z*0.5f; + float edge = 0.0075f*0.5f; + float height = 8 * radius; + + AddBox(Vec3(edge, height, depth), center + Vec3(-width, height / 2, 0.0f)); + AddBox(Vec3(edge, height, depth), center + Vec3(width, height / 2, 0.0f)); + AddBox(Vec3(width - edge, height, edge), center + Vec3(0.0f, height / 2, (depth - edge))); + AddBox(Vec3(width - edge, height, edge), center + Vec3(0.0f, height / 2, -(depth - edge))); + AddBox(Vec3(width, edge, depth), Vec3(center.x, lower.y, center.z)); + + g_params.gravity[1] = -9.f; + g_params.radius = radius; + g_params.dynamicFriction = 0.0f; + g_params.fluid = false; + g_params.numIterations = 5; + g_params.numPlanes = 1; + g_params.restitution = 0.0f; + g_params.collisionDistance = radius; + g_params.particleCollisionMargin = radius*0.5f; + + g_params.relaxationFactor = 0.0f; + g_numSubsteps = 2; + + g_lightDistance *= 0.85f; + + // draw options + g_drawPoints = true; + g_warmup = false; + } +};
\ No newline at end of file diff --git a/demo/scenes/trianglecollision.h b/demo/scenes/trianglecollision.h new file mode 100644 index 0000000..65a7824 --- /dev/null +++ b/demo/scenes/trianglecollision.h @@ -0,0 +1,47 @@ + +class TriangleCollision : public Scene +{ +public: + + TriangleCollision(const char* name) : Scene(name) {} + + void Initialize() + { + float radius = 0.05f; + CreateParticleGrid(Vec3(0.4f, 1.0f + radius*0.5f, 0.1f), 10, 5, 10, radius, Vec3(0.0f), 1.0f, false, 0.0f, NvFlexMakePhase(0, eNvFlexPhaseSelfCollide), 0.0f); + + Mesh* disc = CreateDiscMesh(1.0f, 4); + + // create shallow bowl + disc->m_positions[0].y -= 0.5f; + disc->CalculateNormals(); + + + NvFlexTriangleMeshId mesh1 = CreateTriangleMesh(disc); + AddTriangleMesh(mesh1, Vec3(0.0f, 0.5f, 0.0f), Quat(), Vec3(1.0f, 0.5f, 1.0f)); + AddTriangleMesh(mesh1, Vec3(1.0f, 0.5f, 1.0f), Quat(), Vec3(1.0f, 0.5f, 1.0f)); + + NvFlexTriangleMeshId mesh2 = CreateTriangleMesh(disc); + AddTriangleMesh(mesh2, Vec3(-1.0f, 0.5f, 1.0f), Quat(), Vec3(1.0f, 0.5f, 1.0f)); + AddTriangleMesh(mesh2, Vec3(1.0f, 0.5f, -1.0f), Quat(), Vec3(1.0f, 1.0f, 1.0f)); + + NvFlexTriangleMeshId mesh3 = CreateTriangleMesh(disc); + AddTriangleMesh(mesh3, Vec3(-1.0f, 0.5f, -1.0f), Quat(), Vec3(1.0f, 0.25f, 1.0f)); + + + delete disc; + + g_params.radius = radius; + g_params.dynamicFriction = 0.025f; + g_params.dissipation = 0.0f; + g_params.restitution = 0.0; + g_params.numIterations = 4; + g_params.particleCollisionMargin = g_params.radius*0.05f; + + g_numSubsteps = 1; + + // draw options + g_drawPoints = true; + } + +}; diff --git a/demo/scenes/triggervolume.h b/demo/scenes/triggervolume.h new file mode 100644 index 0000000..0e4c1a4 --- /dev/null +++ b/demo/scenes/triggervolume.h @@ -0,0 +1,81 @@ + + + +class TriggerVolume : public Scene +{ +public: + + TriggerVolume(const char* name) : Scene(name) {} + + void Initialize() + { + float radius = 0.05f; + CreateParticleGrid(Vec3(1.75, 2.0, -0.25), 10, 5, 10, radius, Vec3(0.0f), 1.0f, false, 0.0f, NvFlexMakePhase(0, eNvFlexPhaseSelfCollide), 0.0f); + + g_numExtraParticles = 10000; + + // regular box + AddBox(Vec3(0.5), Vec3(0.0, 0.5, 0.0)); + + // trigger box + AddBox(Vec3(0.5), Vec3(2.0f, 0.5, 0.0)); + g_buffers->shapeFlags[1] |= eNvFlexShapeFlagTrigger; + + g_params.radius = radius; + g_params.dynamicFriction = 0.025f; + g_params.dissipation = 0.0f; + g_params.restitution = 0.0; + g_params.numIterations = 4; + g_params.particleCollisionMargin = g_params.radius*0.05f; + + g_numSubsteps = 1; + + // draw options + g_drawPoints = true; + + g_emitters[0].mEnabled = true; + } + + virtual void Update() + { + const int maxContactsPerParticle = 6; + + NvFlexVector<Vec4> contactPlanes(g_flexLib,g_buffers->positions.size()*maxContactsPerParticle); + NvFlexVector<Vec4> contactVelocities(g_flexLib, g_buffers->positions.size()*maxContactsPerParticle); + NvFlexVector<int> contactIndices(g_flexLib, g_buffers->positions.size()); + NvFlexVector<unsigned int> contactCounts(g_flexLib, g_buffers->positions.size()); + + NvFlexGetContacts(g_flex, contactPlanes.buffer, contactVelocities.buffer, contactIndices.buffer, contactCounts.buffer); + + contactPlanes.map(); + contactVelocities.map(); + contactIndices.map(); + contactCounts.map(); + + int activeCount = NvFlexGetActiveCount(g_flex); + + for (int i = 0; i < activeCount; ++i) + { + const int contactIndex = contactIndices[i]; + const unsigned int count = contactCounts[contactIndex]; + + for (unsigned int c = 0; c < count; ++c) + { + Vec4 velocity = contactVelocities[contactIndex*maxContactsPerParticle + c]; + + const int shapeId = int(velocity.w); + + // detect when particle intersects the trigger + // volume and teleport it over to the other box + if (shapeId == 1) + { + Vec3 pos = Vec3(Randf(-0.5f, 0.5f), 1.0f, Randf(-0.5f, 0.5f)); + + g_buffers->positions[i] = Vec4(pos, 1.0f); + g_buffers->velocities[i] = 0.0f; + } + } + } + } + +};
\ No newline at end of file diff --git a/demo/scenes/viscosity.h b/demo/scenes/viscosity.h new file mode 100644 index 0000000..0615855 --- /dev/null +++ b/demo/scenes/viscosity.h @@ -0,0 +1,79 @@ + +class Viscosity : public Scene +{ +public: + + Viscosity(const char* name, float viscosity = 1.0f, float dissipation = 0.0f) : Scene(name), viscosity(viscosity), dissipation(dissipation) {} + + virtual void Initialize() + { + float radius = 0.1f; + float restDistance = radius*0.5f; + + g_params.radius = radius; + + g_params.fluid = true; + g_params.numIterations = 3; + g_params.vorticityConfinement = 0.0f; + g_params.fluidRestDistance = restDistance; + g_params.anisotropyScale = 3.0f / radius; + g_params.smoothing = 0.35f; + g_params.relaxationFactor = 1.f; + g_params.restitution = 0.0f; + g_params.collisionDistance = 0.00125f; + g_params.shapeCollisionMargin = g_params.collisionDistance*0.25f; + g_params.dissipation = dissipation; + + g_params.gravity[1] *= 2.0f; + + g_fluidColor = Vec4(1.0f, 1.0f, 1.0f, 0.0f); + g_meshColor = Vec3(0.7f, 0.8f, 0.9f)*0.7f; + + g_params.dynamicFriction = 1.0f; + g_params.staticFriction = 0.0f; + g_params.viscosity = 20.0f + 20.0f*viscosity; + g_params.adhesion = 0.1f*viscosity; + g_params.cohesion = 0.05f*viscosity; + g_params.surfaceTension = 0.0f; + + const float shapeSize = 2.0f; + const Vec3 shapeLower = Vec3(-shapeSize*0.5f, 0.0f, -shapeSize*0.5f); + const Vec3 shapeUpper = shapeLower + Vec3(shapeSize); + const Vec3 shapeCenter = (shapeLower + shapeUpper)*0.5f; + + NvFlexDistanceFieldId sdf = CreateSDF(GetFilePathByPlatform("../../data/bunny.ply").c_str(), 128); + AddSDF(sdf, shapeLower, Quat(), shapeSize); + + float emitterSize = 1.f; + + Emitter e; + e.mEnabled = true; + e.mWidth = int(emitterSize / restDistance); + e.mPos = Vec3(shapeCenter.x - 0.2f, shapeUpper.y + 0.75f, shapeCenter.z); + e.mDir = Vec3(0.0f, -1.0f, 0.0f); + e.mRight = Vec3(1.0f, 0.0f, 0.0f); + e.mSpeed = (restDistance*2.f / g_dt); + + g_sceneUpper.z = 5.0f; + + g_emitters.push_back(e); + + g_numExtraParticles = 64 * 1024; + + g_lightDistance *= 2.5f; + + // draw options + g_drawEllipsoids = true; + + g_emit = true; + g_pause = false; + } + + virtual void DoGui() + { + imguiSlider("Emitter Pos", &g_emitters.back().mPos.x, -1.0f, 1.0f, 0.001f); + } + + float viscosity; + float dissipation; +};
\ No newline at end of file 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; +}; |