Sign in to follow this  

Taught rope

This topic is 3102 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
Share on other sites
Quote:
Original post by gpu_fem
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.


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 this post


Link to post
Share on other sites
Quote:
Original post by gpu_fem
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.


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

Cheers,
Mike

Share this post


Link to post
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 this post


Link to post
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 this post


Link to post
Share on other sites
Before the thread dies completely...

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:

http://www.fun-motion.com/forums/showthread.php?t=3596

Cheers,
Mike

Share this post


Link to post
Share on other sites

This topic is 3102 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this