4
\$\begingroup\$

I have a terrain with geometry that is fairly ridged. I needed to make sure the player didn't enter the world geometry, so I used sphere-triangle intersections (after narrow down of which tris to test using AABBs on chunks of the terrain).

This works fine, the player smoothly appears to "roll off" the terrain when you walk into it.

What I do is detect the penetration distance of the sphere into the terrain, then just push the player back in the direction of the terrain face. That clears him of the world geometry.

Method 1:

Push the bounding sphere of the player back in the direction of the normal of the wall he hit, until he exits the wall.

enter image description here

However. This has had the awkward side effect of occassionally pushing the player into another face (when the player is near the meeting of 2 faces). The result is this nasty bounce-shake between the two walls and the player gets stuck until he changes direction (turns around).

enter image description here

Initially I tried to solve this problem by:

  • "Cancel" previous move by translating player back along his "last move" vector the exact distance he moved if he touches a wall

    • But this causes walls to feel "sticky". You will get "caught" on walls if you use this, if any component of your velocity enters a wall (so you cannot "slide" by running diagonally into the wall).
  • Pushing the player back along his "last move" vector only far enough to clear the wall. This looks better at first, but converges to the same sticky walls problem as "fully cancelling the move" if the player is already touching the wall, but is trying to slide along it by running diagonally into it

Method 2:

Cancel or partially cancel the move by pushing the player back along the vector from which he came, until he exits the wall he deepest hit

enter image description here

So it seems I was on the right track with the first approach (push in wall's normal direction). What I'm going to try next is a hybrid:

  • Look for wall intersection
    • If one is found, push him back along the normal of the wall, then CHECK FOR A WALL COLLISION AGAIN (apply Method #1)
      • If a 2nd wall collision is found, cancel the move until he exits the wall (apply Method #2)

Am I on the right track here? Is there a better way to solve this?

\$\endgroup\$

4 Answers 4

3
\$\begingroup\$

Here's one quick nice trick implemented in the latest Physics SDK: if you have a ball experiencing multiple collisions, then use impulses to resolve collisions.

  1. find the number of contact points (contact point = {pair, position, normal} )
  2. divide the ball into n balls with the same center of mass (basically sharing the same position and volume, of course not colliding with each other), but having the initial sphere's mass divided by n
  3. now simply compute for each sphere the necessary impulse required to push it out of the wall
  4. when all contact points are solved by finding appropriate impulses, just add those impulses together and apply them to your big sphere
  5. Inside a frame, to assure convergence, you can perform 4 such iterations to find a solution (relaxation).

Nvidia Physics researchers claim it's even jitter free :).

\$\endgroup\$
5
  • 2
    \$\begingroup\$ That's an interesting set of slides you linked. I hunted down the presentation of them with the audio: nvidia.fullviewmedia.com/gtc2013/0321-MB4-S3388.html \$\endgroup\$ Jul 26, 2013 at 15:26
  • \$\begingroup\$ Thanks, I only read the slides and their paper. It seemed awesomely intuitive (I've done it in my soft body collision system and got jitter free simulations, but, as Richard Tonge says, for rigid bodies it presents a certain softness when it comes to how well stiffness is simulated - not a problem for soft bodies though :) ). \$\endgroup\$
    – teodron
    Jul 26, 2013 at 16:14
  • \$\begingroup\$ yo can u help me with a 2d javascript implementation? \$\endgroup\$ Apr 30, 2020 at 8:13
  • \$\begingroup\$ @bluejayke if you can skip implementing this yourself (it will be non-trivial for sure) and can do away with one of the industry standards, Box2D github.com/kripken/box2d.js, then you needn't look any further. Or do you have any limitations/restrictions when using that library? Or is your aim to actually implement this method and not just use it to support 2D physics in an app or game? \$\endgroup\$
    – teodron
    Apr 30, 2020 at 8:22
  • \$\begingroup\$ @teodron Thanks, but yes I want to implement everything from absolute pure javascript, with no dependencies. I have it almost working, you can see some example of the code here: stackoverflow.com/questions/61518457/… its just that it gets stuck at the corners \$\endgroup\$ Apr 30, 2020 at 8:25
2
\$\begingroup\$

You could add one invisible wall to prevent players from trying to squeeze into these areas. So instead of bouncing between two walls at an acute angle, they could bounce off three walls with obtuse angles between them. That would avoid your feedback problem without additional collision logic. But to the player, it would appear that they simply can't move any farther into the joint of the two visible walls.

bobobobo bouncing off an invisible wall

\$\endgroup\$
5
  • 1
    \$\begingroup\$ I'm tempted to upvote this answer just for this nice looking Boboboboball. \$\endgroup\$
    – Rak
    Jul 26, 2013 at 9:09
  • 1
    \$\begingroup\$ My awesome artwork is distracting people from my solution to the problem. \$\endgroup\$ Jul 26, 2013 at 13:42
  • \$\begingroup\$ Actually, +1 for the dead simple yet effective answer. The pro art was just the cherry on top of the sundae. \$\endgroup\$
    – anthonyvd
    Jul 26, 2013 at 14:01
  • \$\begingroup\$ This is a nice idea but (not being distracted by the Boboboboball) I'd have to say it'd be fairly intensive to run an "angle analyzer" and insert additional invisible walls everywhere that these corners appear, the depth of which will work for the largest bounding sphere that moves. I'd rather solve the problem without adding phantom geometry (but I'll say I have used phantom geometry in other problems before). \$\endgroup\$
    – bobobobo
    Jul 26, 2013 at 14:41
  • 1
    \$\begingroup\$ That's fair. It basically changes from an engine feature problem to a level design problem. If your levels are procedural, this solution would be terrible. \$\endgroup\$ Jul 26, 2013 at 14:44
1
\$\begingroup\$

Method #1 does work, but performance is a lot better if you use the interpolated normal of the face (instead of the face normal, as I had been using).

enter image description here

But you can still get sporadic behavior with this. The "weird bounce" behavior occurs mostly when a sphere "chomps" into the side of a triangle (instead of "kissing" the triangle from above)

So I found there were actually 3 cases to handle distinctly to avoid sporadic bouncing behavior:

1. "Kissing" intersections (normal intersections like you'd expect).

enter image description here

For these you push off in the interpolated normal direction (use barycentric coordinates to determine the interpolated normal from the vertex normals -- you have the barycentric coordinates from the sphere-tri test anyway)

2. "Chomping Edge" intersections

enter image description here

3. "Chomping Corner"

enter image description here

For chomping edge and chomping corner, don't use the normal direction, that will push your sphere WAY off in the wrong direction. Instead you need the closest pt on the tri to the sphere center, and to push the sphere OFF the triangle in the direction from the closest pt on the tri to the sphere center.

A couple of other notes:

  • I only select one tri to push back on each frame.
  • The tri I select (of all the tris intersected) is the tri with the closest tri centroid to the sphere centroid. Choosing the tri with the deepest penetration distance does not seem to be a good choice.
\$\endgroup\$
1
  • \$\begingroup\$ yo very interesting diagrams and very helpful. I'm trying to implement a similar appraoch in javascript, I'm able to calcualte the projection and normal, but what do I do with it exactly when I have it? I tried just setting the position equal to it, but then it gets stuck at the corners stackoverflow.com/questions/61518457/… \$\endgroup\$ Apr 30, 2020 at 8:15
0
\$\begingroup\$

The "canceling" you described earlier should work, just you need to separate the movement between the axes and check both seperatedly. E.g. a collision on the X-axis shouldn't cancel the movement on the Y-axis and vice versa.

This also applies to the bouncing, hitting a wall should just invert the movement on the X-axis and not affect the movement on the Y-axis at all.

\$\endgroup\$
1
  • \$\begingroup\$ Hi, would it also be possible to check the different axes somehow when moving around with Math.cos etc? If I just cancel the X movement entirely then it freezes, is there some way to "map" the new position to the wall itself? stackoverflow.com/questions/61518457/… \$\endgroup\$ Apr 30, 2020 at 8:16

You must log in to answer this question.

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