• Advertisement
Sign in to follow this  

Cloth Physics

This topic is 3730 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

I've been working on cloth physics for some time now and I can't seem to get it to look right. I'm using the spring-ball approach where I'm loading a mesh, creating a ball at everything vertice and putting a spring through all edges and one past it (as long as the dot product of those vectors are close to 1). I'm also calculating using Hooke's look and a spring constant, but I can't seem to find the right values to make it look right, the cloth seems to stretch too much and look very rubbery. I want to be able to set a maximum (and maybe minimum) percent each spring can stretch and have the cloth stay intact. Here's an image of what i'm seeing:

Share this post


Link to post
Share on other sites
Advertisement
Can you post the code you use?
I remember that there's a very good article linked from here about cloth sim, I use it sometimes ago.
The real problem with cloth sim is that it's hatd to make it "rigid". Springs/mass are great for very soft cloth, but you can't really make a "rigid" cloth without a very good integration scheme, or small time step etc. (which mean more computation time).
Increase the spring constant to get something harder, but maybe you will have to fight against oscillations, which can be decrease with damping...

I think another way to create cloth is to use the fast LSM (which was posted here 1 or 2 month ago), which could lead, I think, to very hard and stable cloth.

Share this post


Link to post
Share on other sites

void cWCloth::_Update(WcrFLOAT dt)
{
float springLen;
float extension;
sWVector3D force, acc, vel;
sWVector3D tension;

for (WuLONG i=0 ; i<m_Springs.GetNetItems() ; ++i)
{
springLen = ((*m_pCurrent)[m_Springs->m_BallIndex[0]]->m_Position -
(*m_pCurrent)[m_Springs->m_BallIndex[1]]->m_Position).Length();
extension = springLen - m_Springs->m_fNaturalLength;
m_Springs->m_fExtension = springLen / m_Springs->m_fNaturalLength;
m_Springs->m_fTension = m_fSpringConstant * extension / m_Springs->m_fNaturalLength;
}

for (WuLONG i=0 ; i<m_Balls[0].GetNetItems() ; ++i)
{
force = m_v3Gravity + m_v3ExternalForce;
vel = sWVector3D();
for (WuLONG j=0 ; j<m_Springs.GetNetItems() ; ++j)
{
// if the the current ball is the first ball of the spring
if (m_Springs[j]->m_BallIndex[0] == i)
{
tension = (*m_pCurrent)[m_Springs[j]->m_BallIndex[1]]->m_Position -
(*m_pCurrent)->m_Position;
tension.Normalize();

force += tension * m_Springs[j]->m_fTension;
/*if (m_Springs[j]->m_fExtension > m_fMaxExtension)
{
vel += (tension *
((m_Springs[j]->m_fExtension - m_fMaxExtension)
* (m_Springs[j]->m_fNaturalLength)));
} else
if (m_Springs[j]->m_fExtension < m_fMinExtension)
{
vel += (tension *
((m_Springs[j]->m_fExtension - m_fMinExtension)
* (m_Springs[j]->m_fNaturalLength)));
}*/

}
else
// if the current ball is the second ball of the spring
if (m_Springs[j]->m_BallIndex[1] == i)
{
tension = (*m_pCurrent)[m_Springs[j]->m_BallIndex[0]]->m_Position -
(*m_pCurrent)->m_Position;
tension.Normalize();

force += tension * m_Springs[j]->m_fTension;
}
}

// Calculate where the ball is going to be
acc = force / m_fBallMass;
(*m_pNext)->m_Velocity = (*m_pCurrent)->m_Velocity + (acc * dt) + vel;
(*m_pNext)->m_Velocity *= 0.75f;
if (i != 0 && i != 110)
(*m_pNext)->m_Position = (*m_pCurrent)->m_Position +
((*m_pCurrent)->m_Velocity + (*m_pNext)->m_Velocity) * dt/2.0f;

// Position the vertice at the next ball
if (i != 0 && i != 110)
m_pModel->Objects[0]->Verts->Vertex = (*m_pNext)->m_Position;
}

// Swap the lists
tWVectorList<sWBall> * temp = m_pCurrent;
m_pCurrent = m_pNext;
m_pNext = temp;
}



inside that comment, i tried to add implementation for what i was saying; having a maximum percent of extension and minimum extension. it worked a little bit, but not completely...

Share this post


Link to post
Share on other sites
If I understand correctly you apply a 0.75 damping on velocituy, this can be a too much (I think value between 0.99 and 0.95 are better, lower the system will loose to much energy).

Also I'm surprised about

m_Springs-&gt;m_fExtension = springLen / m_Springs-&gt;m_fNaturalLength;
m_Springs-&gt;m_fTension = m_fSpringConstant * extension / m_Springs-&gt;m_fNaturalLength


(maybe I just don't understand the code), but the force to apply to the particle are lineary dependant to the extension (in meter). For example if the spring has a rest length of L, and the distance between the 2 particles are X, then the force is X * constant.
The higher the constant value is, the harder the cloth will be.
You can also apply other forces, look at this article (this is the one I was talking in my previous post) :
http://www.intel.com/cd/ids/developer/asmo-na/eng/20413.htm

Share this post


Link to post
Share on other sites
Natural length is the length of the edge when i first loaded the mesh and created the balls.

The extension is the percentage from the current length divided by the natural length.

I remember now why i changed the damp from .95 to .75, because this happened

Share this post


Link to post
Share on other sites
That article is good and all; the code works and it looks like really good cloth, but the code is a bit big to try to break apart and figure out my specific problem... Is there maybe some tutorial or any other smaller projects that show how to do cloth physics?

Share this post


Link to post
Share on other sites
I would use infinitely stiff springs. Look at the Thomas Jakobsen character physics article. I think I have some code somewhere, but I achieved a very basic cloth animation demo like that very easily. Not sure about springs, especially when you need very stiff springs and you are performing a basic euler integration.

Share this post


Link to post
Share on other sites
I can second the Jakobsen recommendation, it is quite easy to come up with a stable implementation using this approach. You may also want to check out how Ageia did their cloth, it's described here (PDF). This has a nice approach for implementing bending constraints amongst other things.

Share this post


Link to post
Share on other sites
I agree with above that the method described by Jakobsen is pretty easy to implement nice looking springs.

However, I have some source codes of different springs implementation; the problem is I can't remember where I found it:) If you find out who is author, let me know.
http://data.hardwire.cz/nic/springs.zip

Share this post


Link to post
Share on other sites
Ok, I have new implementation and it works A LOT better. The cloth is now intact but it waves WAY too much... it seems that the forces are too great for it.


void cWCloth::_Update(WcrFLOAT dt)
{
float springLen;
float extension;
//sWVector3D force, acc, vel;
//sWVector3D tension;

sWVector3D Force, relative, relVel;
float springForce, damp, force;

for (WuLONG i=0 ; i<m_Balls[0].GetNetItems() ; ++i)
{
if (i != 0 && i != 110)
{
m_Balls[0]->m_Velocity += (m_v3Gravity + m_v3ExternalForce) * dt;
m_Balls[0]->m_Position += m_Balls[0]->m_Velocity * dt;
m_pModel->Objects[0]->Verts->Vertex = m_Balls[0]->m_Position;
} else
{
m_Balls[0]->m_Velocity = sWVector3D();
}
}
for (WuLONG i=0 ; i<m_Springs.GetNetItems() ; ++i)
{
Force = m_Balls[0][m_Springs->m_BallIndex[1]]->m_Position - m_Balls[0][m_Springs->m_BallIndex[0]]->m_Position;
Force.Normalize();

relative = m_Balls[0][m_Springs->m_BallIndex[0]]->m_Position - m_Balls[0][m_Springs->m_BallIndex[1]]->m_Position;
relVel = m_Balls[0][m_Springs->m_BallIndex[0]]->m_Velocity - m_Balls[0][m_Springs->m_BallIndex[1]]->m_Velocity;
springForce = m_fSpringConstant * (relative.Length() - m_Springs->m_fNaturalLength);
damp = (m_fDamping * (relative * relVel)) / m_Springs->m_fNaturalLength;
force = (springForce + damp) / 2.0f;
Force *= force;

m_Balls[0][m_Springs->m_BallIndex[0]]->m_Velocity += Force * dt;
m_Balls[0][m_Springs->m_BallIndex[1]]->m_Velocity -= Force * dt;
}



The only way it looks decent is when:
m_fDamping = 1.4f
m_fSpringContant = 2000.0f
m_v3Gravity = vector(0, -100, 0)

Share this post


Link to post
Share on other sites
I don't know if you've solved these issues yet but i've found some suspicious (read "incorrect") information in this thread.

Quote:
Original post by Pilo
...
Also I'm surprised about
*** Source Snippet Removed ***
(maybe I just don't understand the code), but the force to apply to the particle are lineary dependant to the extension (in meter). For example if the spring has a rest length of L, and the distance between the 2 particles are X, then the force is X * constant.
The higher the constant value is, the harder the cloth will be.
...


Assuming L is resting length and X is distance between particles then:

Force = -(X-L) * k;

Quote:
Original post by BloodLust666
Natural length is the length of the edge when i first loaded the mesh and created the balls.

The extension is the percentage from the current length divided by the natural length.
...


Springs do not work off a percentage, they are linear for the distance they are displaced. CurrentLength / NaturalLength is incorrect, it should be Extension = CurrentLength - NaturalLength.

Share this post


Link to post
Share on other sites
hmm... makes sense.

So what should I do with the code? what part in the code is wrong? and why does it act like really really thin silk and move so much even when i don't apply any wind.

Share this post


Link to post
Share on other sites
I would say your dampening looks suspect. I have no idea where you came up with that formula, but typically you have a spring constant "k" and an dampening constant which is a percentage of your spring constant.

For instance (fake values here):

k = 100;
d = 0.25;
naturallength = 2.0;

forcedir = (ballB.Pos - ballA.Pos).normalized;
currentlength = (ballB.Pos - ballA.Pos).length;
relvel = ballB.Vel - ballA.Vel;
displacement = currentlength - naturallength;

force = -k * displacement * forcedir;
force -= relvel * (d * k);

ballb.AddForce(force);
ballA.AddForce(-force);

Also, spring systems like these have no concept of angular constraint. it could quite possibly fold itself into a ball and still be properly solving the equation. You'll need to add some kind of angular constraint to make it more rigid. Either another set of springs that skip every other "ball", or some kind of true angular constraing that compares the force dir of two apposing springs and add's a torque if they get too close to each other (high dot product).

Share this post


Link to post
Share on other sites
ohh, ok, so the damping is related to the relative velocity of the two particles in the cloth? Why is the relVel scaled to the springconstant * damp? that's the only line i don't understand

confirming... k is the springconstant and d is damp, right?

Share this post


Link to post
Share on other sites
It dosnt need to be, d can be a completely independant constant. The reason I prefer to have dampening dependant on the spring constant is so that if I want to increase the spring constant, the dampening automagically increases with it. That way I only need to tweak one value to get stiffer springs (the k) and the other one follows.

The alternative equivalent code would look like this:

k = 100;
d = 25;
naturallength = 2.0;

...

force = -k * displacement * forcedir;
force -= relvel * d;

Share this post


Link to post
Share on other sites
THERE we go! that one worked! thanks a bunch! :)

Here's what I ended up doing:


void cWCloth::_Update(WcrFLOAT dt)
{
sWVector3D Force, relative, relVel;
float extension;

for (WuLONG i=0 ; i<m_Balls.GetNetItems() ; ++i)
{
// Testing code, hold two corners so they don't move
if (i != 0 && i != 110)
{
m_Balls->m_Velocity += (m_v3Gravity + m_v3ExternalForce) * dt;
m_Balls->m_Position += m_Balls->m_Velocity * dt;
m_pModel->Objects[0]->Verts->Vertex = m_Balls->m_Position;
} else
{
// If this is a 'held corner' zero it's velocity
m_Balls->m_Velocity = sWVector3D();
}
}
for (WuLONG i=0 ; i<m_Springs.GetNetItems() ; ++i)
{
Force = m_Balls[m_Springs->m_BallIndex[1]]->m_Position - m_Balls[m_Springs->m_BallIndex[0]]->m_Position;
Force.Normalize();

relative = m_Balls[m_Springs->m_BallIndex[0]]->m_Position - m_Balls[m_Springs->m_BallIndex[1]]->m_Position;
relVel = m_Balls[m_Springs->m_BallIndex[0]]->m_Velocity - m_Balls[m_Springs->m_BallIndex[1]]->m_Velocity;

extension = relative.Length() - m_Springs->m_fNaturalLength;

Force *= m_fSpringConstant * extension;
Force -= relVel * m_fDamping;

m_Balls[m_Springs->m_BallIndex[0]]->m_Velocity += Force * dt;
m_Balls[m_Springs->m_BallIndex[1]]->m_Velocity -= Force * dt;
}
}

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement