Search Unity

Rigidbody.SweepTestAll() not detecting Colliders occasionally.

Discussion in 'Physics' started by Phedg1, Oct 6, 2019.

  1. Phedg1

    Phedg1

    Joined:
    Mar 3, 2015
    Posts:
    113
    This is going to be a long post, so please bear with me. I first encountered this issue a long time ago. I made a post about it then but wasn't able to resolve it. I have since gathered some more details about it and I hope that this time I can make some progress.

    My game doesn't use the built in physics system, instead characters perform a SweepTest in a given direction before updating their position with
    Code (CSharp):
    1. transform.position += moveVector;
    . This allows me to keep them nicely aligned to grid spaces, which is necessary for my puzzle game. Sometimes when playing my game, a character will fall through a piece of floor. Other characters or objects are able to move over the same piece of floor without any issues, it seems to be a special relationship between just the two objects, seemingly selected at random. It does not always effect the same character and it does not always effect the same piece of floor. It does not matter which direction the character approaches the floor from, or how it is positioned relative to the floor. Because of the given number of pieces of floor (or walls or other objects) as well as characters, I only stumble across it once in a blue moon. It can be months between when I happen upon it (I spend a lot of time developing but not a lot of time playing). Starting a new game in the application through the menus, restarting the application (if it is a built version) or exiting play mode (if it is in the editor) all fail to reproduce the issue in the same way. Again, it seems to happen seemingly at random.

    This means that if I want to do some debugging I need to have it all coded before the current execution, because editing any scripts causes them to recompile and causes errors in the current session.

    My game build the puzzle map by additively scene loading multiple puzzle rooms. I do not know if this could be a factor, but I will mention it anyway.

    My character is has a scale of (100, 200, 100) and has a move speed of 20. His box Collider is set at a scale of (0.99, 0.99, 0.99). He also has a kinematic rigidbody. The top of the floor is at a height of 0, and its box Collider has the equivalent scale of (1, 1, 1). The character normally sits at positional height of 100 and his origin is in his center. This means that his base should always be about 1 above the floor, meaning that his base should never align perfectly with the floor preventing floating point error overlap. This also means that a SweepTest with a magnitude of 20 downwards should pick up the floor without issue.

    Character Inspector: https://i.imgur.com/c4detlv.png
    Floor Inspector: https://i.imgur.com/fQFotn7.png

    Using some debugging I logged the results of every downwards SweepTest, here is the code and the results.
    Code (CSharp):
    1. RaycastHit[] hitThings = GetComponent<Rigidbody>().SweepTestAll(moveVector, moveVector.magnitude, QueryTriggerInteraction.Ignore);
    2. Debug.Log(gameObject.transform.position);
    3. Debug.Log(moveVector);
    4. Debug.Log(moveVector.magnitude);
    5. Debug.Log(hitThings.Length);
    6. foreach (RaycastHit hitThing in hitThings) {
    7.     Debug.Log(hitThing.collider.name);
    8.     Debug.Log(hitThing.collider.tag);
    9.     Debug.Log(hitThing.collider.transform.parent.name);
    10.     Debug.Log(hitThing.collider.transform.root.name);
    11.     Debug.Log(hitThing.distance);
    12.     Debug.Log(hitThing.collider.transform.position);
    13. }
    14. Debug.Log("--------");
    Code (CSharp):
    1. (-2370.0, 100.0, -4050.0)
    2. (0.0, -20.0, 0.0)
    3. 20
    4. 1
    5. Piston
    6. Piston
    7. WalkwayExtendedEast
    8. Tier1Room-
    9. 1.252515
    10. (-2450.0, -50.0, -4000.0)
    11. --------
    12. (-2350.0, 100.0, -4050.0)
    13. (0.0, -20.0, 0.0)
    14. 20
    15. 0
    16. --------
    17. (-2350.0, 80.0, -4050.0)
    18. (0.0, -20.0, 0.0)
    19. 20
    20. 0
    21. --------
    22. (-2350.0, 60.0, -4050.0)
    23. (0.0, -20.0, 0.0)
    24. 20
    25. 0
    26. --------
    27. (-2350.0, 40.0, -4050.0)
    28. (0.0, -20.0, 0.0)
    29. 20
    30. 0
    31. --------
    32. (-2350.0, 20.0, -4050.0)
    33. (0.0, -20.0, 0.0)
    34. 20
    35. 0
    36. --------
    The character starts on top of something solid. As soon as he moves 20 to the right he is now solely over the floor in question. As you can see the SweepTest does have any hits detected.

    In a separate bit of debugging I did a Physics.OverlapBox() test on the character, to determine if the character begins inside the piece of floor in question. Here are those results.
    Code (CSharp):
    1. Debug.Log(trasform.position);
    2. Debug.Log(transform.scale * 0.99f);
    3. Collider[] overlapping = Physics.OverlapBox(gameObject.transform.position, transform.scale * 0.99f / 2f);
    4. foreach (Collider currentCollider in overlapping) {
    5.     if (currentCollider.tag != "Character") {
    6.         Debug.Log(currentCollider.tag);
    7.         Debug.Log(currentCollider.transform.position);
    8.         Debug.Log(currentCollider.transform.root.position);
    9.      
    10.     }
    11. }
    12. Debug.Log("--------")
    Code (CSharp):
    1. (-2370.0, 100.0, -4050.0)
    2. (99.0, 198.0, 99.0)
    3. --------
    4. (-2350.0, 100.0, -4050.0)
    5. (99.0, 198.0, 99.0)
    6. --------
    7. (-2350.0, 80.0, -4050.0)
    8. (99.0, 198.0, 99.0)
    9. Fixture
    10. (-2250.0, -75.0, -4000.0)
    11. (-4000.0, 0.0, -4000.0)
    12. --------
    13. (-2350.0, 60.0, -4050.0)
    14. (99.0, 198.0, 99.0)
    15. Fixture
    16. (-2250.0, -75.0, -4000.0)
    17. (-4000.0, 0.0, -4000.0)
    18. --------
    19. (-2350.0, 40.0, -4050.0)
    20. (99.0, 198.0, 99.0)
    21. Fixture
    22. (-2250.0, -75.0, -4000.0)
    23. (-4000.0, 0.0, -4000.0)
    24. --------
    25. (-2350.0, 20.0, -4050.0)
    26. (99.0, 198.0, 99.0)
    27. Fixture
    28. (-2250.0, -75.0, -4000.0)
    29. (-4000.0, 0.0, -4000.0)
    30. --------
    31. (-2350.0, 0.0, -4050.0)
    32. (99.0, 198.0, 99.0)
    33. Fixture
    34. (-2250.0, -75.0, -4000.0)
    35. (-4000.0, 0.0, -4000.0)
    36. --------
    37. (-2350.0, -20.0, -4050.0)
    38. (99.0, 198.0, 99.0)
    39. Fixture
    40. (-2250.0, -75.0, -4000.0)
    41. (-4000.0, 0.0, -4000.0)
    42. --------
    43. (-2350.0, -40.0, -4050.0)
    44. (99.0, 198.0, 99.0)
    45. Fixture
    46. (-2250.0, -75.0, -4000.0)
    47. (-4000.0, 0.0, -4000.0)
    48. --------
    49. (-2350.0, -60.0, -4050.0)
    50. (99.0, 198.0, 99.0)
    51. Fixture
    52. (-2250.0, -75.0, -4000.0)
    53. (-4000.0, 0.0, -4000.0)
    54. --------
    55. (-2350.0, -80.0, -4050.0)
    56. (99.0, 198.0, 99.0)
    57. Fixture
    58. (-2250.0, -75.0, -4000.0)
    59. (-4000.0, 0.0, -4000.0)
    60. --------
    61. (-2350.0, -100.0, -4050.0)
    62. (99.0, 198.0, 99.0)
    63. Fixture
    64. (-2250.0, -75.0, -4000.0)
    65. (-4000.0, 0.0, -4000.0)
    66. --------
    67. (-2350.0, -120.0, -4050.0)
    68. (99.0, 198.0, 99.0)
    69. Fixture
    70. (-2250.0, -75.0, -4000.0)
    71. (-4000.0, 0.0, -4000.0)
    72. --------
    73. (-2350.0, -140.0, -4050.0)
    74. (99.0, 198.0, 99.0)
    75. Fixture
    76. (-2250.0, -75.0, -4000.0)
    77. (-4000.0, 0.0, -4000.0)
    78. --------
    79. (-2350.0, -160.0, -4050.0)
    80. (99.0, 198.0, 99.0)
    81. Fixture
    82. (-2250.0, -75.0, -4000.0)
    83. (-4000.0, 0.0, -4000.0)
    84. --------
    85. (-2350.0, -180.0, -4050.0)
    86. (99.0, 198.0, 99.0)
    87. Fixture
    88. (-2250.0, -75.0, -4000.0)
    89. (-4000.0, 0.0, -4000.0)
    90. --------
    91. (-2350.0, -200.0, -4050.0)
    92. (99.0, 198.0, 99.0)
    93. --------
    94. (-2350.0, -220.0, -4050.0)
    95. (99.0, 198.0, 99.0)
    96. --------
    These results indicate that the character is not overlapping with the floor in any way, until it has started falling through it.

    My character is kinematic. Making it non kinematic and enabling gravity will cause the character to come to rest on the offending piece of floor. This, combined with the Physics.OverlapBox() results show that the physics system is detecting the floor, just now the SweepTest.

    I tried moving the piece of floor variously up and down slightly, the character still passed through. I tried moving the piece of floor to chest height so the character could approach it from another angle. Still, the the character was able to move through the object, but no other objects or characters could.

    Character through object: https://imgur.com/VwbUfUx

    I copied and pasted the piece of floor. My character was not able to phase through this new object and the debugging showed this as well. Even though the copied object had the exact same properties and values, collisions were now being detected with the SweepTest.

    Adding another box Collider to the floor also prevented my character from falling through it. So did adding another box Collider to my character. I think that something is wrong with these two particular instances of these Colliders, adding a new Collider or copying the object was creating a new Collider component instance and that new instance presumably has the same "once in a blue moon" chance of having this glitch.

    Lastly, I tried resetting each of the components on the offending piece of floor. This didn't yield any results, the character was still able to pass through it.

    Although it happens rarely, this can cause a big problem in a game. The player with the effected character could be forced to restart his game. Being unable to cross certain sections of floor can make many games unfinishable. The other players can not finish the game without every player present, so they would be interrupted as well.

    This seems to me to be a problem with Unity, not with my code. If anybody knows of a Unity staff member in these forums, could they please tag the staff member? I think that would go a long way to narrowing in on this issue.

    My theory: Although I have only experienced this issue between one of my characters and another object, I would hazard a guess that it is possible for this issue to occur between any two objects. Seeing as I only happen upon it once every couple of months and seeing as my characters are the objects which most often come into contact with other objects, I doubt I'm likely to ever experience this. This problem seems to link two Collider instances together and I imagine that there is a very slight chance that any two Colliders will have this relationship.

    Unity 2018.4.9f1 Personal LTS.
    Physics settings: https://imgur.com/pKI7Q07
     
    Last edited: Oct 6, 2019
  2. canis

    canis

    Joined:
    Oct 25, 2013
    Posts:
    79
    Seem like you trying to develop your game in a hard way.
    anyway, if you use `Rigidbody.SweepTest` and sometime return nothing.
    since they should using the same engine for AABB test, Raycast issue should able to reproduce with SweepTest.

    Let A & B are the different rigidbody with collider attach on it.
    Beware the following issues.
    • If A and B already overlapped, the raycast methods will not return any collision. it's by design.
      they are overlapped already, you won't get the hit result by "Cast" type.
    • if A or B somehow have ZERO unit (no size), you may randomly get the wrong hit point.
    • since you use "QueryTriggerInteraction.Ignore" if one of them is "Trigger", those will be ignore.
    if you confirm the above cases were not the issues,
    perhaps it's the problem within your script logic.

    For example.
    the way you used to OverlapBox to debug the Rigidbody.SweepTest was wrong.
    Code (CSharp):
    1. Collider[] overlapping = Physics.OverlapBox(gameObject.transform.position, transform.scale * 0.99f / 2f);
    two problems
    • It's not your character's size, it's another BOX test. you need to use the one Exactly matching your Rigidbody's mesh.
    • can't prevent or detect the A & B overlap issue on time, e.g. same frame, same update().
    consider to use Physics.ComputePenetration it's the API to locate overlapping and return the depenetration vector if overlapped. (Warning it's costly !)
    if you API not enough for you to prevent the issue, perhaps my study can give you some idea.

    Since I also develop my character without using gravity like yours
    I can tell : the way you use the console to debug and log coordinate and vector as result will confuse yourself.
    my advise to debug those things are using Gizmos / Debug.DrawLine ....etc,

    Don't use numbers, use image, draw it on screen !!

    some WIP video may help you to understand how important to visualize the error in editor.
     
    Last edited: Oct 11, 2019
  3. Phedg1

    Phedg1

    Joined:
    Mar 3, 2015
    Posts:
    113
    In my game the BoxCollider for my character is slightly smaller than his mesh, 99% the size of his mesh to be exact. I introduced this to prevent any possible overlap. This would have made difference of 1 unit between the base of the character and the floor. Because his movement step size is 20, he would never move closer than that to the Collider. When I last encountered this issue I tried moving the floor closer and further away from the character by a couple of units. Because this still would have been smaller than the step size it should not have triggered another movement. Still the SweepTest did not detect the floor. As you can see in the screenshots of my OP, neither the floor nor the character had a size of 0 and neither Collider was a trigger.

    For the OverlapBox test the formula is Physics.OverlapBox(Vector3 centerOfTheBox, Vector3 halfSizeOfTheBox). Because the size of my Collider is based on the scale of the mesh, I wrote in that exact formula. 99% of the scale divided by 2, because the function requires a half size. That being said, I will give your Physics.ComputePenetration the next time I encounter this issue. I do not mind that it is costly, I only need to debug a few frames to record the results. This debugging is not running constantly in my game, it's something I can enable in the inspector when I come across the issue, then disable as soon as I have walked my character through the floor. Otherwise the game would be barely responsive.

    I like your on screen debugging suggestion and I may use it for some other errors. However, the critical interaction for this issue passes by so quickly during a FixedUpdate that I would rather just process the information in a log, one frame at a time. That way I can dissect it at my leisure, regardless of how often the screen is rendered.

    Before ending the play session where I encountered this issue, I opened a new Unity instance and tried to write a simple script to replicate the problem. The setup was the same, one box with a Collider slightly smaller than its mesh (to prevent overlap), performing SweepTests downwards, with another box with a Collider below it. The box below was a prefab and between each test the box below was destroyed and reinstantiated. This didn't work. For the next test I deleted that prefab and instead saved the box below as its own scene. I would load this scene additively, do a SweepTest downwards from the box above, then unload the box. I was able to reproduce this issue twice (out of about 50,000 tests), where a SweepTest doesn't detect a Collider, before Unity crashed. It crashed all open instances, so it closed my game session as well. When loading scenes additively you need to remember to garbage collect when you unload them and my memory had reached capacity. After I restarted the editor though, I was not able to produce it any more.

    What I suspect is that the additive scene loading is a crucial factor in reproducing this error, but it's clear it is not the only one. Something happened when Unity closed to prevent this issue occurring for now. I have said before that this issue only seemed to occur once in a blue moon, once every several months, so I suspect I will have to wait a while before I get lucky enough again. I tend to leave my computer on for extended periods, and I tend to leave Unity sessions open for extended periods as well. Perhaps those extended sessions contribute as a factor. Perhaps my log had grown too extensive? Perhaps it just needed to clear its cache? I'm not too sure.

    I hope I didn't come across as harsh, I'm really thankful for your reply because you're the only one who has offered one. Thank you. I'm planning on adding your Physics.ComputePenetration test shortly.