Search Unity

  1. We are migrating the Unity Forums to Unity Discussions by the end of July. Read our announcement for more information and let us know if you have any questions.
    Dismiss Notice
  2. Dismiss Notice

Bug Bug with SphereCollider 3D physics, unnecessary Collisions created at collider edges.

Discussion in 'Physics' started by LaM0uette, Mar 3, 2024.

  1. LaM0uette

    LaM0uette

    Joined:
    Jun 2, 2022
    Posts:
    13
    Good morning,

    I'm making a 3D golf game and I'm facing a problem that seems impossible to solve.

    my game is simple, I have a ball with a `SphereCollider` and a `RigidBody`, and I apply a force with `Rigidbody.AddForce(force, ForceMode.Impulse)` to move my golf ball forward. Everything works very well on a plane, but the problem is that when I create my terrain with several blocks (cubes with `MeshCollider` or `BoxCollider`) then my ball starts to jump when it collides with the next surface, except they are all the same height, are the same size and there is no space between each block. The ball hits the normal faces and therefore jumps, likewise if the ball arrives too slowly on a wall, it does not bounce at all but stops abruptly or continues to follow the wall instead of bouncing.

    From what I understand, it comes from a problem linked to speculative contacts, but despite trying everything I could find, nothing does not work..

    my `mesh` are not `convex`, and I have already tried all the possible parameters for the `RigidBody` of the ball (`Interpolate` and `Collision detection`).

    I even tried to launch this project on github: https://github.com/swapnilrane24/Mini-Golf, it was made in version 2019 and seems not to have this problem, but by opening it with 2022 the problem is present...

    I partly solved this problem by resetting the Y velocity of the ball during a collision, but it doesn't work perfectly at all and it's a "crappy" solution.

    do you have any idea about this bug? I'll give you a gif to show you my problem:


    and if necessary, here is the link to my project on github (on the other hand, packages will be missing so not sure that the project will be able to launch): https://github.com/LaM0uette/CueGolf
     
    Last edited: Mar 3, 2024
  2. LaM0uette

    LaM0uette

    Joined:
    Jun 2, 2022
    Posts:
    13
    humm.. thanks to chatGPT I may have a solution but it needs to be tested, what do you think of this:

    Code (CSharp):
    1. private void OnCollisionEnter(Collision collision)
    2.         {
    3.             foreach (var contact in collision.contacts)
    4.             {
    5.                 if (!(contact.normal.y > 0.8f))
    6.                     continue;
    7.                
    8.                 var velocity = Rigidbody.velocity;
    9.                 velocity.y = 0;
    10.                 Rigidbody.velocity = velocity;
    11.             }
    12.         }
     
  3. LaM0uette

    LaM0uette

    Joined:
    Jun 2, 2022
    Posts:
    13
    oh well no... it doesn't work
     
  4. Qriva

    Qriva

    Joined:
    Jun 30, 2019
    Posts:
    1,356
    But do you have speculative enabled? Check 12:00
     
    Edy and codebiscuits like this.
  5. codebiscuits

    codebiscuits

    Joined:
    Jun 16, 2020
    Posts:
    118
    Hi,
    I'm not sure I correctly "read" your gif, and I don't know if this is a good solution, but it looks like a problem I'd had a while ago:
    https://twitter.com/biscuitsmitten/status/1135527874662936576
    I think I'm using discrete collision detection there.
    Ah, it's here too https://forum.unity.com/threads/ghost-collisions-on-adjacent-box-colliders.850951/ :)

    I feel like if you can, avoiding seams between colliders entirely is probably good, to make life easy for physics, and for yourself:).
    If you're feeling fancy, you can probably use contact modification to catch when it moves over a seam, and maybe reduce the depenetration impulse or modify the normal. I'm using contact modification to reduce depenetration impulse briefly when my car wheels go over small bumps at high speed.
     
  6. LaM0uette

    LaM0uette

    Joined:
    Jun 2, 2022
    Posts:
    13
    no changing the `discrete collision` parameters doesn't change anything, I've already tried everything. I also tried to modify the contacts, but it doesn't work.

    as Qriva said, my problem should be solved by activating speculative contact, but with this video I can't understand how to do it, I don't use havok or DOTS, and so there are things that I I don't have in my code..

    when I change the Physics.ContactModifyEvent, I just get weird behavior or my ball goes through walls/floor, and I still have my bug
     
  7. Qriva

    Qriva

    Joined:
    Jun 30, 2019
    Posts:
    1,356
    As far as I know speculative is just another option in detection mode.
    upload_2024-3-4_12-7-47.png
    What kind of mode you have?

    I am sadly no physics expert, so I am unable to tell you how to fix it or exactly why that happens
    (assuming it's not speculative).
     
  8. LaM0uette

    LaM0uette

    Joined:
    Jun 2, 2022
    Posts:
    13
    I am continuously, but in any case I have already tested all the modes, and the problem is the same each time, so it does not come from there or at least it is not enough to correct this bug
     
  9. Qriva

    Qriva

    Joined:
    Jun 30, 2019
    Posts:
    1,356
    All I know that (non convex) mesh colliders are kind of weird. I think never had such behaviour like yours, not so strong, but I remember similar things happen on connected edges in the past. However as I said, I am not expert, so you need different dude :D

    In any case I am also interested in how to solve this.
     
  10. codebiscuits

    codebiscuits

    Joined:
    Jun 16, 2020
    Posts:
    118
    Hi,
    So did you try discrete collision detection & edit->project settings->physics->default contact offset of 0.001?
    I've verified that this still "fixes" the issue from my tweet that I just reproduced in Unity 2021.3.33f1 & 2022.3.16f1 (attached: ball moves smoothly over stuff when you run it, hits invisible bumps if you switch back to default contact offset of 0.01). Of course, maybe your problem is different.

    I'm using Physics.ContactModifyEvent quite a bit in my game, it shouldn't make stuff worse if it's used correctly (unless you're unity version is not up to date, I had a bug that caused me problems in environments like yours that was fixed in 2021.3.33f1 (I'm staying off 2022.x as there seem to be other issues, but they probably won't affect you).
     

    Attached Files:

  11. LaM0uette

    LaM0uette

    Joined:
    Jun 2, 2022
    Posts:
    13

    thanks, but I have already modified the default contact offset, it doesn't change anything, and your example has the same problem, we're just not in the same configuration.
    if we replace the planes with cubes, apply rb.AddForce only once, and reduce the size of the ball, then the same problem arises. now, the solution is perhaps to modify the scale of the ball to avoid this problem, I would have to do tests with a scale of 1 or even 2. I give you your project with the modifications that I made to correspond to my example, and you will notice the same bug
     

    Attached Files:

  12. LaM0uette

    LaM0uette

    Joined:
    Jun 2, 2022
    Posts:
    13
    by putting a scale of 1 on the sphere, it seems to work correctly, but that doesn't suit me because it forces me to modify all my objects... and it's not said that it works 100% either.

    correction, I had the problem even with the scale of 1, as I enlarged the cudes in fact it comes to the same thing. It just seems a little less common...
     
  13. codebiscuits

    codebiscuits

    Joined:
    Jun 16, 2020
    Posts:
    118
    Ok, I had a go with your project and put this script on the ball:
    Code (CSharp):
    1. using Unity.Collections;
    2. using UnityEngine;
    3.  
    4. public class GhostCollisionCatcher : MonoBehaviour {
    5.  
    6.     private void OnEnable() {
    7.         Physics.ContactModifyEvent += ModificationEventDCD;
    8.         Physics.ContactModifyEventCCD += ModificationEventCCD;
    9.         GetComponent<Collider>().hasModifiableContacts = true;
    10.     }
    11.  
    12.     private void OnDisable() {
    13.         Physics.ContactModifyEvent -= ModificationEventDCD;
    14.         Physics.ContactModifyEventCCD -= ModificationEventCCD;
    15.     }
    16.     private void ModificationEventDCD( PhysicsScene scene, NativeArray<ModifiableContactPair> pairs ) {
    17.         ModificationEvent( pairs );
    18.     }
    19.     private void ModificationEventCCD( PhysicsScene scene, NativeArray<ModifiableContactPair> pairs ) {
    20.         ModificationEvent( pairs );
    21.     }
    22.     private void ModificationEvent( NativeArray<ModifiableContactPair> pairs ) {
    23.  
    24.         foreach ( var pair in pairs ) {
    25.             for ( int i = 0; i < pair.contactCount; ++i ) {
    26.                 pair.SetNormal( i, Vector3.up );
    27.             }
    28.         }
    29.     }
    30. }
    31.  
    This fixes the ghost contact (caused by a "bad" normal) in the example scene you sent me (& defaultContactOffset can be 0.01 again:).
    Of course, it's not a good general-case solution right now.
    But hopefully you should be able to modify it to detect bad contacts (the one in your scene was when FixedUpdate ran while the ball was right on top of a collider edge) and apply the appropriate normal. If you have simple geometry in your scene, you can maybe read the face-normal from the surface the ball's colliding with and always apply that, or maybe keep some collider/normal dictionary or something.
    If you can at all though, I'd try and avoid having adjacent colliders. I don't think a single continuous collider, e.g., like ProBuilder produces, has this problem at all.
     
  14. LaM0uette

    LaM0uette

    Joined:
    Jun 2, 2022
    Posts:
    13
    thank you, it's an interesting idea, the problem is that we're going through walls now and the problem still happens even if it's mitigated, but I'm going to dig a little to see.
    and regarding having only one mesh, that would solve the problem yes but impossible in my case, I plan to create a level editor, and I can't see myself combining all the meshes each time
     
  15. LaM0uette

    LaM0uette

    Joined:
    Jun 2, 2022
    Posts:
    13
    I find it crazy that such a bug is present in Unity with no simple solution to correct it, yet they are well aware of the problem...
     
  16. LaM0uette

    LaM0uette

    Joined:
    Jun 2, 2022
    Posts:
    13
    I think I found something pretty good, it's not 100% perfect but clearly it works well in 95% of cases which is already very good, I added a MonoBehaviour script on my ball, I modify the `ContactModifyEvent` and ignore the contacts by getting the separation distance at the ith contact point. If this distance is greater than 0, it means that the objects are not overlapping at this point of contact and therefore the physics system will act as if the two objects were not colliding at this point, even if they were .

    here is the code :
    Code (CSharp):
    1. using Unity.Collections;
    2. using UnityEngine;
    3.  
    4. namespace Game.Modules.Player
    5. {
    6.     public class GhostCollisionCatcher : MonoBehaviour {
    7.         private void OnEnable()
    8.         {
    9.             Physics.ContactModifyEvent += ModificationEventDCD;
    10.             Physics.ContactModifyEventCCD += ModificationEventCCD;
    11.          
    12.             GetComponent<Collider>().hasModifiableContacts = true;
    13.         }
    14.         private void OnDisable()
    15.         {
    16.             Physics.ContactModifyEvent -= ModificationEventDCD;
    17.             Physics.ContactModifyEventCCD -= ModificationEventCCD;
    18.         }
    19.      
    20.         private static void ModificationEventDCD( PhysicsScene scene, NativeArray<ModifiableContactPair> pairs )
    21.         {
    22.             ModificationEvent( pairs );
    23.         }
    24.      
    25.         private static void ModificationEventCCD( PhysicsScene scene, NativeArray<ModifiableContactPair> pairs )
    26.         {
    27.             ModificationEvent( pairs );
    28.         }
    29.      
    30.         private static void ModificationEvent( NativeArray<ModifiableContactPair> pairs )
    31.         {
    32.             foreach ( var pair in pairs )
    33.             {
    34.                 for ( var i = 0; i < pair.contactCount; ++i )
    35.                 {
    36.                     if (pair.GetSeparation(i) > 0)
    37.                         pair.IgnoreContact(i);
    38.                 }
    39.             }
    40.         }
    41.     }
    42. }
    It's not perfect but at the moment I don't think I could have anything better
     
  17. codebiscuits

    codebiscuits

    Joined:
    Jun 16, 2020
    Posts:
    118
    You'll be going through walls right now because I hardcoded the normal to "up", if you set the normal correctly for every collision, it should fix this. If the problem's still happening it might be good to step through frame by frame with the physics debugger on to see the impulses and normals. This is how I saw the original problem was to do do with a "bad" normal. The bad normal was causing this huge vertical impulse, so clamping vertical impulse might also help.

    I'm not sure it's a bug exactly, although of course it's bad news of you want to skate over colliders like this. I'm no expert, but I think this stuff is all handled by PhysX, from my reading of the PhysX documents it feels like everything is kindof "mostly ok" provided you obey various constraints. Like, the PhysX WheelCollider is ok for regular vehicles and roads but doesn't really work well for stunt driving. Joints are ok but can be bad with large body to body mass ratios. I guess collider edges like this are hard work for collision detection. I've spent the last year or so part-time patching around stuff that the physics doesn't quite get right for my specific edge-cases. It's ok tho, I'm happy that PhysX is doing most of the heavy lifting
     
    LaM0uette likes this.
  18. codebiscuits

    codebiscuits

    Joined:
    Jun 16, 2020
    Posts:
    118
    Ah, nice! You posted while I was writing my last reply glad it's mostly working now
     
    LaM0uette likes this.
  19. codebiscuits

    codebiscuits

    Joined:
    Jun 16, 2020
    Posts:
    118
    I think actually what you've done there is effectively set the default contact offset to float.epsilon. I wonder if cranking up the fixed timestep will also help..
     
  20. LaM0uette

    LaM0uette

    Joined:
    Jun 2, 2022
    Posts:
    13
    it's possible but I prefer to avoid touching this kind of parameters
     
  21. LaM0uette

    LaM0uette

    Joined:
    Jun 2, 2022
    Posts:
    13
    Well, the victory was short-lived... the bug is still there, when you throw the ball in the air, once it falls it does this mini jump almost all the time. this bug I can't take it anymore
     
  22. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    8,432
    You have to remember that Unity is using the Nvidia PhysX physics engine in 3d contexts. Ghost collisions are a well understood phenomenon in a number of physics engines.

    The simplest solution is to just change the Default Contact Offset to something like 0.001 and be done with it. That's what I did when I played around with a ball rolling puzzle game.
     
    codebiscuits likes this.
  23. LaM0uette

    LaM0uette

    Joined:
    Jun 2, 2022
    Posts:
    13
    thank you but no, I have already modified the Default Contact Offset, and that does not solve my problem, it just alleviates it a little as said above