Sign in to follow this  
Skelit

Collision response with a particle and the ground.

Recommended Posts

I'm making a physics engine based off of the one from the nehe tutorials, and I'm trying to get a particle to stop when it hits the ground, instead of falling through it. I found this site: http://www.essentialmath.com/tutorial.htm Which has this explaination about it all: http://www.essentialmath.com/CollisionResponse.pps And I understand it all, but when I code it, my particle just continues to fall through the ground. It slows down when it hits it, but it just keeps going. Here is what I have:
if ( pos.y < 200){ // 200 is an arbitrary point for the ground. 

  Vector3D v = vel;

  Vector3D n(0, m*gravity, 0);
  float impulse = -(1+0.5); //0.5 is the coefficient of restitution
  impulse *= v.dot(n);
  impulse /= n.dot(n)*(1/m);

  n *= impulse/m;
  vel = v + n;
}

/*
the Vector3D class is the same as the tutorial gives you, except i added a dot function to use for the dot product of two vectors. heres the code for that:
 */

float dot(Vector3D d) {
  return x*d.x + y*d.y + z*d.z;
}


Could someone help me figure out what I'm doing wrong?

Share this post


Link to post
Share on other sites
I think you just miss :
y = 200.0f;

and / or that test :
if(v.dot(n) < 0.0f) return false;

so you your particle don't get stuck when it's exiting the collision plane.

I'd try this.


// 200 is an arbitrary point for the ground.
if ( pos.y < 200.0f)
{
pos.y = 200.0f; // put particle on collision plane

// arbitrary normal of collision.
Vector3D n(0, m*gravity, 0);

float vn = vel.dot(n);
float nn = n.dot(n);

// particle not exiting the plane
if(vn > 0.0f) ///// or should it be (vn < 0.0f?!?). try either
{
// 0.5 is the coefficient of restitution.
// impulse magnitude (scaled by the inverse length of normal).
float impulse = -(1.0f + 0.5f) * vn / (nn * 1/m);

// impulse vector.
Vector j = impulse * n;

// apply impulse
vel += (j / m);
}
}

Share this post


Link to post
Share on other sites
Quote:
Original post by oliii
I think you just miss :
y = 200.0f;

and / or that test :
if(v.dot(n) < 0.0f) return false;

so you your particle don't get stuck when it's exiting the collision plane.

I'd try this.


// 200 is an arbitrary point for the ground.
if ( pos.y < 200.0f)
{
pos.y = 200.0f; // put particle on collision plane

// arbitrary normal of collision.
Vector3D n(0, m*gravity, 0);

float vn = vel.dot(n);
float nn = n.dot(n);

// particle not exiting the plane
if(vn > 0.0f) ///// or should it be (vn < 0.0f?!?). try either
{
// 0.5 is the coefficient of restitution.
// impulse magnitude (scaled by the inverse length of normal).
float impulse = -(1.0f + 0.5f) * vn / (nn * 1/m);

// impulse vector.
Vector j = impulse * n;

// apply impulse
vel += (j / m);
}
}


Ah, thank you! I just did that and now it works perfectly! I did have to change it to if ( vn < 0.0f ) though. Thank you so much for your help, it's so cool seeing my little dot bounce realisticly when it touches the ground! :D

Quote:
Original post by Numsgil
"n" usually denotes normal, but you seem to have it represent acceleration. I don't know if that's necessarily your problem, but it seems odd to me.


When on object is just sitting on the ground and is at rest, isn't the normal mass*gravity? I thought it'd be the same for when a falling object collides with the ground. Since it's working right now though, I guess that normal does work.

Share this post


Link to post
Share on other sites
In general, A collision normal doesn't have anything to do with which way the gravity is, or how strong it is. It just so happens that your hard-coded collision plane is aligned with your gravity and will be always point in the direction of (0, 1, 0).

If you collide with an inclined plane, the normal would be different (perpendicular to the plane), and your particle will 'deflect' and bounce around.

If your normal changes, your collision test (y < 200.0f) will not be valid anymore.

say you have a inclined plane with normal (0.1f, 1.0f, 0.1f), and an origin Vector(2.0f, -2.0f, -1.0f) (the origin is basically any point that would be on the plane).

your test would become.


//------------------------------------------
// n : plane normal
// o : an arbitrary point on the plane.
//------------------------------------------
float n2 = n.dot(n);

// distance of particle from plane (scaled by the plane normal length).
float dist = (pos - o).dot(n);

// particle under the plane
if(dist < 0.0f)
{
// move particle on surface of plane.
pos -= n * (dist / n2);

// impact speed
float vn = vel.dot(n);

// particle is entering the plane.
if(vn < 0.0f)
{
////// ect.......
////// .......
////// ..

vel += (j / m);
}
}

Share this post


Link to post
Share on other sites
Quote:
Original post by oliii
In general, A collision normal doesn't have anything to do with which way the gravity is, or how strong it is. It just so happens that your hard-coded collision plane is aligned with your gravity and will be always point in the direction of (0, 1, 0).

If you collide with an inclined plane, the normal would be different (perpendicular to the plane), and your particle will 'deflect' and bounce around.

If your normal changes, your collision test (y < 200.0f) will not be valid anymore.


Yeah, my normal with the ground was just for testing to get started. :)

How could a find a normal for any surface that I come in contact with though? You don't just decide one for each plane, do you? Surely there has to be a way to calculate it for any plane at any angle, but how?

Share this post


Link to post
Share on other sites
It doesn't matter what angle the particle hits the plane at; the normal is uniquely determined from the surface being hit. In the case you're hitting a line segment, the normal is perpindicular to that. Let r = p1 - p0, where p1 and p0 are points on your line segment. Then let n = (-ry, rx). Often times if you're careful with the math you don't have to normalize it, though since you're pretty new to the math I'd recommend normalizing it just as a sanity check.

Share this post


Link to post
Share on other sites
Well, probably the most convenient way to describe a plane would be just with a point on the plane and its normal vector (as oliii showed); using angles would be much more cumbersome in this case.

For a surface such as a triangle where you know the vertices, you can calculate the normal by taking the cross product of the vectors representing two of its sides. For example, for a triangle with vertices A, B, C, you can calculate the normal by taking the cross product of the vector from A to B and the vector from B to C (and usually normalizing the result). Of course, the direction of the normal depends on the direction of the vectors and the order of the cross product operation.

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