Search Unity

Elastic collision and angular momentum

Discussion in 'Physics' started by LeRan, Mar 4, 2017.

  1. LeRan

    LeRan

    Joined:
    Nov 24, 2015
    Posts:
    118
    Hi forum,

    I'm trying to code some sort of bowls game, and I need to model collisions beforehand to have the IA decide its shots.

    I did the calculation for purely elastic collisions, but the actual result differs from the simulation. See example below :


    I expected the first bowl to stop and the second to go at its initial speed (fig. b) but actually both went together more or less at the same speed (fig. c).

    More generally, the expected angle between resulting velocities after an elastic collision is a right angle, but the actual angle observed in Unity is much more acute.

    So, question for those of you who know their physics better than me : is it only due to the angular momentum of the bowls and the fact that the model I'm using was (maybe ?) designed for non rotating masses ? Or does it have something to do with the materials, like friction and angular drag parameters, that I should tweak ?

    Thanks for your help
     
  2. josh_rake

    josh_rake

    Joined:
    Jan 4, 2017
    Posts:
    15
    For the velocities :
    Do you have a physics material with a restitution of 1 on both bowls?

    That'd be a start
     
  3. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    1,154
    I calculate this manually, based off the Wiki for elastic collision....

    PS:
    I just copy & paste my method...lot's of stuff you don't need...you can basically stop at the Velocity calculations...

    note, this was for a 2D game (2d collision) + the collision is actually later on not realistic, i.e. leverages the calculated velocities but is adjusted for better game play in the resolve collision method.

    Code (CSharp):
    1.         public void ResolveCarCollision (GameObject object1, GameObject object2)
    2.         {
    3.             ICollidable o1 = (ICollidable) object1.GetComponent<ICollidable>();
    4.             ICollidable o2 = (ICollidable) object2.GetComponent<ICollidable>();
    5.          
    6.             if (o1 == null || o2 == null)
    7.             {
    8.                 Debug.LogError ("Objects need to Implement ICollidable");
    9.                 return;
    10.             }
    11.          
    12.             // 2D ellastic collision --- WIKI (see my initial trigonometric way commented out below)
    13.             float m1 = o1.MyCarSpecs.weight;
    14.             float m2 = o2.MyCarSpecs.weight;
    15.             Vector2 p1 = o1.Position;
    16.             Vector2 p2 = o2.Position;
    17.             Vector2 v1 = o1.Velocity;
    18.             Vector2 v2 = o2.Velocity;
    19.          
    20.             Vector2 collisionVelocity1 = v1 - (((m2 + m2) / (m1 + m2)) * (Vector2.Dot(v1 - v2, p1 - p2) / ((p1-p2).magnitude * (p1-p2).magnitude))) * (p1-p2);
    21.             Vector2 collisionVelocity2 = v2 - (((m1 + m1) / (m1 + m2)) * (Vector2.Dot(v2 - v1, p2 - p1) / ((p2-p1).magnitude * (p2-p1).magnitude))) * (p2-p1);
    22.          
    23.             // resolve intersection at collision detection
    24.             float x_dist = Mathf.Max(0f, Mathf.Ceil(0.5f * (o1.SpriteWidth + o2.SpriteWidth) - Mathf.Abs(p1.x-p2.x))); // if x-distance is less than 1/2 their combined width, they overlap by the difference in pixels
    25.             float y_dist = Mathf.Max(0f, Mathf.Ceil(0.5f * (o1.SpriteHeight + o2.SpriteHeight) - Mathf.Abs(p1.y-p2.y))); // if y-distance is less than 1/2 their combined height, they overlap by the difference in pixels
    26.             Vector2 collisionSeparation1;
    27.             Vector2 collisionSeparation2;
    28.          
    29.             if (x_dist < y_dist)
    30.             {
    31.                 // separate on x axis
    32.                 // distribute according to mass relationship and position (i.e. the one on the left moves to the left, the other one to the right)
    33.                 collisionSeparation1.x = Mathf.Sign(p1.x - p2.x) * Mathf.RoundToInt (x_dist * m2 / (m1 + m2));
    34.                 collisionSeparation2.x = -Mathf.Sign(collisionSeparation1.x) * (x_dist - Mathf.Abs(collisionSeparation1.x));
    35.              
    36.                 collisionSeparation1.y = 0f;
    37.                 collisionSeparation2.y = 0f;
    38.             } else
    39.             {
    40.                 // separate on y axis
    41.                 collisionSeparation1.x = 0f;
    42.                 collisionSeparation2.x = 0f;
    43.              
    44.                 // distribute according to mass relationship and position (i.e. the one one the top moves uo, the other one down)
    45.                 collisionSeparation1.y = Mathf.Sign(p1.y - p2.y) * Mathf.RoundToInt (y_dist * m2 / (m1 + m2));
    46.                 collisionSeparation2.y = -Mathf.Sign(collisionSeparation1.y) * (y_dist - Mathf.Abs(collisionSeparation1.y));
    47.             }
    48.          
    49.             // determine length of collision based on relative mass (and hence velocity change)
    50.             float collisionDuration1 = Constants.fixedSlideTime + Constants.variableSlideTime * (m2 + m2) / (m1 + m2);
    51.             float collisionDuration2 = Constants.fixedSlideTime + Constants.variableSlideTime * (m1 + m1) / (m1 + m2);
    52.          
    53.             o1.ResolveCollision (collisionSeparation1, collisionVelocity1, collisionDuration1);
    54.             o2.ResolveCollision (collisionSeparation2, collisionVelocity2, collisionDuration2);
    55.  
    56.         }
     
    Last edited: Mar 5, 2017
    LeRan likes this.
  4. LeRan

    LeRan

    Joined:
    Nov 24, 2015
    Posts:
    118
    The physics materials I'm using are such. I know so little about Unity's physics that I post them as are (I dont even know what's a restitution...)

    Each bowl

    Dynamic friction : 0.05
    Static friction : 0
    Bounciness : 0
    (plus averages combinations)

    Ground
    Dynamic friction : 0.25
    Static friction : 0
    Bounciness : 0.2
    (plus averages combinations)



    Actually I thought of imposing velocities manually like you did, but it felt like I was missing the point of having Unity's engine take care of things, so I'm trying to find what I did wrong in the physics settings. But if nothing else works, I'll go ahead and defile Unity's engine with my own physics :)
     
  5. josh_rake

    josh_rake

    Joined:
    Jan 4, 2017
    Posts:
    15
    Before reading any code, you're doing perfectly elastic collisions so you want a bounciness of 1 on each bowl (bounciness = restitution)
    That should at least take care of the balls sticking together problem
     
    LeRan likes this.
  6. LeRan

    LeRan

    Joined:
    Nov 24, 2015
    Posts:
    118
    Thank you very much, the physical behaviour of the balls is already much better ! I put all the friction into the ground material, zero to the balls material and set the combination to "maximum", and it works wonders.
     
  7. LeRan

    LeRan

    Joined:
    Nov 24, 2015
    Posts:
    118
    All right, I still have some weird behaviour in my game, but I think that I'm narrowing down the problem to a limited number of possible causes...

    With very, very tiny changes in the initial conditions (a 0.05 % increase of the ball's initial speed in the present case), I can obtain 2 widely differing results, cf. picture below :
    - the case 1 where everything behaves like expected.
    - the case 2 where things become weird.



    It seems that something fishy happens in case 2 just after the impact with the ground :
    -the rigidbody's velocity splitting between longitudinal and negative vertical components, while it should already be in contact with the ground.
    - the angular velocity being weird.

    I have no idea why this happens and how to fix it. Help someone ?
     
  8. LeRan

    LeRan

    Joined:
    Nov 24, 2015
    Posts:
    118
    Long story short, I think that the cause of the problem may be related to the size of my objects : with ridiculously oversized balls (diameter 37 cm instead of 7.5 cm) the physics behaviour is back to normal (and the timestep or initial velocity no longer induce chaotic results).

    But I don't want to differ from the 1 Unity unit = 1 meter rule that's so helpful for the rest of the project. Is there a way to fix those physics artefact at "small" scales ?
     
  9. josh_rake

    josh_rake

    Joined:
    Jan 4, 2017
    Posts:
    15
    Project settings -> time > fixedtimedstep
    Try decreasing that value
    It will increase the physics precision, at the cost of performance
    By default it runs at 0.02 which is 50 fps
     
  10. josh_rake

    josh_rake

    Joined:
    Jan 4, 2017
    Posts:
    15
    Project settings -> physics
    Other values to fiddle with to increase precision, paying with performance
     
  11. LeRan

    LeRan

    Joined:
    Nov 24, 2015
    Posts:
    118
    @tresshort Thanks for the tip, I've been meddling with Time and Physics parameters : refining them improves the situation, but at the cost of enormous computing time ; the game becomes really laggy before the problem is fully solved. Which is weird, because I only deal with few objects (less than 10), that have a fairly common size (around 7 cm) and speed (between 1 and 10 m/s).

    Besides that, I found that the incorrect physcial behaviour is related to both the size and speed of the objects. So, after extensive research, I found this thread : https://forum.unity3d.com/threads/r...fter-certain-conditions-faster-better.332085/ that points to this one : https://blogs.unity3d.com/2014/07/08/high-performance-physics-in-unity-5/

    Basically, it seems that Unity's PhysX engine decides whether or not it triggers the continuous collision detection, based on impact speed : for lower speeds, it decides that discrete is good enough. That would explain the weird physical behaviour at low speed! But I still need to model correct collisions at low speed for my pétanque game... Help :(
     
  12. josh_rake

    josh_rake

    Joined:
    Jan 4, 2017
    Posts:
    15
    Are you using 2D objects and colliders? Because it runs on Box2D which is a different engine from Physx

    Anyways the default time step is 0.02, which means an object with 10 velocity will move 0.2 meters every step
    If you put 0.005, that's 4 times the precision and one step will be 0.05 m, which should be enough to prevent tunneling through your 7 cm objects.
    And a desktop computer can handle that easily, unless it's a mobile game?

    Another thing to double check is that you're not using mesh colliders

    Finally, decreasing the contact offset might help
     
  13. LeRan

    LeRan

    Joined:
    Nov 24, 2015
    Posts:
    118
    @tresshort Thanks for your answer. I'm using 3D objects with sphere colliders, so there is no immediate solution...

    I experimented with numerous combinations of time steps and contact offsets. The main result is that the collision simulations vary largely and unpredictably depending on those parameters : the final position of the ball after impact can vary by something like 30 cm depending on the couple timestep / contact offset I'm using, which is huge given the scale of my game.

    So finally I gave up. Thus :
    a) I fix collisions manually with mathematics formula applied to both rigidbodys velocity after the collision, so that at least the resulting angle is correct.
    b) I set a timestep and contact offset arbitrarily and I gave up the idea of predicting accurately the moves of the IA - it's good enough for a "casual gamer IA", which is kind of sad actuallly, since I wanted to predict the moves perfectly then add customized error margins to reflect different levels of skill.
     
  14. josh_rake

    josh_rake

    Joined:
    Jan 4, 2017
    Posts:
    15
    Yeah. I actually pushed physics aside too because it's not reliable and it's underdocumented