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. Join us on Dec 8, 2022, between 7 am & 7 pm EST, in the DOTS Dev Blitz Day 2022 - Q&A forum, Discord, and Unity3D Subreddit to learn more about DOTS directly from the Unity Developers.
    Dismiss Notice
  3. 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. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    565
    This work is not dependent on DOTS, though you can combine it with some dots stuff indeed. NativeArray and the C# Job system API that's used here is part of Unity core and doesn't require pulling any packages.
     
    NotaNaN, Prodigga, Ruchir and 2 others like this.
  2. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    428
    I'm not sure about kinematic CCs (since you have the freedom to do whatever you want), IMO dynamic CCs (physics-based) could get really improved using this API, simply because it allows you to implement one way platforms easily (2D and 3D), simulate invisible walls (if slope angle > slope limit), modify friction (i believe) and some other cool stuff.
     
    NotaNaN and Ruchir like this.
  3. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,357
    Actually friction spoofing isn't available. Quote from PhysX docs:
    (would have been cool that have that)
     
    NotaNaN and lightbug14 like this.
  4. FissicsPeep

    FissicsPeep

    Joined:
    Jan 14, 2014
    Posts:
    63
    Thanks for doing these tests. Seeing the ball bouncing on seams issue fixed via this is just beautiful. Would be interested to know what other methods there are? When I investigated the issue it was just the normals you'd get back from the collision would be pointing towards the ball somewhat (like the ball hit the side of the object, rather than rolling across the top of it)... so my plan with contact modification was to just change the normal to be the triangles normal in this case.

    Are there even better alternatives?
     
  5. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,357
    I feel like it's important to first understand why this happens, I'll try to explain it briefly here:

    When you move the ball across collider seams, you can sometimes get contact normals that seem like they hit the side of the object (this can happen even on flat planes, terrain seams etc). It's happening because physics engines have thing called contact offset. When the narrowphase does try to find the contact points, it uses collision shapes to detect the collision but it also takes into account this positive (contact) offset, making the collision shape feel tad bigger. You can adjust this in Unity's physics settings but it has fairly small value by default and you can't set it to value like 0 here so you'll always have some issues like this (but you can definitely make the behavior better by putting really tiny value for this).

    Now when the ball hits collider seam with offset on both ball and the object it hits, it will not always be what you'd expect it to be, and you get impacts like you'd hit a wall for fraction of the second, which then causes the physics engine to try to resolve this collision. I'll explain this a bit more later..

    In my demo project, I just ignored all contact pairs which had separation larger than zero. This effectively removes most of the false positives and ball doesn't bounce across seams anymore. After all you can't get contact point further away than the radius of the sphere which effectively will always give you contact normal that's facing the correct direction.

    Now this may sound like it solves the issue but there's one negative side effect from removing existing contact pairs: if this was your only contact pair at that physics frame but ball is still touching the ground, you are essentially also removing contact resolving, friction and restitution from the ball from that physics step. This means that the ball will be more slippery (while crossing the colliders seams) and have less friction (especially noticeable if you move the ball via physics torque).

    I haven't actually done the following myself for the ball use case but knowing what's happening there, I can think of few other ways one could fix this:

    - if you know the object is a flat plane etc thing where it's surface normal is expected to always be the same, you could just spoof the contact pair normal with it's known normal value, there would still be small offset in the actual contact position which could still make small changes to the ball trajectory but probably nothing noticeable

    - if you need something that works with more complex collision shapes, you may want to compute the true collision position by projecting the ball's current position to the direction where you know the other object is. I don't have a great algo to present for this but I'd assume it would depend a lot on your level design too. Once you know the actual position where the ball touches the object, you can just get the contact normal by subtracting the ball's position (center point) from that true contact point position and normalizing it.

    Now you may think, why wouldn't you just do the last step I just mentioned (use unaltered reported contact point position and ball position to compute the contact normal)? The thing here is.. it's actually what happens with physx already and the result you get (in case you have data with positive separation on the contact pair) will be that sideways facing contact normal because the contact offset in position. You can do the math yourself if you log the current position and ball position and compute the normal from that, but it will be the same value physx already computed.

    So, in the end, there are multiple angles you can approach to fix this. If you don't need any kind of friction and just move the ball via forces or you can compute your own friction each physics step (this isn't difficult), you could just go with the contact pair ignore route which I used in the demo. Also if you don't have many seams that break your physics, losing bit of friction there could just be acceptable as is. Otherwise you have to come up with something like what I tried to explain here that will suit your project specifically.

    Additionally, I could imagine doing naive "store the previous physics step normal and reuse it in case with positive separation" could work as well. In such case you'd just spoof both contact normal and position where normal would be the previous physics steps value and position would be just the ball position with ball radius offset in opposite direction of the contact normal.
     
    Last edited: Jan 13, 2021
  6. FissicsPeep

    FissicsPeep

    Joined:
    Jan 14, 2014
    Posts:
    63
    Thanks for the in-depth, detailed reply!

    Yeah, this is the approach I was thinking of taking. If I know a triangle/seam is part of a smooth/flat/continuous surface then just use the triangle normal.

    However, there are still times when even though the object is part of a flat surface, its other edges are indeed edges, so you might want to bounce off that edge "correctly", rather than "reflect bounce" off it if you just modified the contact and used the triangle normal. For example, two touching, identical boxes forming a flat surface on the top - there's a seam along the edge where they touch, but the other 3 sides are genuine, non-flat edges, e.g. the very right-hand edge of your gif.

    Not sure what physx supports, but if I recall with some physics engines you could store some very small metadata into each triangle (unsigned int?). With this you could use a single bit for each triangle edge to indicate if it's a seam edge or an outer edge (in the case of static objects of course).
     
  7. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    565
    We don't feature anything like that at the moment, unfortunately.
     
  8. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,357
    We probably are not allowed to use raycasts (regular ones, not jobified ones) on contact mod callback? I can't immediately remember if physx itself would have issues with this (other than it not being the best idea in general) but I can see Unity API having some issues with it depending on how the wrapper is made.

    I could see getting single raycast result on that ball case being useful as you could then just query the proper data for the callback via it.
     
    FissicsPeep likes this.
  9. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    565
    Yeah, this is a pretty good consideration. Most of the Unity API is designed to be called from the main thread really, however a good portion of it is such for no particular reason other than back in 2005 threading not being of the same concern as today.
     
  10. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    565
    You're right one could use the raycast batches probably, however I'm not sure waiting from inside the modification job and thus stalling the main thread too (since Physics.Simulate originates from the main thread always, and modifcation is part of its job graph) would be all that great perf wise.
     
  11. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    565
    Later this year I hope to start work on exposing the raw primitives + some "immediate mode"-ish API for it, but until then nothing stands out on top of my mind right at the moment as a possible great solution for it I'm afraid.
     
    LudiKha, Ruchir, NotaNaN and 2 others like this.
  12. FissicsPeep

    FissicsPeep

    Joined:
    Jan 14, 2014
    Posts:
    63
    @yant - I know you can't give specific dates or versions, but do you have a ballpark idea for when we might see this contact modification make it into a release? 3 months? 6 months? This year? Next year? Even the vaguest guess would be useful. Really appreciate this is finally being exposed. It's going to help so many different genres of games.
     
    NotaNaN and Prodigga like this.
  13. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    565
    Thank you for your kind support, but I can't really share precise dates at this moment. All I could say in the spirit of transparency, is that it's fair to expect relevant news this year. I'll be posting here as soon as I can. <3
     
    NotaNaN, Prodigga, Gooren and 3 others like this.
  14. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,357
    Was really hoping to see this on 2021.2 but at least just released a5 doesn't have this.

    I know, no promises but one can still hope :)

    Edit-> Not in a10 either.
     
    Last edited: Mar 17, 2021
  15. Deleted User

    Deleted User

    Guest

    Thanks Yant,
    Waiting for this since 2017 :) Hope I will able to test soon,
     
  16. Ruskul

    Ruskul

    Joined:
    Aug 7, 2014
    Posts:
    71
    This is super cool. Stuff I always needed but I had heard the same work was going to be done for 2d as well (a few years back), but it fell off the road map recently and I can't find any info on it. Is the work still happening?
     
  17. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    565
    I think @MelvMay has more visibility into 2D plans than I do.
     
  18. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    565
    It's been pretty silent in here, just wanted to share one extra thing that appeared in this branch as it was getting finalized for delivery. It's a small feature that allows retrieving the triangle data directly from within the callback. For instance, look at this simple visualization that highlights the current triangle that the ball collided with:

    aaf00d5b5dacba491f297dc544d4ab5b.gif

    Code:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Collections;
    5.  
    6. public class FaceIndexSample : MonoBehaviour
    7. {
    8.     public float scale = 0.1f;
    9.     public Mesh mesh;
    10.  
    11.     public uint faceIndex = 0xffffFFFF;
    12.  
    13.     private int[] triangles;
    14.     private Vector3[] vertices;
    15.  
    16.     public void OnEnable()
    17.     {
    18.         Physics.ContactModifyEvent += ModificationCallback;  
    19.  
    20.         mesh = GetComponent<MeshFilter>().sharedMesh;
    21.         triangles = mesh.triangles;
    22.         vertices = mesh.vertices;
    23.  
    24.         GetComponent<MeshCollider>().hasModifiableContacts = true;
    25.     }
    26.  
    27.     public void OnDisable()
    28.     {
    29.         Physics.ContactModifyEvent -= ModificationCallback;  
    30.     }
    31.  
    32.     public void OnDrawGizmos()
    33.     {
    34.         if (faceIndex == 0xffffFFFF)
    35.             return;
    36.  
    37.         int i = triangles[faceIndex * 3];
    38.         int j = triangles[faceIndex * 3 + 1];
    39.         int k = triangles[faceIndex * 3 + 2];
    40.  
    41.         Vector3 a = transform.TransformPoint(vertices[i]);
    42.         Vector3 b = transform.TransformPoint(vertices[j]);
    43.         Vector3 c = transform.TransformPoint(vertices[k]);
    44.  
    45.         Gizmos.color = Color.red;
    46.         Gizmos.DrawSphere(a, scale);
    47.         Gizmos.DrawSphere(b, scale);
    48.         Gizmos.DrawSphere(c, scale);
    49.  
    50.         Gizmos.color = Color.white;
    51.         Gizmos.DrawLine(a, b);
    52.         Gizmos.DrawLine(b, c);
    53.         Gizmos.DrawLine(a, c);
    54.     }
    55.  
    56.     public void  ModificationCallback(PhysicsScene scene, NativeArray<ModifiableContactPair> contactPairs)
    57.     {
    58.         // only one pair in this sample
    59.         var pair = contactPairs[0];
    60.  
    61.         // suppose there is only one contact point too.
    62.         faceIndex = pair.GetFaceIndex(0);
    63.     }
    64. }
    65.  
     
  19. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,250
    Thank you! Could you share more details on the ModifiableContactPair struct?

    I wonder if this could be used as an alternate to Collision.impulse, so we could read the individual impulses of each contact point instead of the sum of the impulses of the collision.
     
  20. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    565
    Not sure Edy, this thing is called pre-solver so it won't know about the impulses it will apply next. There's only a per-point doodle to limit the impulse it can apply. As to the per-point impulse -- that's an old & shameful thing that hasn't been solved yet, should bounce it higher in the planning doc. Also, I was intending to expose the read-only contacts to scripts in a similar way to the modifications -- "one" large array of contacts for scripts to iterate as opposed to a myriad of OnCollisionStay invocations. Give me a few minutes to complete building a branch and I'll share a couple of screenshots why I thought that was possibly a good idea.
     
    NotaNaN, Edy, TheZombieKiller and 3 others like this.
  21. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,085
    Always exciting to see your work Yant, thanks for keeping us posted!
     
  22. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    565
    So a few thoughts on performance of reading data from a somewhat tricky array (actually, accessing portions of a huge contacts array from all the threads) vs getting called once per each contact pair (=OnContactStay).

    This is a sample that will come with contacts modification -- all it does is to visualize contact points of ~8000 balls falling, and then rolling on an inclined plane:

    a11285a7bc9fefa0de27d97b7aaedd7a.gif

    Now, solving this traditionally -- making it so that there is a script with an OnCollisionStay function added to the plane and then collecting the contact points from there works in ~23 ms on my machine.

    Screenshot 2021-03-02 at 14.58.51.png

    And here is the same done with the contact modification approach (without actually modifying anything of course -- just collecting points) -- it's roughly 6 ms, almost regardless of the amount of contacts -- scales well especially compared to the screenshot above, where you can see a huge cliff as it starts to discover more and more contact points.

    Screenshot 2021-03-02 at 14.56.52.png

    Here are the scripts if you're curious. Please forgive me being somewhat ignorant of the threading issues while writing to the native array really, seems to work fine at the moment :)

    Traditional approach:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections.Generic;
    3. using Unity.Collections;
    4.  
    5. public class CallbackBasedVisualizer : MonoBehaviour
    6. {
    7.     public NativeArray<Vector3> contacts;
    8.     private int contactCount;
    9.  
    10.     public float gizmoScaling = 0.5f;
    11.     private int maxContacts = 1000000;  
    12.  
    13.     public void OnEnable()
    14.     {
    15.         contacts = new NativeArray<Vector3>(maxContacts, Allocator.Persistent);
    16.     }
    17.  
    18.     public void OnDisable()
    19.     {
    20.         contacts.Dispose();
    21.     }
    22.  
    23.     public void FixedUpdate()
    24.     {
    25.         contactCount = 0;
    26.     }
    27.  
    28.     public void DrawFrames(Vector3 center, float scale)
    29.     {
    30.         Gizmos.color = Color.red;
    31.         Gizmos.DrawLine(center, center + Vector3.right * scale);
    32.  
    33.         Gizmos.color = Color.green;
    34.         Gizmos.DrawLine(center, center + Vector3.up * scale);
    35.  
    36.         Gizmos.color = Color.blue;
    37.         Gizmos.DrawLine(center, center + Vector3.forward * scale);
    38.     }
    39.  
    40.     public void OnDrawGizmos()
    41.     {
    42.         for (int i = 0; i < contactCount; ++i)
    43.         {
    44.             DrawFrames(contacts[i], gizmoScaling);
    45.         }
    46.     }
    47.  
    48.     public void FillContacts(Collision collision)
    49.     {
    50.         for (int i = 0; i < collision.contactCount; ++i)
    51.         {
    52.             contacts[contactCount++] = collision.contacts[i].point;
    53.         }
    54.     }
    55.  
    56.     public void OnCollisionEnter(Collision collision)
    57.     {
    58.         FillContacts(collision);
    59.     }
    60.  
    61.     public void OnCollisionStay(Collision collision)
    62.     {
    63.         FillContacts(collision);
    64.     }
    65. }
    66.  
    Threaded approach with contacts modification tech:

    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3. using System.Collections.Generic;
    4. using Unity.Collections;
    5.  
    6. public class ModificationBasedVisualizer : MonoBehaviour
    7. {
    8.     public NativeArray<Vector3> contacts;
    9.  
    10.     public float gizmoScaling = 0.5f;
    11.     private int maxContacts = 1000000;
    12.     private int contactCount;
    13.  
    14.     public void OnEnable()
    15.     {
    16.         contacts = new NativeArray<Vector3>(maxContacts, Allocator.Persistent);
    17.        
    18.         // assume we're been added to the ground
    19.         transform.GetComponent<Collider>().hasModifiableContacts = true;
    20.         Physics.ContactModifyEvent += ModificationCallback;
    21.     }
    22.  
    23.     public void OnDisable()
    24.     {
    25.         contacts.Dispose();
    26.         Physics.ContactModifyEvent -= ModificationCallback;
    27.     }
    28.  
    29.     public void FixedUpdate()
    30.     {
    31.         contactCount = 0;
    32.     }
    33.  
    34.     public void DrawFrames(Vector3 center, float scale)
    35.     {
    36.         Gizmos.color = Color.red;
    37.         Gizmos.DrawLine(center, center + Vector3.right * scale);
    38.  
    39.         Gizmos.color = Color.green;
    40.         Gizmos.DrawLine(center, center + Vector3.up * scale);
    41.  
    42.         Gizmos.color = Color.blue;
    43.         Gizmos.DrawLine(center, center + Vector3.forward * scale);
    44.     }
    45.  
    46.     public void OnDrawGizmos()
    47.     {
    48.         for (int i = 0; i < contactCount; ++i)
    49.         {
    50.             DrawFrames(contacts[i], gizmoScaling);
    51.         }
    52.     }
    53.  
    54.     public void  ModificationCallback(PhysicsScene scene, NativeArray<ModifiableContactPair> contactPairs)
    55.     {
    56.         for (int i = 0; i < contactPairs.Length; ++i)
    57.         {
    58.             var pair = contactPairs[i];
    59.  
    60.             for (int j = 0; j < pair.contactsCount; ++j)
    61.             {
    62.                 contacts[contactCount++] = pair.GetPoint(j);
    63.             }
    64.         }
    65.     }
    66. }
    67.  
     
    NotaNaN, Ruchir, JoNax97 and 2 others like this.
  23. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    565
    Experiments like that also highlight the Physics.UpdateBodies thing now being super expensive at larger scale, especially for what it does, which is just running through the PhysX bodies, taking their transform, and assigning it to the Unity Transform, on the main thread. With clever coding it can actually be made jobified these days, hope to get there too.
     
    NotaNaN, Ruchir, JoNax97 and 3 others like this.
  24. Ruchir

    Ruchir

    Joined:
    May 26, 2015
    Posts:
    885
    Any plans to release these updates in the 2021 Tech cycle?
     
  25. NotaNaN

    NotaNaN

    Joined:
    Dec 14, 2018
    Posts:
    313
    I just stumbled into this thread and got totally super excited. Thank you so much for your hard work, @yant, on all these amazing new PhysX features! I'm very much looking forward to them. :p
     
    yant likes this.
  26. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    565
    Unfortunately, this won't happen in 21.1. The earliest it can actually happen is 21.2.
     
    NotaNaN and Ruchir like this.
  27. LudiKha

    LudiKha

    Joined:
    Feb 15, 2014
    Posts:
    137
    This is great - though shouldn't you compare it using the non-alloc GetContacts(); method? I'd imagine a portion of that frame time is due to GC.
     
  28. koirat

    koirat

    Joined:
    Jul 7, 2012
    Posts:
    1,780
    I somehow missed this thread and have not added my valuable input. ;)
    What I see is ModifiableContactPair got properties in world space ( point/normal/separation).

    Today we still got problem with getting collision point on body collider (in it's local space).

    Correct me if I'm wrong but people me included were struggling for years with situation where fast colliding bodies (ex: two fast moving spheres) collides, repel each other and what you get is a point somewhere in the world space completely outside of the bodies and without any possibility to find what was the point on collider that was realy hit.
     
    Last edited: Mar 12, 2021
    NotaNaN likes this.
  29. PandaArcade

    PandaArcade

    Joined:
    Jan 2, 2017
    Posts:
    101
    I just wanted to chime in and show my support for adding this feature ASAP :D
     
    yant, Ruchir and NotaNaN like this.
  30. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    565
    Hi everyone,

    This is a quick message to share that contact modification will be available since Unity 2021.2.0a12. I wanted to use this opportunity to thank all the early adopters on this thread, your efforts testing and shaping the feature definitely helped a lot. <3

    As always, I'm happy to see any bug reports (preferably with some way to repro, as usually).

    Anthony
     
  31. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,357
    Thanks Anthony, this is awesome :) Very much appreciated!
     
  32. romanpapush

    romanpapush

    Joined:
    Sep 20, 2012
    Posts:
    40
    Amazing news @yant, thank you for the transparency!
     
    DannyWebbie, Prodigga and yant like this.
  33. lightbug14

    lightbug14

    Joined:
    Feb 3, 2018
    Posts:
    428
    Thank you very much @yant , great news! :cool:
    Now we need to convince Melvyn to implement the PreSolve from Box2D :D.
     
    yant, NotaNaN and Prodigga like this.
  34. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,085
    Exciting stuff, thanks Yant!
     
    yant and NotaNaN like this.
  35. FissicsPeep

    FissicsPeep

    Joined:
    Jan 14, 2014
    Posts:
    63
    Fantastic news! Thank you @yant. This feature is a game changer.
     
    DannyWebbie, yant and NotaNaN like this.
  36. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,357
    And 2021.2.0a12 is now out :)
    Edit: Also updated my earlier sample for it: https://github.com/0lento/ContactModSampleUnity
     
    Last edited: Apr 7, 2021
  37. Hannibal_Leo

    Hannibal_Leo

    Joined:
    Nov 5, 2012
    Posts:
    493
    Is this a dream? THIS IS AWESOME :D
    Working on physics based stuff since years and always had to use fake colliders/rigidbodies to simulate the collision response I wanted. Absolutely amazing that we can modify this now.

    Can't wait to rewrite what I called "soft collision" for my building destruction system. (because a building flipping over won't just act like a rigid body, some parts will break on impact and it will sink into the ground before applying (reduced) forces)
     
    Ruchir, yant, NotaNaN and 1 other person like this.
  38. Ruchir

    Ruchir

    Joined:
    May 26, 2015
    Posts:
    885
    Can you suggest a better way?
     
  39. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,357
    Ruchir likes this.
  40. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    600
    Hi, @yant

    This is pretty exiting stuff, I been looking it for a while and hopping to perform some tests with my easy character movement 2 (asset store package), as this could help to better integrate it with Phys X.

    However, one question regarding continuous collision detection (e.g. sweep contacts), are those reported and modifiable too ? For example in my controller, I implement a typical collide and slide algorithm sweeping along character's velocity and resolving "future" contacts allowing the character to better navigate the world geometry.

    Thanks,
    Krull
     
    NotaNaN likes this.
  41. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    565
    Yes, CCD contacts are reported and are modifiable as well. In PhysX this goes through a separate callback really onCCDContactModify vs onContactModify, however I thought to expose it via a single callback in the Unity integration for now. That said, both ccd and discreet contacts are sent via ContactModifyEvent.
     
  42. Krull

    Krull

    Joined:
    Oct 31, 2014
    Posts:
    600
    Awesome! definitely worth deep dive on this, thank you!

    Regards,
    Krull
     
    yant likes this.
  43. flimflamm

    flimflamm

    Joined:
    Jan 6, 2020
    Posts:
    38
    Thank you so much for this as I have desperately wanted a way to intercept collisions before they reach the solver!

    I have at least two specific use cases for this, but I'm not sure what is the best strategy for some of the details. Stabbing physics (one collider piercing another), and directional-friction are my two use cases:

    Stabbing physics is confounded mainly by the fact that last-tick's collision impulses are already applied by the time FixedUpdate rolls around, and any manually applied forces on that tick can only take effect on the next tick. The rest I can easily handle by clever use of an on-demand configurable joint...

    The second use case, directional-friction (I want friction to be greater depending on which way the object is sliding relative to its surface). To do this (without constantly modifying instanced physic materials), I need to compare the difference in world-space velocities of the colliding objects (along with the normals of the collision to determine direction), and factor the friction accordingly.

    One of the main questions I have is how I can determine which type of collision event is happening if I want to modify contact in more than one way (how can I easily identify which type of game-object is being collided with, so i can apply the correct modification type). I could encode an identifier in the bounciness field, or something along those lines, but is there a more sensible way to do this?

    Additionally, is there a convenient way to identify the exact gave objects that a given contact pair represents?

    Thank you very much for any advice or insight you can offer!
     
    yant likes this.
  44. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    565
    For any modifiable contact pair, you can get Unity instance ids for the colliders and bodies of both participants. Then, since that happens on a thread, most of the Unity API is not accessible so you'd have to build up some sort of a hashmap that can map from the instance ids to some struct that has all the data you need. You'd update that hashmap every frame right before simulation happens. Does this sound like a viable way forward?
     
    Ruchir and flimflamm like this.
  45. janzak

    janzak

    Joined:
    Jan 21, 2014
    Posts:
    1
    Hi yant,
    any chance of being able to reassign which collider (or more specifically rigidbody) will be handling the contact?

    Edit: found a better solution!
     
    Last edited: May 26, 2021
  46. flimflamm

    flimflamm

    Joined:
    Jan 6, 2020
    Posts:
    38
    A hash map approach using the unity instance id field sounds perfect. Thanks very much for the help!
     
  47. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,357
    You can also check the sample I posted earlier here (https://github.com/0lento/ContactModSampleUnity). It's quick sample with NativeHashMap, I don't claim it uses best practices but maybe it'll help?
     
    Krull, NotaNaN and Prodigga like this.
  48. flimflamm

    flimflamm

    Joined:
    Jan 6, 2020
    Posts:
    38
    This is quite helpful!

    For anyone interested, here is my first pass attempt at directional friction for a snake agent I have planned



    This is pretty interesting because there are no forces being applied to this string of rigidbodies and joints whatsoever (side from the joints flexing the body itself). By reducing the friction in the forward direction of each body segment, the resulting asymmetry and imbalance of friction forces pushes it forward. It approximates snake locomotion physically, which is why it looks relatively good.

    The problem is I am using very crude math to do this right now (basically just using the relative velocity and forward of each collider naively), but piping in all the various data to determine the exact "movement" of each contact relative to the nearest surface point on each collider is a bit extra. (it ought to be doable, just tedious...). Once the math is fixed and I give an agent this kind of body, it should looks incredibly realistic.
     
    Last edited: May 28, 2021
    adamgolden, Krull, JuozasK and 5 others like this.
  49. Ruchir

    Ruchir

    Joined:
    May 26, 2015
    Posts:
    885
    Could you provide some examples as to how you implemented this? :)
     
  50. Hannibal_Leo

    Hannibal_Leo

    Joined:
    Nov 5, 2012
    Posts:
    493
    My previous approach was quite simple - there were just two colliders on different layers for each part of the building.

    So I've written a quite complicated physics engine (using the Jobsystem & Burst, based on verlet physics), that can calculate stress on a building and will break it into chunks based on this stress.

    upload_2021-6-2_3-15-22.png

    upload_2021-6-2_3-15-31.png

    upload_2021-6-2_3-16-1.png

    upload_2021-6-2_3-16-24.png

    I had to write it myself because unity can't deal with 1000s of joints on the same object.
    upload_2021-6-2_3-17-1.png

    Once I have my chunks (which consist of building parts such as walls, floors, pillars) I just added one rigidbody on top of each chunk, so they form a compound collider and react to physics.

    This lead to rigid behaviour, so instead I just had a second collider for each building part (wall, floor, pillar, ..) with no mesh renderer (invisible colliders on a seperate layer than the actual building parts with colliders and mesh renderers).

    So all real collisions are invisible, so the only thing I had to do is to synchronise the invisible one with the visible one.
    The visible one has a maximum velocity change value - it won't change it's velocity more than that within one fixed update.
    So when the invisible building responds too rigid, it will be ignored. Example: it bounces off the ground or stops completely in one frame - then the visible building won't accept these values, just apply reduced values and break all building parts that are intersecting with the floor (using OnCollisionEnter on the invisible building). Then I just synchronise the invisible building with the visible one (because the velocity of the invisible one is now at 0, it has collided, responded and stopped, but it should continue moving down, just slower, so I set the velocity to match the one of the visible building).

    And that's it.
    1) Have an invisible and visible building.
    2) Always synchronise the visible one to match the invisible one.
    3) On collision, check if we exceeded the maximum velocity change.
    3a) if not - just keep synchronising, don't do anything
    3b) if we exceeded it, synchronise the visible building with reduced forces
    3b -> 4) break colliding building parts
    5) Set the velocity of the invisible building to the correct value
    6) repeat in next frame

    Final result:


    With Debug:


    BUT unfortunately I am not actively working on this right now, we concluded "this project is way to big to be the first one, let's make a simple game first" - yea, we said that one year ago xD The "simple game" has grown insanely, it is a big scifi first person stealth combat puzzle game with branching narrative by now (halfway done) and will be finished within the next 1.5 years - THEN we are going to focus on the building destruction game again xD

    And with the contacts modification, I can get rid of the invisible building entirely and apply reduced forces on the main (visible) building directly. This simplifies the code extremely and allows for more complex building x building collisions (when one building falls onto another one).
     
    Last edited: Aug 4, 2021
    NotaNaN, JuozasK and Ruchir like this.