In this recipe we will learn how to simulate cloth by creating a grid of particles connected by springs.
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
We will create a grid of particles connected with springs to create a cloth simulation.
#include "ParticleSystem.h"
using
statements before the application class declaration as shown in the following code:using namespace ci; using namespace ci::app; using namespace std;
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;
update
and draw
methods.Void MyApp::update(){ mParticleSystem.update(); } void MyApp::draw(){ gl::clear( Color( 0, 0, 0 ) ); mParticleSystem.draw(); }
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;
float gap = ( mRightCorner.x - mLeftCorner.x ) / ( mNumRows-1 );
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 ); } }
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 ); } }
update
method:Vec2f gravity( 0.0f, 1.0f ); for( vector<Particle*>::iterator it = mParticleSystem.particles.begin(); it != mParticleSystem.particles.end(); ++it ){ (*it)->forces += gravity; }
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;
Particle
pointer to store the particle being dragged.Particle *mDragParticle;
setup
method initialize the particle to NULL
.mDragParticle = NULL;
mouseUp
and mouseDown
methods in the application's class declaration.void mouseDown( MouseEvent event ); void mouseUp( MouseEvent event );
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; } } }
mouseUp
event we simply set mDragParticle
to NULL
.void MyApp::mouseUp( MouseEvent event ){ mDragParticle = NULL; }
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.227.46.69