Search Unity

  1. Unity Asset Manager is now available in public beta. Try it out now and join the conversation here in the forums.
    Dismiss Notice
  2. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  3. Unity support for visionOS is now available. Learn more in our blog post.
    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:
    594
    Hi,

    EDIT: A newer build here: #22

    tl;dr - here is a custom build with the experimental contact modifications API exposed: https://beta.unity3d.com/download/7a80bceabf9d/public_download.html. It is based on 2020.2.a8 and only the mac, windows and linux editor executables are available at this moment in time.

    Contact modification is all about customizing the reaction to contacts, and that has been a rather frequent request over the years. PhysX offered this functionality a while ago, but just because of the internal implementation details it was tricky to expose it to scripts in Unity. Today I wanted to share with you a custom build with some early/experimental work in that area, to see what you guys think. In spirit of transparency, let's look at this together and shape it to a form that is shippable and usable (just like we did with Physics.Simulate, articulations, PhysX upgrades and many others).

    Here is a one-page summary of how it works: https://docs.google.com/document/d/1lyvZ_Epm7W5iQSuLkF0kHKsHNshKDoyp4U73JO8Zt1M

    A single-scene quick demo: https://drive.google.com/file/d/1W853CPme46wh3wTmFXsPLYDyaKBAhkKv/view

    4217dee0cbd5ae0f5b70e20f26235502.gif

    This demo shows two use cases actually. On the left a ball falls through a plane by ignoring all the computed contact points. This can easily be extended to ignoring a portion of a mesh (make holes in anything). On the right, there is a bouncy cube that reflects off tilted planes. It doesn't rotate because all the contact points are ignored but one. This only contact point is set at the centre of the cube, so the depenetration impulse won't cause rotations. The target velocity is also set to communicate the desired direction of the bounce (along the plane normal).

    Let me know what you think. Thank you so much for testing and sharing your ideas.

    Anthony
     
    Last edited: Oct 17, 2020
  2. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,495
    That's cool thanks!!
    As per this update, will the regular ContactPoint struct expose the individual impulse for that contact? (instead or in addition to the aggregated Collision.impulse). It think it's a good opportunity to improve that, and would be useful in more situations.
     
    PedroCoriAG likes this.
  3. segant

    segant

    Joined:
    May 3, 2017
    Posts:
    196
    I'm interested in exposed heightfield
     
  4. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    594
    What I have in mind next is to try exposing a buffer of contacts to scripts, for direct iteration by analogy with modifications. Essentially, an approach that would allow to iterate an array of PxContactPair and access directly what's there with no wrappers. Traditional contact callbacks can easily be achieved from there. I believe there is still a lot of overhead with the current per-pair callback design that is driven by the native code.
     
    Last edited: Jul 7, 2020
    guaralism, Cynicat and Edy like this.
  5. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
    Oh nice, I totally missed this got out for testing :D THANK YOU. I'm guessing if everything goes well, this would ship in 2021?
     
    Last edited: Jul 16, 2020
  6. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
    I quickly looked at the demo project and current API.

    What I do wonder a bit is this:
    Code (csharp):
    1.     public void  ModificationCallback(IntPtr buffer, int count)
    2.    {
    3.        for (int i = 0; i < count; ++i)
    4.        {
    5.            var header = ModifiableContactPairHeader.GetFromBuffer(buffer, i);
    If one uses contact modifications, you are more than likely to iterate through all contacts. At least I can't think of any exception where this wouldn't happen. I do know that you've exposed this in pretty similar manner to how physx does it though (they don't expose the whole buffer natively at once either if I remember right). But what I'm wondering is if Unity could just grab the whole header array in native code and pass it all once to managed side? I dunno what kind of overhead difference we are talking about here but just throwing it out there as this could result in better perf with lots of modifiable contacts.

    also bit curious about this:
    Code (csharp):
    1.        // This should be done once before every physics simulation, for now.
    2.        Physics.SetContactModificator(contactsReceiver.ModificationCallback);
    would this be done automatically in final version if contact modifications are enabled (I feel there should be a physics setting toggle for this that's set to disabled by default so you could omit this for projects that don't need it). I'm curious what extra is currently done on each fixed update for these? You'd think this could be just registered once on level load?

    I was also going to point out the need for collider specific flags (as physx supports this) but I then saw mention of this already on the google doc you linked :)

    Also wondering a bit about the naming, for example ModifiableContactPairHeader seems bit too verbose for my taste, could it be just ContactPairHeader?

    All in all, I'm happy to see that you managed to expose all the contact mod api here, looking forward to the day this works on stock Unity :D
     
    Last edited: Jul 16, 2020
  7. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
    Also, any chance to get next preview on 2020.2.0a15+ so we could test this with new articulation additions?

    As additional note, I'd love to see new physics features just get merged to main releases sooner with (Experimental) tags, just like happens with new rendering feats atm. This would give people early access to new things and more time for Unity to stabilize the feat / API before locking it in. In case of contact modifications, it would be a pretty safe addition as long as there's a physics setting that sets the whole feat off by default :)

    As second additional note, this isn't really that big of a deal but there could be an additional toggle for contact modifications when you create additional physics scenes (this is getting into super niche category) but I'm guessing this wouldn't be that difficult to implement as the contact mod callback is set on physics scene creation, could just throw this into the mix. What I mean here is that if you have multiple scenes with different physics scenes, you could opt to only have contact mods enabled on some of them.
     
    Last edited: Jul 17, 2020
  8. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    594
    Yes, I'll do that once I'm back to work in mid-August.

    I'm not sure I follow 100%. Isn't the current API exposing everything you talk about, just not in a flat array? It's a flat array of contact pairs, each having a link to a flat array of contact points, essentially.

    This is a great question, thanks. The way I imagined this (not verified yet!) is to expose a sort of a function that marks a collider as having modifiable contact points. Something like Collider.modifiableContacts = true. Collider already belongs to only one scene, so we're done with that on this side of the API. Then, it's one callback invocation per scene actually. But you're right I should probably extend the callback so that it accepts the scene reference explicitly.
     
  9. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
    Thanks, will keep eye on the thread :)

    Ah the point wasn't that something wouldn't be available, the suggestion was mainly to reduce the interop overhead if you could just pass the whole array at once (as NativeArray etc). This could play a role if there's a lot of contacts to process (again haven't tested the perf but it's pretty hard to properly test on editor).

    This would be fine IMO considering how niche this feat ultimately is.
     
  10. Cynicat

    Cynicat

    Joined:
    Jun 12, 2013
    Posts:
    290
    Awesome stuff! Isn't contact modification how you're supposed to implement the modern versions of triggers in PhysX? Would this open the door to more robust and performant triggers in unity?
     
  11. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
    I don't think you should do triggers as generic solution with this. Contact modifications do have perf overhead applied to them so you should use them sparingly, they are more like special hammer to fix edge cases and things that are known to cause issues with generic contact solver data.

    Also worth noting that the way this works, you are supposed to mainly alter the contact data, not generate extra events from it (but surely you can also extract a lot of extra data with it, just be aware of the lack of Unity api while using the callback). Doing triggers with it is technically possible but I doubt you could make them more performant this way.

    Of course if you need more functionality that is not available through existing API, this could allow you to hack your own variants.
     
  12. Cynicat

    Cynicat

    Joined:
    Jun 12, 2013
    Posts:
    290
    Yant and Pierre Terdiman discuss it in this thread, apparently the built-in trigger path in PhysX is both janky and slow.
    https://forum.unity.com/threads/physx-4-1-in-unity-experimental-builds.634960/page-3
    but i vaguely remember another thread talking about it where they said filtering was faster, but i haven't been able to find it. Unreal engine actually implements their triggers this way and it lets them do some very detailed collision filtering, for example letting a shape collide with one layer and just overlap (their version of trigger) against another layer.

    If you have done any experiments on this, i'd love to hear about them, i haven't messed with internal physX myself in years. =3
     
  13. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
    @Cynicat You are correct that Unreal doesn't use trigger path at all but their approach also has it's own overhead. I should double check but pretty sure they do manual polling for final overlaps there which in turn creates x amount of extra steps to accomplish this. It is probably what allows them to do their filtering setup like they do though. Their huge overhead from the overlap checking is reason why you should always omit them in Unreals actors if they don't need it (these used to be enabled by default for each actor there in past but I think they changed the default at some point at the expense of convenience of overlaps always triggering). But I do admit I have no idea if using trigger callback from physx is any slower or faster than doing it like unreal as I've never actually tested the different approaches on same framework (so I don't even try to estimate this myself).

    Anyway, to get back to the point. What Pierre suggested on that thread (afaik anyway) was to implement triggers same way as regular collisions but omit the few flags that make them resolve collisions. This is a different approach from omitting the collision from already processed contact pair data through contact modification api. Former (omitting those few flags from physics shapes) basically says to physx that this physics shape will not have it's collision resolved so it never processes the relevant data for it. If you ignore the collision through contact modification api a bunch of extra things already get computed before you get to even ignore the collision. Contact modification is just the last step in the way where you can make final adjustments to the data before contact resolving happens.

    I have doubts that contact mod api could help on generic trigger case but if you have special case that needs it or you just need it for few limited amount of objects, I guess it's still possible to abuse the api a bit for this purpose. If just talking about this previews implementation, yant mentioned that Unity api is not available to use within the contact mod callback but you could probably cache the event data during contact mod callbacks and send it after physics.simulate is done etc to keep the thread safety intact.
     
  14. Cynicat

    Cynicat

    Joined:
    Jun 12, 2013
    Posts:
    290
    Thanks for the details! I didn't know most of this, i'll trust your judgement and do more research then.

    I'm desperate for reliable triggers in unity and will clutch at any straw I see. I'm so tired of bending over backwards and burning tons of perf just to keep track of what a trigger is overlapping. =<
     
  15. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    594
    Pierre and myself experimented with emulating triggers as contacts some time back.

    Basically, generating the contact pairs, and then filtering them out after the broadphase. That was with the onContact call, not through modifications. I'll have to recollect but there were some rough edges there actually, we couldn't seamlessly migrate from onTrigger to onContact with no side effects. For instance, by default, the contact pairs won't get generated for kinematic pairs, but trigger pairs would. Fixing that required turning on a potentially expensive option that enables all kinematic pairs to be processed. It's all solvable potentially, but not directly and instantly. Just my 2c. Anthony.
     
    Cynicat likes this.
  16. TheZombieKiller

    TheZombieKiller

    Joined:
    Feb 8, 2013
    Posts:
    265
    It's awesome to see that we're finally on the cusp of getting this functionality, I've been wishing we had it for a long time now.

    It definitely seems a little awkward for the API to expose a raw IntPtr and count instead of a more formal accessor. In the absence of support for Span<T>, the above suggestion to supply a NativeArray<ModifiableContactPairHeader> parameter (and equivalents for the fields) seems like the natural choice to me, since it'd be far less error prone.

    Also, this is a bit of a nitpick, but is there a reason for the API using "modificator" instead of "modifier" in its naming?
     
  17. Darkgaze

    Darkgaze

    Joined:
    Apr 3, 2017
    Posts:
    381
    This is AWESOME.
     
    NotaNaN likes this.
  18. Qleenie

    Qleenie

    Joined:
    Jan 27, 2019
    Posts:
    839
    Any chance this will be available in 2020.2 / 2020 LTS ?
     
  19. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    594
    This is a quick note that I'm working through your feedback posted to this thread so far, right as we speak. Expect a new build soon.
     
    TheZombieKiller, m0nsky and rz_0lento like this.
  20. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    594
    Here is another early build with a new iteration of the contacts modification API: https://beta.unity3d.com/download/467cd01a0bba/public_download.html

    Here are a few short notes:

    As always, your thoughts and ideas help a lot. Thanks so much for posting and helping out testing.

    Anthony
     
  21. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
    I'm really digging the setup now, looks nice and polished :) Thank you for still working on this.

    I'll give it a go and report if I find something noteworthy on current approach.
     
    yant likes this.
  22. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    Very excited for this. I have a fast moving rigid body in an arcadey game, I want it to scrape along walls on impact but because of the large forces involved, any slight angle or change in the walls and it can cause the rigidbody to bounce or ricochet violently off the wall. Hoping to be able to smooth that out.
     
    yant likes this.
  23. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    594
    Appreciate if you could take a look at API, or - even try to hack something using the build shared above - and come back with your ideas. Given it's current state, I'm looking into having it shipped in 21.2 (the earliest it can be delivered actually). Any feedback helps, let's shape it together. Anthony.
     
  24. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
    Here's a quick test I did:

    (git repo here: https://github.com/0lento/ContactModSampleUnity)

    Basically there are few things happening here:

    1) There are no forces/velocities added directly to these two balls in the scene. Instead the cubes at the bottom are acting as boost pads through contact modification (they just make the ball contact points think that the pads actually are moving at certain velocity).

    2) Second ball has additional contact modification hack to check if the contact pair has positive separation. If it finds separation bigger than 0, it will ignore the contact point. This will prevent the ball from bouncing on collider seams in this example. The other ball doesn't have this fix and you can see it getting airborne almost immediately. There are other (and better) ways to deal with this case, it merely acts as example here.

    3) Lastly, that transparent blue cube on the left side acts here as a directional valve, it's setup via contact modification to ignore any contact pairs whose contact normal is facing right world axis, basically this allows the balls to pass through initially but not into opposite direction.

    Don't take this as proper example on how to fix these presented cases, it's just more of a thing to show how one can use the contact modification API. Worth noting that I've set the different collider indices into NativeHashMap for quick search for the contact modification effect we want to apply for that collider (using collider integer index as key). This part could be expanded to pass even more data to the contact modification stage, for example one could prefill a custom struct for the hash map instead of just the contact mod type.

    As for the API itself, I like the current structure. I'd really love to be able to access the required GameObject data directly from contact modification callback but I do get it's not trivial to make it threadsafe (and that threadsafe gameobjects are not a priority for Unity). Considering how niche this feature ultimately is, I'm fine by using the manually cached data for this.
     
    Last edited: Nov 2, 2020
  25. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    Downloading now, I don't plan to do anything advanced with it, but happy to provide feedback anyway!
     
  26. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    Oh man, yant, what I would give to have this available for production use..! This goes such a long way towards fixing all of our janky physics issues in my arcadey game... Inverse Intertia Scale is a godsend, and am currently toying with the contact friction values to penalize the player for scraping the walls but only under certain conditions. (I guess I could achieve this by driving physics material properties..but still!).

    One way walls would have been amazing too in an older project that I had worked on.

    Very cool stuff. API looks good to me, I didn't have any problems with it. Obviously could use some documentation but I was able to google some physx documentation and got what I needed from there.
     
    PutridEx, NotaNaN, Ruchir and 2 others like this.
  27. Ruchir

    Ruchir

    Joined:
    May 26, 2015
    Posts:
    933
    Is there a way to add additional contacts through this API, it could be super useful for kinematic characters
     
  28. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
    You can't add contact points or pairs, only modify existing ones.

    But you can move existing contact points from the contact pair however you like.
     
  29. Ruchir

    Ruchir

    Joined:
    May 26, 2015
    Posts:
    933
    Could it be possible in a future update or is this technically impossible given the physX API?
     
  30. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
    Pretty much this. There's no API in PhysX contact modifications to actually feed in more data, you can only modify (and ignore) what it reports to you. You can go a long way with modifications though.
     
  31. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    Do you have any interesting examples/use cases of contact modification? I can think of a fair few uses, but now I am curious what other games use it for?
     
  32. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
    Obviously there can't be much Unity samples out for this as it's not a released thing even, I'd expect to see more examples shared by community once the feat gets released.

    But there really aren't that many examples for the original c++ api either. Here's Nvidia's own sample snippet where they normalize masses for the contact solving (so things with high mass ratio will not glitch):
    https://github.com/NVIDIAGameWorks/...ctModification/SnippetContactModification.cpp

    Here's another from Nvidia showing how to use it on wheels:
    https://github.com/NVIDIAGameWorks/...ehicleContactMod/SnippetVehicleContactMod.cpp

    If you find some other examples, I'd love to see them as well :)
     
    Prodigga likes this.
  33. Onigiri

    Onigiri

    Joined:
    Aug 10, 2014
    Posts:
    464
    Can i use this for filtering contacts with specific rigidbodies and discarding impulses from them so they wouldn't push each other?
     
  34. Onigiri

    Onigiri

    Joined:
    Aug 10, 2014
    Posts:
    464
    I'm trying to make dynamic rigidbodies stop in place and not push when they colliding into each other regardless of their velocities and masses. Can contact modification help me with my case?
     
  35. Onigiri

    Onigiri

    Joined:
    Aug 10, 2014
    Posts:
    464
    Tried with no luck:( I think i need this
    and add counterimpulse to each contact point so no one will be pushed.
     
    Prodigga likes this.
  36. TJHeuvel-net

    TJHeuvel-net

    Joined:
    Jul 31, 2012
    Posts:
    837
    Is that property on a collider if they have modifyable contacts serialized and exposed in the inspector?
     
  37. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
    It's not. I'd love that have that there but I'm now assuming it's hidden to avoid confusion in majority of the user base. Just randomly enabling this feat as checkbox on the inspector could just result in worse perf for people who enable it without actually using the feature.

    Would be nice if we had some hidden advanced settings on the inspector for this (like we have for example on many HDRP components like lights etc).
     
  38. TJHeuvel-net

    TJHeuvel-net

    Joined:
    Jul 31, 2012
    Posts:
    837
    Sometimes settings appear when you enter debug mode.

    To be honest for this one it might make sense, because without some code backing it doesnt do anything.
     
  39. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
    It doesn't show up in debug mode either but this could be one option to hide it from normal users I suppose.
    @yant any thoughts on showing the checkbox on debug mode?

    I'd still rather have some setup for this that would have a toggle in physics settings for this and then if the contact mod setting is enabled, just show up the checkbox per collider in the editor. This way it would be hidden from regular users and shown only when you actually have the functionality separately enabled.
     
  40. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
    This probably isn't the right stage to modify for what you want. Basically with contact modifications you are spoofing the actual contact data that's going to be fed to the solvers, actual collision resolving hasn't been computed at this point yet so you can't modify that. What it sounds like you'd want to adjust the part that PhysX does AFTER this (but that's not exposed nor has public API in PhysX afaik).

    If you really want to try to utilize contact modifications for this, you could try to play with spoofing the mass ratios I suppose (to make the object - which you don't want to move - appear heavier to the solver than it really is) but this could have stability issues and probably wouldn't fully solve your case.

    If this is for character controller, in general I'd advice doing some kinematic character controller instead as you'll keep fighting physics engine all the time with physics engine simulated RB's.

    If it's just few objects, one way I can imagine you could try to solve this (without any contact modifications) is to simply put extra kinematic rigidbody and collider attached to the dynamic objects as child gameobject. So if this is for player character, then you'd set the char controllers collider to not collide with these other dynamic objects at all but instead you'd set the char's collider to collide with the extra kinematic colliders (that you've now just set follow the other dynamic objects). You can do setup like this with Unity's built-in physics collision matrix on the physics settings.
     
    Onigiri likes this.
  41. Ruchir

    Ruchir

    Joined:
    May 26, 2015
    Posts:
    933
    Any update on this topic?
     
  42. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    594
    There isn't anything concrete that I could share at this stage other than note the feedback shared on the thread was overall positive and the feature looked useful to have in the mainline, so I think we're making it. Unfortunately, I can't share any dates today.

    ---

    That ^ isn't an update tech folks would like to see, so here is an additional perspective that hasn't been shared before.

    Basically, I've been wondering how does collecting contacts with the modification callback compares to collecting them with the good old OnCollision events. I made a small scene that spawns a grid of spheres falling onto a tilted plane -- that will produce a lot of moving objects feeding us enough contacts for a test.

    185236ecb623b2938143073a4bb37799.gif

    (The blue-ish doodles are actually visualisers for contact points -- it displays a basis for each one; this grid is 90x90 big ~ 8K rigidbodies)

    Now here are some profiler captures. First this is with the OnCollisionStay events.

    Code:
    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.  
    Snapshot:

    Screenshot 2020-12-17 at 19.28.36.png

    Discussion: An average frame looks ~18ms long. ~10ms are taken by Physics.ProcessReports which is totally consumed by a simple script populating a native array. This illustrates the great overhead of OnCollisionStay.

    Now on to modifications.

    Code:

    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.parent.GetComponent<Collider>().hasModifiableContacts = true;
    20.         Physics.ContactModifyEvent = ModificationCallback;
    21.     }
    22.  
    23.     public void OnDisable()
    24.     {
    25.         contacts.Dispose();
    26.     }
    27.  
    28.     public void FixedUpdate()
    29.     {
    30.         contactCount = 0;
    31.     }
    32.  
    33.     public void DrawFrames(Vector3 center, float scale)
    34.     {
    35.         Gizmos.color = Color.red;
    36.         Gizmos.DrawLine(center, center + Vector3.right * scale);
    37.  
    38.         Gizmos.color = Color.green;
    39.         Gizmos.DrawLine(center, center + Vector3.up * scale);
    40.  
    41.         Gizmos.color = Color.blue;
    42.         Gizmos.DrawLine(center, center + Vector3.forward * scale);
    43.     }
    44.  
    45.     public void OnDrawGizmos()
    46.     {
    47.         for (int i = 0; i < contactCount; ++i)
    48.         {
    49.             DrawFrames(contacts[i], gizmoScaling);
    50.         }
    51.     }
    52.  
    53.     public void  ModificationCallback(PhysicsScene scene, NativeArray<ModifiableContactPair> contactPairs)
    54.     {
    55.         for (int i = 0; i < contactPairs.Length; ++i)
    56.         {
    57.             var pair = contactPairs[i];
    58.  
    59.             for (int j = 0; j < pair.contactsCount; ++j)
    60.             {
    61.                 contacts[contactCount++] = pair.GetPoint(j);
    62.             }
    63.         }
    64.     }
    65. }
    66.  
    Snapshot:

    Screenshot 2020-12-17 at 19.28.09.png

    Discussion: An average frame simulation takes 6ms, and the contact point collection is now almost free. One can see that the next big obstacle to simulating faster is Physics.UpdateBodies that is single-threaded (this is simply reading transforms from PhysX and assigning values to Unity Transform; the only complication there is it performs in a tree up to down order).

    Conclusion: collecting contacts with the modification-based approach is roughly 3x faster than with the OnCollisionStay events (even when reuse collision data is turned on). We're saving on passing data through .net marshalling, and on copying buffers that occurs inside Physics.FetchResults.

    Hope that was still an interesting read.

    Anthony
     
    Last edited: Dec 18, 2020
  43. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
    Thanks for the example Anthony, much appreciated.

    Why it is single-threaded though? Can't you use ParallelForTransform etc for this or is the job overhead too big in most expected cases?
     
  44. yant

    yant

    Unity Technologies

    Joined:
    Jul 24, 2013
    Posts:
    594
    The main reason it is single-threaded is because that's a decade-old code block that evolved naturally over time. It used to have many side-effects like calling transform listeners which was never possible off the main thread. Now there is only one such thing (for AI/Navmesh), which I imagine we could split off.

    Still even that done, we need to respect up-to-bottom update order (remember in PhysX there is no concept of hierarchy for rigidbodies at all so we do kind of sorting ourselves). I guess the best we could do in that regard is a set of ParallelForTransform+wait on each transform depth. In my particular case all the falling spheres are on one level of the hierarchy so it should be pretty much like iterating an array as you suggest. Would be nice to have that done.
     
  45. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
    I'd assume that in most larger scale physics simulations you'd have pretty flat hierarchies for the physics bodies in general - where you could also really benefit from parallel processing.
     
    NotaNaN, Lukas_Kastern and yant like this.
  46. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    Thanks for all the details, it certainly was an interesting read. Glad to see this is likely to become a real thing, I find it so useful and interesting! Looking forward to it, and love to read more on your research and discoveries.
     
    NotaNaN and yant like this.
  47. FissicsPeep

    FissicsPeep

    Joined:
    Jan 14, 2014
    Posts:
    79
    This looks very promising and something I'm extremely interested in making use of. I notice that the callback makes use of a NativeArray... does this mean it's limited to DOTS/ECS? I'm just using "standard" Unity at the moment for my project.

    EDIT: Seems NativeArray is not limited to DOTS/ECS... just a managed/unmanaged container.
     
    Last edited: Jan 9, 2021
    Prodigga likes this.
  48. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    What's the chance of getting a new experimental build on the non-beta version of unity? :D
     
    NotaNaN and Ruchir like this.
  49. rz_0lento

    rz_0lento

    Joined:
    Oct 8, 2013
    Posts:
    2,361
    If @yant is able to make this land on 2021.2, we probably see it next on upcoming alphas. I do hope it makes it as it would be awesome to be able to test this on actual builds too :)
     
    NotaNaN and Ruchir like this.
  50. Ruchir

    Ruchir

    Joined:
    May 26, 2015
    Posts:
    933
    It would really help with kinematic simulations like kinematic character controller and such
     
    NotaNaN, Gooren and yant like this.