Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Have a look at our Games Focus blog post series which will show what Unity is doing for all game developers – now, next year, and in the future.
    Dismiss Notice

Experimental contacts modification API

Discussion in 'Physics Previews' started by yant, Jul 3, 2020.

  1. flimflamm

    flimflamm

    Joined:
    Jan 6, 2020
    Posts:
    38
    Indeed. I'm still looking into different optimization strategies, but this one isn't so bad.

    Another thing I'm interested in is having the rigidbody rotation and position be exposed in addition to the colliders. It would not take much to vastly improve the usability and power of the contact mod API in general.
     
  2. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    565
    While the new changes don't seem to be allowed into 2021.2 at this point in time, sadly, it's still good time to put stuff into 2022.1 actually -- so I appreciate if you can make a list of requests that appear to unlock use cases, or make life easier from your POV. As before, I'll make a custom build for you to try the changes early -- and then we deliver if that works. Thanks so much. <3

    ps I'll send the extra velocity getters to 2022.1 as it seems they're useful?
     
  3. flimflamm

    flimflamm

    Joined:
    Jan 6, 2020
    Posts:
    38
    Sounds excellent! Having the velocity getters is extremely useful; I'll be updating to 2022.x as soon as they're in!

    An immediate request that I have has to do with the position/otherPosition and rotation/otherRotation variables: they only give access to the colliders' transform data, but not the rigidbodies'. Having both might be required in a lot of different cases (for example, to derive relativeVelocity). In my case, the need arises from using child colliders with offset centers relative to the rigidbody center-of-mass. I recommend a change to/add the following:

    colliderPosition (collider center)
    otherColliderPosition
    (collider center)
    colliderRotation
    otherColliderRotation
    bodyPosition
    (center of mass)
    otherBodyPosition (center of mass)
    bodyRotation
    otherBodyRotation


    Regarding the lack of impulse:

    Given the above (along with the velocities and a given collision point), it's possible to derive the relativeVelocity of the colliders at the collision point, which is a broadly useful value (especially given the absence of impulse). It's a bit tricky to calculate because the relative velocity at a given point is affected by the angular velocity of both bodies (the gist is that you need to calculate the linear displacements at a given point on both colliders caused by their angular velocities, and add them to their linear velocities), so it might be worth adding a helper function for this for new user, although I'm not sure if that would be efficient system-wise. Weighting velocities by mass and inertia tensors before calculating a final relative velocity also seems to be the only or best way of guesstimating what the impulse will be, but this is something I have not toyed very much with yet.

    More requests to come!
     
    Last edited: Sep 9, 2021
    yant and NotaNaN like this.
  4. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    565
    Will be taking a took into these shortly.

    anthony.
     
    FissicsPeep and flimflamm like this.
  5. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    565
    The velocity getters will be available in 2022.1.0a12+. After this experimental round it was discovered that calling the velocity getter on a static collider resulted in a crash, so I fixed that one. Otherwise, it's precisely as was in the custom build shared above. Additionally, I added a minimal sample of contacts modification in the scripting API docs -- in the page for Physics.ContactModifyEvent (shows how to ignore contact points in a certain radius from origin).

    As to exposing positions -- I'll keep a card open on that. From a quick look, I couldn't conclude whether getGlobalPose is actually thread-safe in PhysX these days or not.
     
  6. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    565
    Wanted to bring this case up real quick.

    Order of object initialisation can be different Editor vs Player, and for that reason one shouldn't rely on the order of the Colliders in a modifiable pair (since that order depends on what physx shape gets created the first). Use hashmaps to decide on object type by instance id. Hope that helps.
     
  7. Gustorvo

    Gustorvo

    Joined:
    Oct 26, 2017
    Posts:
    32
    @yant friction modification doesn't seem to work with articulation body components...is it intended? If so, have you any time estimations when this will be implemented? Thanks!
     
  8. Deceleris

    Deceleris

    Joined:
    Jan 3, 2018
    Posts:
    21
    Hello ! Is it possible to implement it on an existing project ? What I want is really simple : freeze the rotation of a boat, produced by collisions with his environnement. Literally "don't rotate with external collision, but rotate when I add to you a force"
     
  9. Gustorvo

    Gustorvo

    Joined:
    Oct 26, 2017
    Posts:
    32
    You may want to check out the Layer-based collision detection, which will do exactly what you want. Also, make sure to read through the Colliders/Collisions in unity, which will give you a solid understanding on how those work. You don't need to use experimental contacts modification for suck a simple task.
     
  10. Deceleris

    Deceleris

    Joined:
    Jan 3, 2018
    Posts:
    21
    If I make it based on the layer, the boat will just pass through objects. Am I missing something ?
    My problem is more complex than it sound, I want to keep the collision, but not the rotation while NOT freezing it.
    But thanks for your answer, you gave me an idea : simulate the rotation using torques inside a separate rigid body unaffected by external environnent and child of the boat. Then using it's rotation and apply it to the parent, wich is affected by the collisions !
     
  11. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    428
    Try this:
    Code (CSharp):
    1. ModifiableMassProperties modifiableMassProperties = pair.massProperties;
    2.  
    3. modifiableMassProperties.inverseInertiaScale = 0f;
    4. pair.massProperties = modifiableMassProperties;
     
  12. Qleenie

    Qleenie

    Joined:
    Jan 27, 2019
    Posts:
    525
    Hey, I'd like to implement something like a hole in a mesh collider with Contact Modification, but I am struggling a bit with how to detect that the colliding object is in the hole, or outside. What would be the best approach to detect this? Have another trigger collider, and modify contacts as long as the colliding object is colliding with the trigger collider (with OnTriggerStay?). Any help appreciated.
     
  13. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    565
    Could you elaborate on how your hole is defined? The straightforward approach would be to have some function that being provided with a position, says whether it's in a hole or not. With that function, you could ignore the contact points that are within (or close) the hole.
     
  14. Qleenie

    Qleenie

    Joined:
    Jan 27, 2019
    Posts:
    525
    Thanks for getting back! Easiest way of definition would be by having e.g. a sphere collider / shape defining the hole. It needs to move with the rigidbody to which the mesh collider is assigned to, so a dynamic scenario.
     
  15. Qleenie

    Qleenie

    Joined:
    Jan 27, 2019
    Posts:
    525
    @yant any idea if this is solvable with contact modification? right now I am using a mechanism with collision layer switching based on collision trigger, but this is complicated setup and not very precise.
     
  16. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Yeah it's solvable with the existing API. Are you needing help with anything? Why would you use a collision trigger when Contact Modification callback is more accurate and timely?

    Basically once you get the callback and pair, you choose to ignore the collision within the hole and (optionally) construct a valid normal for the response for anything colliding. That is pretty much all you need to do to pretend there's a hole you can collide with properly.
     
  17. Qleenie

    Qleenie

    Joined:
    Jan 27, 2019
    Posts:
    525
    What's unclear to me is how do I determine if I am actually inside the hole inside the callback, and only manipulate the response if it is the case. Only way I can imagine would be to use a trigger collider in the shape of the hole and "OnTriggerStay", but I'd guess there must be a more elegant solution.
     
  18. Qleenie

    Qleenie

    Joined:
    Jan 27, 2019
    Posts:
    525
    I figured it out somehow to do it only with contact modification: by running through all pairs, finding all instances which collide a) with the main body and b) with the hole defining collider, and then manipulating the eligible pairs in a second loop. Works great, albeit the code does not look like that ...
     
  19. zf_jon

    zf_jon

    Joined:
    Aug 15, 2018
    Posts:
    41
    Hey @yant! Thanks for adding this API! It adds a lot of sweet possibilities.

    Trying it out in Unity 2022.1.0b2 has some issues (see bug reports 1393368, 1394290).

    Is there a newer build available to try?

    Edit: Tried 2022.1.0b3 and, unfortunately, it crashes even more easily.
     
    Last edited: Jan 12, 2022
  20. jacasch

    jacasch

    Joined:
    Jan 20, 2017
    Posts:
    16
    Oh wow, this sound so promising.
    Then it would finally be possible to do proper "fake" holes in colliders using other colliders (triggers) as a mask. currently its not really possible without extensive use of Layers and tweaking the collision layermask.
    Any Updates when this will land?
     
  21. jacasch

    jacasch

    Joined:
    Jan 20, 2017
    Posts:
    16
    Would you be willing to share your code?
    I'm tackling the same exact problem
     
  22. Qleenie

    Qleenie

    Joined:
    Jan 27, 2019
    Posts:
    525
    I was able to simplify it, with "faking" the second collider, as I realized that the callback seems to be called multiple times per frame in parallel, if multiple collider are colliding at same time with the colliders enabled for contact modification (not sure if this is wanted behavior or a bug in the current implementation), and with this behavior the above mentioned approach does not work reliable.
    By faking second collider, I mean that I am doing the math of calculating an overlap myself, instead of relying on Unity collision detection. I can share the actual contact modification code:

    Code (CSharp):
    1.     public void ModificationCallback(PhysicsScene scene, NativeArray<ModifiableContactPair> contactPairs)
    2.     {
    3.         for (int i = 0; i< contactPairs.Length; i++)
    4.         {
    5.             var pair = contactPairs[i];
    6.             int idToUse = capsulesForHoleCheckPerMainBody.ContainsKey(pair.bodyInstanceID) ? pair.bodyInstanceID : pair.otherBodyInstanceID;
    7.             Capsule[] capsules = capsulesForHoleCheckPerMainBody[idToUse];
    8.             Sphere[] spheres = spheresForHoleCheckPerMainBody[idToUse];
    9.             for (int j = 0; j < pair.contactCount; j++)
    10.             {
    11.                 bool foundCollision = false;
    12.                 for (int k = 0; k < capsules.Length; k++)
    13.                 {
    14.                     if (capsules[k].Contains(pair.GetPoint(j)))
    15.                     {
    16.                         pair.IgnoreContact(j);
    17.                         foundCollision = true;
    18.                         break;
    19.                     }
    20.                 }
    21.                 if (!foundCollision)
    22.                 {
    23.                     for (int k = 0; k < spheres.Length; k++)
    24.                     {
    25.                         if (spheres[k].Contains(pair.GetPoint(j)))
    26.                         {
    27.                             pair.IgnoreContact(j);
    28.                             break;
    29.                         }
    30.                     }
    31.                 }
    32.             }
    33.         }
    34.     }
    I am updating the positions of the "fake" collider in "FixedUpdate", so I can use them in the callback
     
  23. Qleenie

    Qleenie

    Joined:
    Jan 27, 2019
    Posts:
    525
  24. Kaktusz

    Kaktusz

    Joined:
    Jan 17, 2015
    Posts:
    9
    Hi, this seems like a very useful addition! I want to cancel a collision depending on the resulting impulse (like in Collision.impulse.magnitude). As I understand it, at this stage the actual impulse is not yet known. Is there a way to work around this? The context is that I have breakable windows, walls, etc. which are static colliders that get deactivated after a strong enough collision. This of course means that any rigidbody that breaks a window/wall/etc will bounce off of it, instead of ignoring the collision and flying through.

    Using pair.GetMaxImpulse won't work as it often returns values such as 1x10^32. Reverting the rigidbody to the last fixed update is not sufficient as it visibly freezes for a split-second, plus it is quite inefficient to save the state of all tracked rigidbodies to a dictionary every physics update. Reverting just the velocity but not the position does not work as sometimes the rb.position is already mid-bounce in OnCollisionEnter, for whatever reason.

    A very crude solution I'm considering is:
    - Have a concurrent dictionary, for rigidbody colliders, between instance ID and momentum.
    - Have a concurrent dictionary, for destructible object colliders, between instance ID and a tuple containing their max impulse tolerance and a flag for if they should be broken once we're back on the main thread.
    - Every fixed update, all tracked non-sleeping rigidbodies have their momentum saved to the dictionary for each collider which they are composed of.
    - In the modify contacts callback, use the contact normal and saved momentum to estimate the resulting impulse (use max among all contact points in the pair).
    - Check the impulse magnitude against the max impulse tolerance. If it exceeds, disable all contact pairs and set the broken flag to true. Otherwise, do nothing.
    - In OnCollisionEnter, the destructible object checks the broken flag in the dictionary and acts accordingly (gets broken or does nothing).

    Does anyone have a better way to handle this?
     
    NotaNaN likes this.
  25. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    428
    In 2022.1 you can access bodyA and bodyB linear/angular velocities. This is very useful especially if you want to calculate the impulse. The collision impulse is determined by the relative velocity, restitution, collision normal and the mass values from the bodies involved (i think, i don't remember the exact formula, there was a dot product somewhere...). With this in mine you could calculate the impulse yourself before it is calculated by the physics engine.

    Once you have the impulse value, you can ignore the contact if the value is greater than X. Here's a very simplified example, i'm just checking if bodyA velocity is greater than X (bodyB is static).
     
  26. darbotron

    darbotron

    Joined:
    Aug 9, 2010
    Posts:
    328
    I've only just found this thread - so glad this feature finally made it into Unity!!

    I've been a pro customer since 2010 & have been asking for this to be added since Unity 4.

    I primarily do console work & so I only use LTS versions of Unity and am currently on 2020.3 LTS, looking forward to having this.

    (@yant) just to confirm: Physics.ContactModifyEvent (& other related stuff) is in the docs for 2021.2 so I'm right to assume it's is in 2021.2 & non-experimental so will be solid in 2021 LTS right?
     
    Last edited: Feb 3, 2022
    hippocoder likes this.
  27. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,357
    There's no reason why Unity would remove this from upcoming 2021 LTS. Contact Modification is a released feature on 2021.2 already. It also exists on current 2022 cycle too.
     
    hippocoder likes this.
  28. xzbobzx

    xzbobzx

    Joined:
    Apr 7, 2015
    Posts:
    29
    To expand on the LTS question: Will/has this come to 2018 LTS?

    Bit of a long shot because it's such an old version of Unity, but I've got a lot of legacy assets that would completely break in 2021+

    PS: Love this addition, been wanting this for an extremely long time.
     
  29. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,357
    Unity doesn't typically backport new features to already released older versions. Also worth noting that Unity 2018 LTS support ended one year ago already so there's pretty much zero change they will add anything to it.
     
  30. xzbobzx

    xzbobzx

    Joined:
    Apr 7, 2015
    Posts:
    29
    Aye, figured something like that. Thanks anyway!
     
  31. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    565
    I have to open with you guys, contact modification is not coming to 2018 LTS for the reasons stated above.

    In addition to that, it's pretty unlikely to be backported to any prior LTS too -- unless there is a "critical" reason to do it. This is generally true for all features of new releases with only a handful of exceptions.

    As to it being present in the versions that are being developed -- yes it's not getting cut. We shipped it and intend to support going forward. I should probably share that we're experimenting with OnContact messages being reworked to follow the same pattern as the modifications -- the managed C# side will receive pointers to contact buffers as NativeArrays and proceed with how it worked before without having to cross managed/native borders (compat path). In addition to that the pure iteration over the native arrays with low overhead is exposed too.

    anthony.
     
    rz_0lento, Prodigga and NotaNaN like this.
  32. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,357
    @yant any updates on exposing physx immediate mode? :D
     
  33. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    565
    I would have loved to share, but so far it's just early work that we can't make available as an early build yet. I'll post as soon as it's ready.

    A.
     
    LudiKha and rz_0lento like this.
  34. Clonkex

    Clonkex

    Joined:
    Jul 31, 2012
    Posts:
    31
    Wait what! I never thought there would be a not-horrible way to make Portal-style portals with Unity!

    And it's even in 2021.2 already :O Mind blown. Thank you for your work, @yant! The more control we can get over PhysX, the more interesting things we can do without hacks and terrible workarounds :D
     
    NotaNaN and yant like this.
  35. iDerp69

    iDerp69

    Joined:
    Oct 27, 2018
    Posts:
    34
    Hrmm, would water physics be a good use case for contact mods? What might that look like? Just starting out and I see you can do cool things like tractor beams with it. Wish there were more tutorials, but it's still relatively new so it makes sense that this thread is about all there is for learning resources.
     
  36. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Basically contacts are what the physics engine gathers about a collision that is in progress, before resolving it. So you get to intercept and meddle. For example ignoring a contact if there is a hole near this contact in 3D space.

    So it can do anything from emulating weird shapes (normals or ignoring) to simulating a thick fluid of some kind (impulse etc). Be aware some values are not rational so look up if its inverted etc.
     
  37. iDerp69

    iDerp69

    Joined:
    Oct 27, 2018
    Posts:
    34
    Is there a reason contact pairs involving fast moving objects with Continous Dynamic detection mode are sometimes not ignored? From what I can tell, pair.IgnoreContact is still being called but I'm still getting a visual "collision".

    The repro is to use yant's build, change the collision mode on the sphere to Continuous Dynamic, and move it's Y coordinate to about 30 so it can pick up some speed.

    Just wondering if this is expected as a quirk from the collision mode or if this might indicate a bug.
     
  38. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,357
    Without knowing further details/your code: there's often more than one pair on same object. Make sure you ignore all of those contact pairs and not just the first one.

    Could be a bug / nonsupported scenario of course but would help if you could give direct repro proejct

    Also why would you use yant's experimental build when the api is already on 2021.2+ with bunch of fixes?
     
    hippocoder likes this.
  39. iDerp69

    iDerp69

    Joined:
    Oct 27, 2018
    Posts:
    34
    rz_0lento Here is a repro project, you can see it's just a modified version of yant's. I refactored the code a bit to be simpler to sandbox and extend but it's not functionally different. I made this in 2021.2.19 but I think any of the newer versions should be fine.
     

    Attached Files:

  40. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,357
    You have to use ContactModifyEventCCD for CCD collision pairs. I had to use both CCD + nonCCD callbacks in combination to get the the thing ignore the plane fully:
    Code (CSharp):
    1.     private void Awake()
    2.     {
    3.         Physics.ContactModifyEvent += ModificationCallback;
    4.         Physics.ContactModifyEventCCD += ModificationCallback;
    5.     }
    6.  
    7.     private void OnDestroy()
    8.     {
    9.         ModifiableContacts.Dispose();
    10.         Physics.ContactModifyEvent -= ModificationCallback;
    11.         Physics.ContactModifyEventCCD -= ModificationCallback;
    12.     }
    Here I just reused ModificationCallback callback function for CCD version, this worked with this sample but you'd probably want to have separate callback function for CCD since CCD version also inverts the contact normals, more about it on the docs here: https://docs.unity3d.com/2021.2/Documentation/ScriptReference/Physics.ContactModifyEventCCD.html
     
    iDerp69 likes this.
  41. iDerp69

    iDerp69

    Joined:
    Oct 27, 2018
    Posts:
    34
    rz_0lento Oh perfect, that fixes it entirely. Thank you so much for your help! I wonder why the separate callback... what is the use case meant to be? Odd about the contact normals being inverted for it.
     
  42. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,357
    Physx itself has separate callback for CCD contact mods so Unity just wraps that too.
     
  43. iDerp69

    iDerp69

    Joined:
    Oct 27, 2018
    Posts:
    34
    I want to create a arcadey bounce impulse velocity between two dynamic rigidbodies that make contact, such that one receives substantially more bounce than the other.

    pair.SetBounciness(i, 2f) is doing what I want... however I would like the bounce to only happen to one of the bodies in the pair. Is there some way I can achieve this?
     
  44. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,357
    @iDerp69 contact pairs apply to both sides once PhysX gets to resolving these things and we don't have access to that stage of physx solvers. I don't have any good suggestions on how to fix this, maybe you could temporarily add the damping (or whatever drag Unity calls this) on the RB that you don't want to bounce off so easily.. and make sure the other side has minimal damping.
     
    iDerp69 likes this.
  45. spider-worm

    spider-worm

    Joined:
    Jun 21, 2018
    Posts:
    4
  46. CaseyHofland

    CaseyHofland

    Joined:
    Mar 18, 2016
    Posts:
    307
    ModifiableContactPair
    has
    SetTargetVelocity(int, Vector3)
    , but no
    SetTargetTorque(int, Vector3)
    .

    Do ContactPairs not need to store torque or is this a missing feature? My real question is obviously: how do I apply torque to Rigidbodies via Modifiable Contact Pair? This seemed like the obvious solution maybe (probably) I'm wrong.
     
  47. backwheelbates

    backwheelbates

    Joined:
    Jan 14, 2014
    Posts:
    195
    Just curious, could this be used to prevent pops when objects Slide Over collider seams at high speeds?
     
  48. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,357
    I know this was a bit old post already but since nobody answered, I wrote a bit about this in here:
    https://forum.unity.com/threads/experimental-contacts-modification-api.924809/#post-6482950
    (my git repo sample also has simple example for this)

    and here:
    https://forum.unity.com/threads/experimental-contacts-modification-api.924809/page-2#post-6720985
     
    NotaNaN, backwheelbates and Edy like this.
  49. backwheelbates

    backwheelbates

    Joined:
    Jan 14, 2014
    Posts:
    195
  50. backwheelbates

    backwheelbates

    Joined:
    Jan 14, 2014
    Posts:
    195
    @rz_0lento , amazing, works super well!

    I had my character going through the ground a couple of times with Valve so I avoided that one. I noticed that No Separation worked well, but became jittery at very low speeds, so I just added a small speed check to the function. Works perfectly now.

    This should be an option in standard unity physics! @yant, any thoughts on exposing some of this in settings?

    Thanks again!!