Spring creation and force calculation

Started by
97 comments, last by Mystery 19 years, 6 months ago
Hi guys, I got confused with some rather basic stuff so will need your help here. I am trying to create 3 springs from the above structure and to calculate the spring force. However, I find that there are quite a number of ways to create them and may end up with different results and thus not consistent. E.g I can create them as 1) A - B, B - C, A - C Resultant force of A = f1 + f2 Resultant force of B = -f1 + f3 Resultant force of C = -f2 - f3 And if I create them this way: 2) B - A, B - C, A - C Resultant force of A = -f1 + f2 Resultant force of B = f1 + f3 Resultant force of C = -f2 - f3 Am I missing out something? The way I am doing the calcution is that I loop through all the springs in each timestep. And for each spring, I calculate the force, assign it to first node and the negated value of the force to the other one.
Advertisement
In the following prefix 'f' refers to a scalar quantity while 'v' refers to a vector quantity.

For every spring 'i' calculate: fF = fK * ( fLength - fRestLength ), which is positive if the spring wants to contract and negative if the spring wants to expand.

Then for every node 'j' calculate: vF[j] += fF[k] * vDirToneighbour[k], where 'k' goes through all the neighbours of the node j. Set vF[j] to zero before looping through 'k'.

That is, first calculate the force for every spring as a scalar. This scalar holds the information about whether the spring wants to contract or expand in its sign. Then for every node use this information by directing the scalar force towards the respective neighbour.

JD
Thanks JD. Does that mean what I did earlier was wrong? This is because currently my data structure is such each spring will hold the the pair of node numbers that it is connecting. I believe what you did is each node will know who its neighbours are.

Quote:Original post by JesusDesoles
In the following prefix 'f' refers to a scalar quantity while 'v' refers to a vector quantity.

For every spring 'i' calculate: fF = fK * ( fLength - fRestLength ), which is positive if the spring wants to contract and negative if the spring wants to expand.

Then for every node 'j' calculate: vF[j] += fF[k] * vDirToneighbour[k], where 'k' goes through all the neighbours of the node j. Set vF[j] to zero before looping through 'k'.

That is, first calculate the force for every spring as a scalar. This scalar holds the information about whether the spring wants to contract or expand in its sign. Then for every node use this information by directing the scalar force towards the respective neighbour.

JD
On 2nd thought, I think my results from calculation are still consistent since the computation of the force takes into consideration the relative position of the positions of the nodes.(vector)
The ways to implement a central force network are many. Obviously, the optimizations possible for different implementations vary accordingly.

As it usually is with optimizations the best way is to disregard them at first and make a working implementation which is intuitive. Then after you start optimizing you can compare the outcome of the optimization to the first model. Of course with experience the first draft can be more or less optimized already but it should always be intuitive enough for you to be sure about what is going on.

In your current implementation you have(?) a list of springs that hold references to adjacent nodes. Every spring knows its spring constant and its rest length. The spring can query the positions of the adjacent nodes and calculate the current (compressed or extended) length of itself and can therefore calculate the fF-value.

Since the spring can query the node positions it can also calculate the direction vector between the nodes which can be used to calculate the vF-value for both of the nodes. All that is left for the spring to do then is to call NodeA->AddForce( vF ) and NodeB->AddForce( -vF ). Check the signs so that I haven't messed up here.

I'm also assuming that you're using a spring class and a node class. You don't have to but I have to assume something.

Before any forces are added in respective calculation loops the forces at the nodes have to be zeroed so that you have no leftovers from the previous force-calculating loop. This may be a problem if you don't(?) have any other reference to the nodes except from the springs. Also, after all the forces are gathered at the end of the loop you have to have some way of telling to nodes to calculate their respective acceleration vA = vF/fM, velocity vV += vA * dt (Euler, replace if you're using something more sophisticated) and finally position vPos += vV * dt (Euler again). That, is for every node do something like Node->UpdatePosition().

To sum up:
1. For every node: Node->ZeroForces()
2. For every spring: Spring->UpdateForces()
3. For every node: Node->UpdatePosition( dt )
4. Render and go to 1.

One way to do this is to have a list of nodes and list of springs, where each spring has some reference to two particular nodes in the nodes list. Here the word 'list' refers to a container of your choice be it array, vector, list, or the famous 'whatever'.

I think there are many tutorials on spring networks on the web. The reason why I'm spending time here is that this is what I think people should do first. It is very rewarding to see your first dynamic spring system in action.

Questions? Shoot.

JD

EDIT: I'm not promoting/demoting the particular implementation but take a look at the spring network tutorial at Gamasutra
http://www.gamasutra.com/features/20011005/oliveira_pfv.htm

[Edited by - JesusDesoles on August 23, 2004 5:08:32 AM]
Thanks JD for taking the time to write such a detailed explanation.

Yes, the system you decribed above is exactly what I am doing now. I have a Particle(node) class and a spring class. The particle class will store stuff like its position, velocity, force, etc. Spring class will store the pair of particles, its rest length, etc.

I am using the Euler method to step through my simulation. At each timestep, I will clear the forces of each node before calculating the external force(Gravity) and internal force(Spring force). My spring force calculation is of what you have described.

This is formula I used for the force calculation:

L - spring vector
l - length of the spring (scalar)
ks - spring constant
kd - damping constant
v1,v2 - velocities of spring's ends
r - rest length of the spring

F = {ks(l-r) + kd[(v1-v2)*L]/l}*L/l

I do remember someone posting a negative sign for the force instead i.e (F = -{ks(l-r) + kd[(v1-v2)*L]/l}*L/l)
(Anyone can confirm which is the right ans)

In any case, I am still unable to get my desired result.
Quote:Original post by JesusDesoles

EDIT: I'm not promoting/demoting the particular implementation but take a look at the spring network tutorial at Gamasutra
http://www.gamasutra.com/features/20011005/oliveira_pfv.htm


I have actually read that article several times already in my attempt to solve my current problem. :)
The negative sign in Hooke F = -k * dx is for notation and basically says that for a stretched spring the force is pulling the spring back to its rest configuration. Whether you should use the negative sign or not depends on your direction vectors, i.e., implementation details. Just make sure that for a stretched spring the force added to a node is directed towards the neighbour and for a compressed spring away from the neighbour. Piece of paper and a debug session with a simple network (use a single triangle with one node initially slightly off from the rest configuration).

At first I suggest you don't do damping.

Just accumulate forces for every node. Then do Euler for the node:

vAcc = vForce/fMass
vVel += vAcc * dt
vPos += vVel * dt
[vVel *= fDamp] <-- Simple damping where fDamp is between 0.0f and 1.0f; 1.0f being no damping. Do no damping at first. Note, that you're not resetting the velocities and positions every frame, just the forces. The velocities and positions are accumulating.

How exactly are you not getting the desired result?

JD
Yes, I understand that. I did not reset the velocities and the positions, just only the forces at each timestep. I have only set a very low value for the damping constant(0.01). Anyway even I turn it off, it does not help me much.

As for my problem, it is best to explain it with the illustration below:



As you might have remembered from my other thread regarding node arrangement, I am trying to flattening the structure seen above. As I applied the gravity force to push it down the plane, I am expecting to spread out as it collides with the plane. However, what is happening in my simulation is that the points simply collapses to the plane with little "spreading" on its sides.
Note, that for vVel *= fDamp type of damping a low fDamp value means high damping.

Now, let's date your system a bit, i.e., never dump on the first compilation. It may be worth a few rounds before dumping this one and moving onto a system with bending stiffness.

What is your collision response like? Are you sure you're not clamping the nodes every time they hit the ground level? What do you do to a node once it hits the ground?

Once the system seems stable (a wrinkled(?) state for your system) what are the spring lengths? Are they equal to rest lengths or something else?

What happens if you clamp the other side of the system and let the simulation roll? That is, store the initial positions of the leftmost nodes and for every simulation step reset their positions to the initial values. Does the sheet fold down nicely, or what?

Have you checked your simulation using a simple mesh I mentioned earlier?

JD

P.S. I found you a paper for bending stiffness calculations that may be easier to understand than the basic elasticity calculations I mentioned in the other thread. See http://eg04.inrialpes.fr/Programme/ShortPresentation/PDF/short38.pdf. I've just browsed it through and to me it seems to be a long path compared to the standard matrix system but it may be easier to grasp.

[Edited by - JesusDesoles on August 24, 2004 1:48:38 AM]

This topic is closed to new replies.

Advertisement