Sign in to follow this  
NickGravelyn

Applying Simple Joints To 2D Particles

Recommended Posts

I've got my particle system nailed down and I wanted to start working on joints. My first plan was to simply make a joint that kept two particles at a set distance apart. My implementation seems logical, but the joint behaves very strange. I'm using two particles with equal mass, but one always seems to swing around the other during collisions.
public override void Update(float dt)
		{
			Vector2 d = p1.position - p2.position;

			if (d.LengthSquared() != (length * length))
			{
				//calculate each particle's "influence" on the joint
				float p1Influence = p1.mass;
				float p2Influence = p2.mass;

				//figure out the total "influence" the joint has
				float totalInfluence = p1Influence + p2Influence;

				//get the percentage of influence for both particles.
				//notice the reversal of the particle influence for
				//the percentage. this percentage is the percentage
				//of the correction distance each particle must move.
				//hence the particle with the highest influence, has the
				//lowest percentage it must move.
				float p1Percentage = p2Influence / totalInfluence;
				float p2Percentage = p1Influence / totalInfluence;

				//get the correction distance and vector
				float correctionDistance = d.Length() - length;
				Vector2 correctionVector = p1.position - p2.position;
				correctionVector.Normalize();

				//move the particles
				p1.position -= correctionVector * (p1Percentage * correctionDistance);
				p2.position += correctionVector * (p2Percentage * correctionDistance);
			}
		}

Share this post


Link to post
Share on other sites
So I tried again. I used the f=ma and p=v/t equations to come to equation f=pm/t2 (t-squared). Using this I applied it to my joint update method:

public override void Update(float dt)
{
Vector2 d = p1.position - p2.position;

if (d.LengthSquared() != (length * length))
{
//calculate each particle's "influence" on the joint
float p1Influence = p1.mass;
float p2Influence = p2.mass;

//figure out the total "influence" the joint has
float totalInfluence = p1Influence + p2Influence;

//get the percentage of influence for both particles.
//notice the reversal of the particle influence for
//the percentage. this percentage is the percentage
//of the correction distance each particle must move.
//hence the particle with the highest influence, has the
//lowest percentage it must move.
float p1Percentage = p2Influence / totalInfluence;
float p2Percentage = p1Influence / totalInfluence;

//get the correction distance and vector
float correctionDistance = d.Length() - length;
Vector2 correctionVector = p1.position - p2.position;
correctionVector.Normalize();

//apply the forces
p1.ApplyForce(-(correctionVector * (correctionDistance * p1Percentage)) * p1.mass / (dt * dt));
p2.ApplyForce(correctionVector * (correctionDistance * p2Percentage) * p2.mass / (dt * dt));
}
}



It works to a degree. It looks better than it did before, but my particles now never come to rest and actually appear to shiver. In my main physics code, I do a loop three times that first updates all the particles, checks for terrain collision, and then handles the joint problems. Any ideas where I'm going wrong?

Edit:
I've combined my methods and compensated for the fact that this is called three times per frame by making the last part into this:

p1.position -= correctionVector * (p1Percentage * correctionDistance);
p2.position += correctionVector * (p2Percentage * correctionDistance);
p1.ApplyForce(-(correctionVector * (correctionDistance * p1Percentage)) * p1.mass / (dt * dt) / 3f);
p2.ApplyForce(correctionVector * (correctionDistance * p2Percentage) * p2.mass / (dt * dt) / 3f);

So now my joints act correctly, but it still seems to never want to completely come to rest. I thought about using a velocity cutoff in my particles, but I couldn't implement it properly. My particles usually reach a point where they are (visually) at rest, but when I use joints, I can clearly see it shivering.

[Edited by - NickGravelyn on March 19, 2007 5:39:08 PM]

Share this post


Link to post
Share on other sites
Well,
if (d.LengthSquared() != (length * length))
is never going to return false, so they are never going to settle. You need some kind of epsilon range if you want them to actually stop.

You might also want to look at verlet integration for this kind of thing. For example, see my blob code.

Share this post


Link to post
Share on other sites

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