Search Unity

  1. Looking for a job or to hire someone for a project? Check out the re-opened job forums.
    Dismiss Notice
  2. Unity 2020 LTS & Unity 2021.1 have been released.
    Dismiss Notice
  3. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

Inconsistency with Collision.impulse

Discussion in 'Physics' started by Iron-Warrior, Jul 22, 2020.

  1. Iron-Warrior

    Iron-Warrior

    Joined:
    Nov 3, 2009
    Posts:
    772
    Aight so strap in this one is pretty damn weird.

    Collision.impulse is described as:

    ...which is a bit fuzzy, but if impulse is obtained by summation, the order of the operations shouldn't matter, meaning it should be consistent regardless of what order objects are inserted into the physics scene etc. However, I've recently been noticing that the impulses are point in opposite directions when the exact same collisions occur based on a few conditions. Below is a gif demonstrating the issue.



    I have a small script attached to the box on the right hand side:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class ImpulseDebugger : MonoBehaviour
    4. {
    5.     public Color color = Color.white;
    6.     public Vector3 launchDirection = Vector3.forward;
    7.  
    8.     private void Awake()
    9.     {
    10.         GetComponent<Rigidbody>().velocity = launchDirection;
    11.     }
    12.  
    13.     private void OnCollisionEnter(Collision collision)
    14.     {
    15.         Debug.Log($"GameObject: {gameObject.name}\n" +
    16.             $"Contact count: {collision.contactCount}\n" +
    17.             $"Impulse: {collision.impulse}");
    18.  
    19.         DrawArrow(collision.contacts[0].point, collision.impulse, 0.5f, color, 1, false);
    20.     }
    21.  
    22.     private void DrawArrow(Vector3 position, Vector3 direction, float arrowSize, Color color, float duration = 0, bool depthTest = false)
    23.     {
    24.         Vector3 cross = Vector3.Cross(direction, Vector3.up).normalized;
    25.  
    26.         if (cross.magnitude < Mathf.Epsilon)
    27.             cross = Vector3.Cross(direction, Vector3.right).normalized;
    28.  
    29.         Vector3 upwardsCross = Vector3.Cross(direction, cross).normalized;
    30.  
    31.         Vector3 norm = direction.normalized;
    32.  
    33.         Vector3 tip = position + direction;
    34.  
    35.         Vector3 p1 = tip + cross * arrowSize * 0.7f - norm * arrowSize;
    36.         Vector3 p2 = tip - cross * arrowSize * 0.7f - norm * arrowSize;
    37.         Vector3 p3 = tip + upwardsCross * arrowSize * 0.7f - norm * arrowSize;
    38.         Vector3 p4 = tip - upwardsCross * arrowSize * 0.7f - norm * arrowSize;
    39.  
    40.         Debug.DrawRay(position, direction, color, duration, depthTest);
    41.         Debug.DrawRay(tip, p1 - tip, color, duration, depthTest);
    42.         Debug.DrawRay(tip, p2 - tip, color, duration, depthTest);
    43.         Debug.DrawRay(tip, p3 - tip, color, duration, depthTest);
    44.         Debug.DrawRay(tip, p4 - tip, color, duration, depthTest);
    45.     }
    46. }
    47.  
    I also have a script that allows me to reload the scene when I press the R key. In the above gif, the first playthrough occurs when I push the play button in the editor, while the second is when I reload the scene with R. We can see the arrow points in opposite directions in each playthrough.

    Relevant to this issue is that Unity iterates over the objects in the scene in a different order based off how you load the scene. When you load via pressing play in the Editor, it iterates over objects in an opposite order than when you load the scene dynamically. This mighty be the culprit but why? The collision has the exact same result, shouldn't the impulse be the exact same?

    This issue is making it challenging to perform work in OnCollisionEnter when the impulses are not consistent, since it may also be happening when objects are disabled/enabled. I've attached a 2019.4.4f1 project to allow this to be reproduced using the following steps.
    1. Open the Main scene.
    2. Duplicate the sphere.
    3. Delete the old sphere.
    4. Run the scene.
    5. Press R to reload it.
    6. Observe the arrow direction.
    The impulse direction will be consistent once the scene is closed/re-opened.

    This probably warrants a bug report, but it's honestly so bizarre I think having a thread is nice. I'll look into it a bit more and file one when I'm done anyways.

    Thanks for any input,
    Erik
     

    Attached Files:

  2. Iron-Warrior

    Iron-Warrior

    Joined:
    Nov 3, 2009
    Posts:
    772
    Alright, so luckily it looks like the
    Collision.contacts[0].normal
    is always pointing in the "correct" direction (the normal of the surface that was contacted), whereas
    collision.impulse
    points in two opposite directions depending on
    • Whether the scene was hot loaded or cold loaded
    • Which colliders are involved in the collision
    For the second point, I've compiled a collision matrix that shows whether the impulse direction is aligned or not. But this isn't important; we can simply pick whether the impulse should be aligned or not for our game, and then invert any impulses the point in the wrong direction with respect to the normal, which is consistent. Shown below is a gif with the impulse in yellow, the normal in cyan (two runs, the same as in the first post in this thread).

     
  3. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    1,969
    Being the sum of the individual impulses at the contact points that compose the collision, collision.impulse has an informative meaning but not a physical utility.

    The underlying physics engine, PhysX, exposes the individual impulses at every contact point. Those are useful, as they are the impulses and positions actually applied by the engine to the rigidbodies to resolve the collision. However, those are not exposed in Unity. I've requested Unity to expose the impulses per contact point, but the average waiting time for this kind of feature requests is ~5 years (yes, seriously :().

    It's the point 4 in this post:
    https://forum.unity.com/threads/my-top-three-physics-feature-requests.584263/
     
  4. Iron-Warrior

    Iron-Warrior

    Joined:
    Nov 3, 2009
    Posts:
    772
    Anticipation is half the fun. It was pretty exciting when we got Physics.Simulate and ComputePenetration.

    I've filed a bug report, case 1265352.
     
    Edy likes this.
unityunity