# Taught rope

## Recommended Posts

Ok, so I have a 2D rope simulation implemented using springs, very similar to the NeHe tutorial. It works well, except it's too slack. It moves too slow and can stretch waaaay too far. I have the k of the springs as high as they can go before shit just goes crazy.. I tried increases the mass of the segments but it just slows it down until I increase k and friction again as far as it will go, but it ends up at pretty much the same as it was. I'm just wondering how I can make a really TIGHT rope. Is there some special balance I need between the mass, k and friction or do I need to add something else? Basically I want it so if the rope is of length 10 at equilibrium, it won't stretch any further than, say 14. Thanks in advance

##### Share on other sites
If you use a more stable integrator, you can make the elasticity constants as large as you want. You can effectively make them infinite.

Take a look at verlet integration, for instance as described here.

##### Share on other sites
If you actually want an unstretchable rope, you'll need to use hard constraints (with a solver), not spring forces.

##### Share on other sites
Yes. You can solve a fully constrained rope (where the lengths between rope nodes is held constant) in linear time. The idea is to solve for the tensions in the rope, and use those to find the node accelerations.

The basic idea is, if d_i is the vector from node i to node i+1, that d_i^2 = const., so that dot(d_i, a_i)+dot(v_i, v_i) = 0, where v_i = first derivative of d_i, and a_i = second derivative of d_i.

For each node, newton's laws say that m*accel_i = d_i*T_i-d_(i-1)*T_(i-1)+F_i. We can use the constraint equation from above to eliminate the accelerations, leaving only the tension (T) in our equations. For every node equation, we involve three adjacent tensions - resulting in a tridiagonal system, solved in linear time! You have to fill in the details, and be careful about B.C.s. Also, you will need to keep weak (very) springs in the system still, because round-off and integration errors will gradually erode the constraint satisfication - the springs fix this. But they don't need to be strong, so won't cause instabilities.

Even if you go with the spring approach only, don't forget at least weak dampers to destroy resonant modes (in some cases this could cause your rope to go haywire). While not required, they also make things look more realistic because real ropes have some dissipation.

##### Share on other sites
Hi ganoosh,

Here's a ~ 500 line c++ soft body simulation using damped springs and a very stable integration scheme (stabler than rk4). If you read the code carefully, you'll be able to pick out everything you need :-)

http://www.jernmager.dk/stuff/cpp/soft_body_03.zip
http://www.jernmager.dk/stuff/cpp/softbody_glut.zip

@gpu_fem

I'm very interested in learning more about this! Can you please explain this in a little more detail, or at least link to a working code sample or a paper explaining this for dummies?

Cheers,
Mike

##### Share on other sites
Quote:
 ...a very stable integration scheme (stabler than rk4)

Looking through the source... velocity verlet. For the curious.

...

I actually did a presentation on what gpu_fem is talking about I think. I have my powerpoint here. And you *may* need this plugin to see the math render right.

The basic idea is that your system of colliding (or in this case jointed) bodies is a single system of linear equations for some unknown impulses. Construct the system and solve. In general solving is a O(n^3) process, but for sparse systems the cost goes way down. And most collision "islands" only have a few contact points per body. Which makes the systems very sparse.

For instance, something like a rope (or in my presentation, Newton's Cradle) is a very simple system which forms a tridiagonal matrix, which can be solved for in linear time through various numerical methods (check out Chapter 2 of Numerical Recipes for a how-to of solving linear systems).

If you use my presentation's format, just assume that the coefficient of restitution between bodies is 0. And be sure to add another "collision" for the lateral (instead of normal) direction for contacts. Otherwise the chains in your rope would drift laterally from each other.

##### Share on other sites
Hi Numsgil,

Unfortunately I can't read your powerpoint - it doesn't go well with open office. Do you know of any relatively simple code samples illustrating these concepts availabe on the web? I would very much appreciate any help getting startet with using constraints in my physics sims.

Cheers,
Mike

##### Share on other sites
I am writing some code / writeup using hard constraints to solve for rope physics instead of springs - need a few more hours though. If there is significant interest (and novelty) I can prepare it to a full blown tutorial.

##### Share on other sites
Quote:
 Original post by gpu_femI am writing some code / writeup using hard constraints to solve for rope physics instead of springs - need a few more hours though. If there is significant interest (and novelty) I can prepare it to a full blown tutorial.

That would be awesome man. That would probably be the easiest way for me without redesigning everything I have from the ground up haha

##### Share on other sites
Quote:
 Original post by gpu_femI am writing some code / writeup using hard constraints to solve for rope physics instead of springs - need a few more hours though. If there is significant interest (and novelty) I can prepare it to a full blown tutorial.

I am very much looking forward to see this! Thanks in advance.

Cheers,
Mike

##### Share on other sites
Here is some sample code demonstrating how to compute tensions and accelerations for a chain of masses in order to keep the lengths between masses constant.

Unfortunately, it is not as stable as I had hoped. Using springs in some ways helps the stability of system because it provides a mechanism to absorb and transmit energy in a timely fashion, whereas computing tensions directly allows information to be transmitted instantaneously.

With the appropriate damping, you can make this scheme stable in most circumstances. I suspect that overall stability probably requires torsional springs and dampers in order to prevent the rope from folding up (like an accordian).

template <class T>struct ropeNode {  enum nodeType { interior, // Nodes on both sides                  fixed, // Can't move                  free_left, // node to the right, but not left                  free_right // node to the left, but not right.                 };  // What type of node is this?  nodeType myType;  // Node mass  T mass;  // Node position  T pos[3],previous_pos[3];  // Node velocity  T vel[3];  // Node acceleration  T a[3];  // External force on this node  T Fext[3];  // Total Force  T Fc[3];  };template <class T>struct ropeLink {  // tension in this link  T tension;  // Vector from node i to i+1, and relavtive velocity between node i and i+1  T d[3], ddot[3];  // Thomas storage  T cp,dp;  ropeNode<T>* pN1, *pN2;};template <class T>class rope {  // List of nodes in our rope  ropeNode<T>* myNodes;  // List of links  ropeLink<T>* myLinks;  int nNodes;  // Length between masses.  T L0;public:  // Constructor  rope(int sz, T dL, T kk) {    int i;    L0 = dL;    springK = kk;    nNodes = sz;    myNodes = new ropeNode<T>[sz];    myLinks = new ropeLink<T>[sz-1];    for (i = 0; i < nNodes-1; i++) {      myLinks[i].pN1 = &(myNodes[i]);      myLinks[i].pN2 = &(myNodes[i+1]);      myLinks[i].tension = 0.0;    }        }  // Destructor  ~rope() {    delete [] myNodes;    delete [] myLinks;  }  int numNodes() const {     return nNodes;  }  void setNode(int i,const ropeNode<T>& r,T dt) {    memcpy(myNodes+i, &r, sizeof(ropeNode<T>) );    for (int k = 0; k < 3; k++)      myNodes[i].previous_pos[k] = myNodes[i].pos[k]-myNodes[i].vel[k]*dt;  }  const ropeNode<T>& getNode(int i) const {    return myNodes[i];  }  void resolveTensions() {    int i;    T  a,b,c,d,tmp;    for (i = 0; i < nNodes-1; i++) {            a = b = c = 0.0;      d = -dot(myLinks[i].ddot, myLinks[i].ddot);      switch (myLinks[i].pN1->myType) {      case ropeNode<T>::interior:	a += dot(myLinks[i-1].d, myLinks[i].d) / myLinks[i].pN1->mass;	b -= L0*L0 / myLinks[i].pN1->mass;	d += dot(myLinks[i].d, myLinks[i].pN1->Fc) / myLinks[i].pN1->mass;	break;      case ropeNode<T>::free_left:	b -= L0*L0 / myLinks[i].pN1->mass;	d += dot(myLinks[i].d, myLinks[i].pN1->Fc) / myLinks[i].pN1->mass;	break;      default:	break;      }      switch (myLinks[i].pN2->myType) {      case ropeNode<T>::interior:	b -= L0*L0 / myLinks[i].pN2->mass;	c += dot(myLinks[i+1].d, myLinks[i].d) / myLinks[i].pN2->mass;	d -= dot(myLinks[i].d, myLinks[i].pN2->Fc) / myLinks[i].pN2->mass;		break;      case ropeNode<T>::free_right:	b -= L0*L0 / myLinks[i].pN2->mass;	d -= dot(myLinks[i].d, myLinks[i].pN2->Fc) / myLinks[i].pN2->mass;	break;      default:	break;      }      if (i == 0) {	myLinks[i].cp = c / b;	myLinks[i].dp = d / b;      } else {	tmp = 1.0 / (b - myLinks[i-1].cp*a);	myLinks[i].cp = c * tmp;	myLinks[i].dp = (d-myLinks[i-1].dp*a) * tmp;	      }    }    const float alpha = 0.0;    // Now do Thomas Back substitution    myLinks[nNodes-2].tension = myLinks[nNodes-2].dp;    for (i = nNodes-3; i >= 0; i--) {        myLinks[i].tension = myLinks[i].dp - myLinks[i+1].tension*myLinks[i].cp;    }  }  void updateAccelerations() {        int i,k;    T a[3],tmp[3];        for (i = 0; i < nNodes; i++) {            switch (myNodes[i].myType) {      case ropeNode<T>::fixed:	for (k = 0; k < 3; k++) {	  myNodes[i].a[k] = 0.0;	}	break;      case ropeNode<T>::free_left:		for (k = 0; k < 3; k++) {	  myNodes[i].a[k] = (myLinks[i].tension*myLinks[i].d[k]+myNodes[i].Fc[k])/	    myNodes[i].mass;	}	break;      case ropeNode<T>::free_right:	for (k = 0; k < 3; k++) {	  myNodes[i].a[k] = (-myLinks[i-1].tension*myLinks[i-1].d[k]+myNodes[i].Fc[k])/	    myNodes[i].mass;	}	break;      default:		for (k = 0; k < 3; k++) {	  myNodes[i].a[k] = (-myLinks[i-1].tension*myLinks[i-1].d[k]+			     myLinks[i].tension*myLinks[i].d[k]+			     myNodes[i].Fc[k])/	    myNodes[i].mass;	}	break;      }    }  }  void updateLinks() {    int i,k;    for (i = 0; i < nNodes; i++) {      for (k = 0; k < 3; k++) {	myNodes[i].Fc[k] = myNodes[i].Fext[k];      }    }    for (i = 0; i < nNodes-1; i++) {      for (k = 0; k < 3; k++) {	myLinks[i].d[k] = myNodes[i+1].pos[k] - myNodes[i].pos[k];	myLinks[i].ddot[k] = myNodes[i+1].vel[k] - myNodes[i].vel[k];      }    }  }  /* other methods omitted */};

##### Share on other sites
Hi gpu_fem,

Thanks for doing this. As for the stability issue you mention, would you still concider this qualitatively better than purely force based springs?

Oh, and is there any chance of seeing a working code example rather than just the structs? If hosting is an issue, I won't mind putting it on my webspace.

Cheers,
Mike

##### Share on other sites

Right now there's a very interesting discussion on the rigid constraint and rope-making topic over at the fun-motion forums. It's turning in to a good beginners guide on both particle - particle and (off center anchor) rigid body - rigid body constraints. Go check it out:

Cheers,
Mike

## Create an account

Register a new account

• ### Forum Statistics

• Total Topics
627701
• Total Posts
2978705

• 21
• 14
• 12
• 10
• 12