4
\$\begingroup\$

I'm really struggling to get a strong grasp on how I should be handling collision response in a game engine I'm building around a 3D ball physics concept. Think Monkey Ball as an example of the type of gameplay.

I am currently using sphere-to-sphere broad phase, then AABB to OBB testing (the final test I am using right now is one that checks if one of the 8 OBB points crosses the planes of the object it is testing against). This seems to work pretty well, and I am getting back:

Plane that object is colliding against (with a point on the plane, the plane's normal, and the exact point of intersection.

I've tried what feels like dozens of different high-level strategies for handling these collisions, without any real success. I think my biggest problem is understanding how to handle collisions against walls in the x-y axes (left/right, front/back), which I want to have elasticity, and the ground (z-axis) where I want an elastic reaction if the ball drops down, but then for it to eventually normalize and be kept "on the ground" (not go into the ground, but also not continue bouncing). Without kluging something together, I'm positive there is a good way to handle this, my theories just aren't getting me all the way there.

For physics modeling and movement, I am trying to use a Euler based setup with each object maintaining a position (and destination position prior to collision detection), a velocity (which is added onto the position to determine the destination position), and an acceleration (which I use to store any player input being put on the ball, as well as gravity in the z coord).

Starting from when I detect a collision, what is a good way to approach the response to get the expected behavior in all cases?

Thanks in advance to anyone taking the time to assist... I am grateful for any pointers, and happy to post any additional info or code if it is useful.

UPDATE

Based on Steve H's and eBusiness' responses below, I have adapted my collision response to what makes a lot more sense now. It was close to right before, but I didn't have all the right pieces together at the right time! I have one problem left to solve, and that is what is causing the floor collision to hit every frame. Here's the collision response code I have now for the ball, then I'll describe the last bit I'm still struggling to understand.

// if we are moving in the direction of the plane (against the normal)...
if (m_velocity.dot(intersection.plane.normal) <= 0.0f)
{
    float dampeningForce = 1.8f; // eventually create this value based on mass and acceleration

    // Calculate the projection velocity
    PVRTVec3 actingVelocity = m_velocity.project(intersection.plane.normal);

    m_velocity -= actingVelocity * dampeningForce;
}
// Clamp z-velocity to zero if we are within a certain threshold
// -- NOTE: this was an experimental idea I had to solve the "jitter" bug I'll describe below
float diff = 0.2f - abs(m_velocity.z);
if (diff > 0.0f && diff <=  0.2f)
{
    m_velocity.z = 0.0f;
}

// Take this object to its new destination position based on...
// -- our pre-collision position + vector to the collision point + our new velocity after collision * time
// -- remaining after the collision to finish the movement
m_destPosition = m_position + intersection.diff + (m_velocity * intersection.tRemaining * GAMESTATE->dt);

The above snippet is run after a collision is detected on the ball (collider) with a collidee (floor in this case). With a dampening force of 1.8f, the ball's reflected "upward" velocity will eventually be overcome by gravity, so the ball will essentially be stuck on the floor. THIS is the problem I have now... the collision code is running every frame (since the ball's z-velocity is constantly pushing it a collision with the floor below it). The ball is not technically stuck, I can move it around still, but the movement is really goofy because the velocity and position keep getting affected adversely by the above snippet.

I was experimenting with an idea to clamp the z-velocity to zero if it was "close to zero", but this didn't do what I think... probably because the very next frame the ball gets a new gravity acceleration applied to its velocity regardless (which I think is good, right?).

Collisions with walls are as they used to be and work very well. It's just this last bit of "stickiness" to deal with. The camera is constantly jittering up and down by extremely small fractions too when the ball is "at rest".

I'll keep playing with it... I like puzzles like this, especially when I think I'm close. Any final ideas on what I could be doing wrong here?

UPDATE 2

Good news - I discovered I should be subtracting the intersection.diff from the m_position (position prior to collision). The intersection.diff is my calculation of the difference in the vector of position to destPosition from the intersection point to the position. In this case, adding it was causing my ball to always go "up" just a little bit, causing the jitter. By subtracting it, and moving that clamper for the velocity.z when close to zero to being above the dot product (and changing the test from <= 0 to < 0), I now have the following:

// Clamp z-velocity to zero if we are within a certain threshold
float diff = 0.2f - abs(m_velocity.z);
if (diff > 0.0f && diff <=  0.2f)
{
    m_velocity.z = 0.0f;
}

// if we are moving in the direction of the plane (against the normal)...
float dotprod = m_velocity.dot(intersection.plane.normal);
if (dotprod < 0.0f)
{
    float dampeningForce = 1.8f; // eventually create this value based on mass and acceleration?

    // Calculate the projection velocity
    PVRTVec3 actingVelocity = m_velocity.project(intersection.plane.normal);

    m_velocity -= actingVelocity * dampeningForce;
}

// Take this object to its new destination position based on...
// -- our pre-collision position + vector to the collision point + our new velocity after collision * time
// -- remaining after the collision to finish the movement
m_destPosition = m_position - intersection.diff + (m_velocity * intersection.tRemaining * GAMESTATE->dt);
UpdateWorldMatrix(m_destWorldMatrix, m_destOBB, m_destPosition, false);

This is MUCH better. No jitter, and the ball now "rests" at the floor, while still bouncing off the floor and walls. The ONLY thing left is that the ball is now virtually "stuck". He can move but at a much slower rate, likely because the else of my dot product test is only letting the ball move at a rate multiplied against the tRemaining... I think this is a better solution than I had previously, but still somehow not the right idea. BTW, I'm trying to journal my progress through this problem for anyone else with a similar situation - hopefully it will serve as some help, as many similar posts have for me over the years.

\$\endgroup\$
2
  • \$\begingroup\$ Both eBusiness and Steve H's responses are right on the money... I'm trying to adjust my strategy closer to some of the finer points they mentioned to see what I get. I'll post my results here and let you both know if I have any other struggles. I think this should do the trick... I was awfully close to having it earlier this week, I think I just ran into a logic error on my part that threw me of course. Thanks again - I'll be in touch soon! \$\endgroup\$
    – David
    Jun 19, 2011 at 16:45
  • \$\begingroup\$ Both SteveH and eBusiness posts below were a tremendous help in solving my problem. I used the pseudocode provided by eBusiness to make sure I was handling things right (I had the idea right, but his post confirmed a few suspicions). I then added in some of the subtler notes left by SteveH and wound up with a working solution at the end. For anyone in a similar situation, the above snippets of code will hopefully help fine tune your own model. Thanks again to you both! \$\endgroup\$
    – David
    Jun 19, 2011 at 20:32

2 Answers 2

1
\$\begingroup\$

I think my biggest problem is understanding how to handle collisions against walls in the x-y axes (left/right, front/back), which I want to have elasticity, and the ground (z-axis) where I want an elastic reaction if the ball drops down...

I think you should handle the walls exactly the same as the ground. Create a method that takes as parameters the surface normal & the ball's velocity and returns a reflected velocity vector. If you need a short snippet for that, we can show that to. The elastic factor of a ball is the same whether it bounces from the wall or floor. I think you may be needing to factor in gravity so your ball's motion appears more natural.

In a game where you are roughly trying to approximate real life physics, you will most likely have a gravity vector which influences (add to) the ball's velocity vector each frame. The effect of the gravity will appear to influence the ball differently if the ball is bouncing from the floor vs. the walls because the gravity is aligned with the floor and has the most pronounce effect on ball speed changes (magnitude of the velocity vector), so there is where the difference you are expecting may come from.

Starting from when I detect a collision, what is a good way to approach the response to get the expected behavior in all cases?

  1. Determine the ball's position at point of contact. Determine what percentage of the frame's time slice The ball will travel in the reflected direction.
  2. Run the surface normal & the ball's velocity vector through the reflection method above. It will return the ball's new velocity vector.
  3. Transform the point representing the ball's position at the time of contact by the new velocity vector multiplied by the remainder of the frame's time slice. Factor in the gravity influence on this point.
\$\endgroup\$
6
  • \$\begingroup\$ I couldn't agree more, Steve, I'd love to see the same code across the board, regardless of the collision (in terms of how it is handled, but things like mass/velocity can have the "bounciness" vary). This kind of a solution is ideal, I'm just struggling with implementing it. I do have gravity being handled just like you suggest, and it does make sense that this shouldn't cause any different in how wall or floor collisions occur. I think my problem with this approach has to do with the ball either falling through the floor or getting stuck in it... let me play some more and post results! \$\endgroup\$
    – David
    Jun 19, 2011 at 16:43
  • \$\begingroup\$ before it falls through the floor or gets stuck, consider determining if the collision is going to happen this frame or not. If it is, then the new position should not go into the floor, but rather be transformed from its position at time of contact, in a direction of the reflected velocity, times the remainder of the time slice. If you do that, you will never have a penetration problem and never need to manually separate the ball from the wall/floor. Determining the position at exact point of contact requires solving a quadratic equation. Do you have the book "Real Time Collision Detection"? \$\endgroup\$
    – Steve H
    Jun 19, 2011 at 18:36
  • \$\begingroup\$ I don't have that particular book, but I will be sure to check it out - I bet it would help de-mystify some of the finer points. I think on the whole I have it, I'm just missing a few key pieces. I'm updating the original post now with the results of the changes I've made thanks to you and eBusiness. I think this is really close, and in fact it may be exactly what I want in terms of collision response. I may now need to adjust what is causing the continual collision! One moment on the edit... \$\endgroup\$
    – David
    Jun 19, 2011 at 19:26
  • \$\begingroup\$ @SteveH I think I have a great, working solution now (snippet posted above) thanks to your help. I have the point of contact and time (normalized between 1.0f and 0), which I then use the remainder of to calculate from that collision point and the newly calculated reflection velocity where the ball should be after a collision. I'm just struggling now to get the ball to stay "at rest" once that reflection velocity (z) gets close to zero and a constant collision is detected with the ground (which is radically interfering with normal movement now). Likely a problem with something else... \$\endgroup\$
    – David
    Jun 19, 2011 at 19:38
  • \$\begingroup\$ I added one more update to the problem (Update 2). The ball now stays at rest thanks to a fix to how I was calculating the new destPosition, but now the ball doesn't move nearly as fast as compared to how he does before he's "resting" on the "floor." I think this is a fundamental flaw with how I'm moving the ball from a higher level. I'll keep thinking... this has been a huge help! \$\endgroup\$
    – David
    Jun 19, 2011 at 20:13
2
\$\begingroup\$

Sphere colliding against unmovable plane in frictionless physics:

Project the spheres velocity on the planes normal, multiply the projection by 2 and subtract it from the spheres velocity. Done.

Before doing the collision you should check if the sphere is moving towards the plane, if not the collision should not be done, or you risk problems with wall-hugging.

If you want a dampening collision you may multiply by less than 2.

I'm not sure if I answered everything in your question, or if this is advanced enough for you, but I hope you can use it.

\$\endgroup\$
1
  • \$\begingroup\$ This is a good idea... I was doing something almost identical to this, but I think I was having trouble with it hugging the floor. I'll try to change back to this approach and see what we get... thanks for the tips, eBusiness! \$\endgroup\$
    – David
    Jun 19, 2011 at 16:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .