Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Bug Lowering the Physics 2D Default Contact Offset causes Box Casts to fail completely

Discussion in 'Physics' started by Kybernetik, May 18, 2021.

  1. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,555
    I reported this as a bug and was asked to move the discussion here.

    TL;DR: it can't be fixed and you should never change the Default Contact Offset (but Unity's documentation doesn't tell you that).

    The setup is very simple. I have a 1m cube in the scene with a BoxCollider2D on it and I do a 1m size Physics2D.BoxCast directly towards it as shown in this diagram:
    Diagram.png
    1. With the Default Contact Offset in the Physics2D settings set to the default 0.01, the cast hits the cube as expected.
    2. But with the offset set to 0.001, the cast always fails to hit anything anywhere in the scene.
    3. The only exception to that is if the object is overlapping the box cast's origin area or very close to it. With the origin at x=1.004 it hits but at x=1.005 or further it misses. I'm not sure why the threshold would be 4x the contact offset, but I don't really care about that, the problem is #2.
    I don't understand how an offset value of 0.01 vs. 0.001 could affect this situation so drastically that the check fails completely with the latter but not the former. I get that it can't easily be fixed, I just don't see how that behaviour is possible in the first place.

    And since it can't be fixed, that means it needs to be documented, but of course it's not.

    According to @MelvMay, the Default Contact Offset "should NEVER be changed unless you know exactly how it affects stuff which is polygon collision which is what not only BoxCast is but many other aspects. Some subtle, some performanc and some gross problems such as yours."

    That information could have saved me several hours of frustration, yet it isn't even hinted at by the Unity Manual or API Documentation pages that talk about the Default Contact Offset.
     
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,321
    I actually don't know why the warning in the tooltip for that setting is not part of the docs for Physics2D.defaultContactOffset. If you hover over the setting, it gives you the warning. I'll request that be added to that property API page. It has been talked about again and again on these forums for sure.

    In your bug report, we tried to give you a comprehensive reply to why this is happening on Box2D including source links to the parts that fail here and I appreciate you don't understand from your simplified image above but that unfortunately doesn't represent what it's doing at all.

    Box2D doesn't provide the functionality above out of the box. You have to find the time-of-impact first then at that position, use it to calculate contact points for the shape(s) at that position. With tiny contact offsets it can fail on poly/poly collisions but it's unpredictable because it's coming down to tiny fractions. In your case, it's 0.001 out and the collision algorithms say there's no contact. Unfortunately it requires a contact margin and while you say there's not much difference in your values, it's an order of magnitude less than the Box2D one which is a compile-time constant.

    With a contact margin too low you get a time-of-impact that's reasonably accurate however often it mismatches contacts and fails here.

    How could we fix it? Well, when we get a time-of-impact we could inflate the shape until we contact but that proves problematic because we often find other contacts too that don't match the time-of-impact. Also, this is basically just doing what contact offset does by artifically inflating the shape so we're fighting ourselves at this point.

    I've often wondered whether we should actually allow this after exposing it as a runtime property many years ago TBH.

    So maybe this is TLDR but it's what is happening. There's no magic fix-it apart from not reducing the contact offset by an order of magnitude. What's not been addressed here is WHY you are making such a large change?
     
    Kybernetik likes this.
  3. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,321
    I will add that related to another change there is a "fudge" for this behaviour which occurs elsewhere that would help here where we progressively advance the time-of-impact until we get a contact but unfortunately, this can become prohibitively expensive too because it's then pretty much the same as continuous collision detection where it's doing an iterative refinement. Users changing the above setting by such a large margin would find certain queries become costly.

    Also, we'd be doing that in key queries we created in Unity, not Box2D so the other instabilities would still be there.

    We'll get that warning from the tooltip added to the API reference for that ASAP.
     
    Kybernetik likes this.
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,321
    Final note: If you add a CircleColider2D as your target here I believe the BoxCast will work fine, showing it's not an inherent problem with the BoxCast call itself. The problem mainly lies in poly/poly detection in Box2D where the polygon radius (contact offset) is too small.
     
    Kybernetik likes this.
  5. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,555
    Thanks for the explanation.
    I didn't see the tooltip, I just looked it up in the docs. Given how strongly you're recommending against changing the setting, it seems like it would be a good idea to add a HelpBox that appears when it's changed to make it as clear as possible that there are dangers. Or even a dialogue box confirmation when you attempt to change it.
    I saw that a 1m box falling onto a 1m box leaves a visible gap:
    upload_2021-5-19_11-13-14.png
    So I went looking for a solution and found suggestions to either reduce the contact offset or go through every collider I ever set up and make it a tiny bit smaller than the visuals. It seemed like a no-brainer and everything was fine until later when I started trying to use box casts.

    The comment for b2_linearSlop on the page you linked says the value was chosen to be "visually insignificant", but that gap with default size boxes and the default contact offset is really obvious.

    And I actually changed it to the minimum 0.0001 because the documentation gives no guidance on what constitutes a reasonable value or what else it affects, all I had to go on was that an offset of 0.01 gives those boxes a gap of 0.014932 which is about 1.5x the offset, so I figured 1.5 x 0.0001 would be preferable.

    Though I never actually looked at the gap with the offset at 0.0001 before. Turns out it actually lets them overlap slightly (by -0.0049165). So I started trying to narrow it down and found that a contact offset of 0.0025648 gives no gap or overlap (or slightly off due to floating point error if the boxes aren't right at the origin).
    Yep, I just tested that and it always hits the circle properly.
     
  6. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,321
    Because it cannot. Rotate stuff slightly and your value will be fine. Use other queries and other stuff and it'll be fine but somewhere you'll encounter a problem. If there were a lower limit, we'd clamp to it and document it. This is the inherent problem in that it gets increasingly undefinably unstable. This is Box2D.

    That's actually a great idea.

    Sorry for the hassle this has caused you. I think it's been around for so long that it's just got left as is. Improving the warnings will help but unfortunately not solve it.
     
  7. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    2,555
    Even if it can't give an exhaustive list of exact effects, it can still provide useful guidance such as:
    • Higher values will increase the gap between colliding objects.
    • It's not just a simple addition. Changing from 0.01 to 0.001 won't just reduce the gap by 0.009.
    • Area casts can fail unexpectedly if it's too low.
    • It doesn't affect raycasts, circles, or overlap queries.
    • The lowest allowed value is 0.0001, but even at 0.001 area casts are basically guaranteed to fail.
     
  8. SamOld

    SamOld

    Joined:
    Aug 17, 2018
    Posts:
    333
    @MelvMay these docs still aren't fixed.