Creating a cloth simulation

In this recipe we will learn how to simulate cloth by creating a grid of particles connected by springs.

Getting Ready

In this recipe, we will be using the particle system described in the recipe Creating a particle system in 2D from Chapter 5, Building Particle Systems.

We will also be using the Springs class created in the recipe Creating springs from Chapter 5, Building Particle Systems.

So, you will need to add the following files to your project:

  • Particle.h
  • ParticleSystem.h
  • Spring.h
  • Spring.cpp

How to do it…

We will create a grid of particles connected with springs to create a cloth simulation.

  1. Include the particle system file in your project by adding the following code on top of your source file:
    #include "ParticleSystem.h"
  2. Add the using statements before the application class declaration as shown in the following code:
    using namespace ci;
    using namespace ci::app;
    using namespace std;
  3. Create an instance of a ParticleSystem object and member variables to store the top corners of the grid. We will also create variables to store the number of rows and lines that make up our grid. Add the following code in your application class:
    ParticleSystem mParticleSystem;
      Vec2f mLeftCorner, 
    mRightCorner;
      intmNumRows, mNumLines;
  4. Before we start creating our particle grid, let's update and draw our particle system in our application's update and draw methods.
    Void MyApp::update(){
      mParticleSystem.update();
    }
    
    void MyApp::draw(){
      gl::clear( Color( 0, 0, 0 ) ); 
      mParticleSystem.draw();
    }
  5. In the setup method, let's initialize the grid corner positions and number of rows and lines. Add the following code at the top of the setup method:
    mLeftCorner = Vec2f( 50.0f, 50.0f );
    mRightCorner = Vec2f( getWindowWidth() - 50.0f, 50.0f );
    mNumRows = 20;
    mNumLines = 15;
  6. Calculate the distance between each particle on the grid.
    float gap = ( mRightCorner.x - mLeftCorner.x ) / ( mNumRows-1 );
  7. Let's create a grid of evenly spaced particles and add them to ParticleSystem. We'll do this by creating a nested loop where each loop index will be used to calculate the particle's position. Add the following code in the setup method:
    for( int i=0; i<mNumRows; i++ ){
    for( int j=0; j<mNumLines; j++ ){
    float x = mLeftCorner.x + ( gap * i );
    float y = mLeftCorner.y + ( gap * j );
    Particle *particle = new Particle( Vec2f( x, y ), 5.0f, 5.0f, 0.95f );
    mParticleSystem.addParticle( particle );
            }
        }
  8. Now that the particles are created, we need to connect them with springs. Let's start by connecting each particle to the one directly below it. In a nested loop, we will calculate the index of the particle in ParticleSystem and the one below it. We then create a Spring class connecting both particles using their current distance as rest and a strength value of 1.0. Add the following to the bottom of the setup method:
    for( int i=0; i<mNumRows; i++ ){
    for( int j=0; j<mNumLines-1; j++ ){
    int indexA = i * mNumLines + j;
    int indexB = i * mNumLines + j + 1;
                Particle *partA = mParticleSystem.particles[ indexA ];
                Particle *partB = mParticleSystem.particles[ indexB ];
    float rest = partA->position.distance( partB->position );
                Spring *spring = new Spring( partA, partB, rest, 1.0f );
    mParticleSystem.addSpring( spring );
            }
        }
  9. We now have a static grid made out of particles and springs. Let's add some gravity by applying a constant vertical force to each particle. Add the following code at the bottom of the update method:
    Vec2f gravity( 0.0f, 1.0f );
    for( vector<Particle*>::iterator it = mParticleSystem.particles.begin(); it != mParticleSystem.particles.end(); ++it ){
            (*it)->forces += gravity;
        }
  10. To prevent the grid from falling down, we need to make the particles at the top edges static in their initial positions, defined by mLeftCorner and mRightCorner. Add the following code to the update method:
    int topLeftIndex = 0;
    int topRightIndex = ( mNumRows-1 ) * mNumLines;
    mParticleSystem.particles[ topLeftIndex ]->position = mLeftCorner;
    mParticleSystem.particles[ topRightIndex ]->position = mRightCorner;
  11. Build and run the application; you'll see a grid of particles falling down with gravity, locked by its top corners.
    How to do it…
  12. Let's add some interactivity by allowing the user to drag particles with the mouse. Declare a Particle pointer to store the particle being dragged.
    Particle *mDragParticle;
  13. In the setup method initialize the particle to NULL.
    mDragParticle = NULL;
  14. Declare the mouseUp and mouseDown methods in the application's class declaration.
    void mouseDown( MouseEvent event );
    void mouseUp( MouseEvent event );
  15. In the implementation of the mouseDown event, we iterate the overall particles and, if a particle is under the cursor, we set mDragParticle to point to it.
    void MyApp::mouseDown( MouseEvent event ){
    for( vector<Particle*>::iterator it = mParticleSystem.particles.begin(); it != mParticleSystem.particles.end(); ++it ){
            Particle *part = *it;
            float dist = part->position.distance( event.getPos() );
    if( dist< part->radius ){
    mDragParticle = part;
    return;
            }
        }
    }
  16. In the mouseUp event we simply set mDragParticle to NULL.
    void MyApp::mouseUp( MouseEvent event ){
    mDragParticle = NULL;
    }
  17. We need to check if mDragParticle is a valid pointer and set the particle's position to the mouse cursor. Add the following code to the update method:
    if( mDragParticle != NULL ){
    mDragParticle->position = getMousePos();
        }
  18. Build and run the application. Press and drag the mouse over any particle and drag it around to see how the cloth simulation reacts.

How it works…

The cloth simulation is achieved by creating a two dimensional grid of particles and connecting them with springs. Each particle will be connected with a spring to the ones next to it and to the ones above and below it.

There's more…

The density of the grid can be changed to accommodate the user's needs. Using a grid with more particles will generate a more precise simulation but will be slower.

Change mNumLines and mNumRows to change the number of particles that make up the grid.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.227.46.69