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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

Modify Contact Normal While Preventing Overlaps

Discussion in 'Physics for ECS' started by Leonardo_Temperanza, Nov 30, 2020.

  1. Leonardo_Temperanza

    Leonardo_Temperanza

    Joined:
    Aug 18, 2014
    Posts:
    7
    I started experimenting with the IContactsJob and PostCreateContacts callback to see if it was possible to set a custom depenetration direction which could be useful to prevent characters from sliding down slopes, for instance.
    I looked at the "ModifyNarrowphaseContacts" scene in the physics sample scenes, but I've noticed that trying to increase the "steepness" of the contact normals while keeping the same collision shapes eventually leads to the bodies falling through the static collision, as the body thinks the slope is much steeper than it actually is. Initially, I thought it was simply because of the way the ModifyNarrowphaseContactsBehaviour system modifies the contact distance:

    Code (CSharp):
    1. distanceScale = math.dot(newNormal, contactHeader.Normal);
    2. contactPoint.Distance *= distanceScale;
    The following image explains the effect I'm trying to achieve.

    Pushback Behaviour Image.png

    In this image, the orange arrow is the desired pushback direction, the red box is the current position of the test entity, the purple box represents the final calculated position of the body, and the green and blue arrows are the unmodified and modified contacts respectively.
    It's possible to get the length of the blue vector like this:

    Code (CSharp):
    1. ContactPoint.Distance = ContactPoint.Distance / Dot
    Where Dot is the dot product of the desired pushback direction and the collision normal.
    I created a simple system that adds a downwards force to all test bodies, sets their InverseIntertia to zero to lock their rotation, and modifies the header's normal and contact distance like I previously described, but the increased contact distance didn't seem to have any impact on the amount of pushback the test entity got. Moreover, setting the distance to an even greater value for testing purposes (like multiplying it by 10) will push the object harder along the new normal direction, but there will always be an initial overlap.
    I'm testing this with an entity that has a box physics shape with no bevel radius and a dynamic physics body with everything set to 0 except for mass which is set to 1, and another static box physics shape with no bevel radius set up like in the image. Both have 0 friction and 0 restitution, and I'm using UnityPhysics, not Havok.
    Is there something I'm missing? There's not much documentation on this, but from what I was able to gather from looking at the sample scenes and a bit of testing:
    • Changing the contact.Position value has no effect on the collision if the body can't rotate
    • The contact.Distance value affects how much the object will get pushed along the header.Normal direction, though I still don't understand why it can be positive as well as negative. Positive distance means the 2 entities are not even touching each other so the contact can just be ignored entirely right? Whether contact.Distance actually changes the position or just the body's velocity is still unclear to me.
    Is this all correct? Is this kind of custom collision behavior even possible using the simulation callbacks or would it be much faster to write a custom contact solver instead?
     

    Attached Files:

  2. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    I'd like to take a step back and try to guide you in a different direction. Tweaking a physics engine solver to achieve custom character behaviors is a hard job. Solver is not modifiable easily for a number of reasons, including stability and performance. However, there are some neat tricks you can use to achieve custom character behavior.

    1. You could make your character just a collider and drive it using collider casts. That's what the https://github.com/Unity-Technologi...Assets/Demos/6. Use Cases/CharacterController is doing. While this one is probably overcomplicated to achieve many use cases, you can strip it down to only the things you need. It boils down to shooting collider casts in the desired direction, feeding the results into the simplex solver, and applying new velocities after solve. It also allows for adding custom constraints, so in your case you could just add another plane and make sure character de-penetrates in the direction you want.
    2. For a simpler use case, you could also introduce a basic support check, and not apply gravity on character if it is supported. This will effectively give non-sliding if character is grounded.

    Let me know if any of these work for your case!
     
  3. Leonardo_Temperanza

    Leonardo_Temperanza

    Joined:
    Aug 18, 2014
    Posts:
    7
    Thank you for your quick reply!

    I'll definitely look into the character controller in the sample scenes, and I do agree that solution n.2 can work in very specific instances, but that was just one of the many use cases for a custom depenetration direction! For example, I might want to always ignore the vertical component of a wall normal, to prevent the player from exploiting the vertical push and getting more height out of a jump.
    The character controller uses collider casts, but I'm guessing simple overlap checks and distance queries could also be used for non-continuous collision detection? I would assume there are pros and cons for both of these approaches. For example, what happens if the controller still collides with a surface, even after applying the new velocities given by the simplex solver? To make sure that the collider never overlaps with anything, it would require a recursive approach in which each new movement must be checked with a collider cast, wouldn't it?

    Regarding the non-continuous approach, I've created a script, without Unity Physics or ECS, that collects the collision information with all of the surrounding GameObjects. The script uses a Physics.OverlapSphere that encloses the entire object's collider shape to get a list of potentially intersecting objects, calls Physics.ComputePenetration for each one and finally moves the object accordingly. This works well when dealing with convex colliders, though because of the fact that the aforementioned methods only provide one contact per collider it wouldn't work well for concave mesh colliders.
    Is it possible to get all of the colliding triangles of a mesh and get the distance to each one? This could also be useful for ground-detection. For example, if a character is touching both a "ground" triangle and a "wall" triangle a simple cast or distance query would only detect the nearest one, while completely ignoring the other one.
     
  4. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    Regarding first part, yes, that's why we do it iteratively. You cast a collider, solve hits, then integrate, cast again, and so on... Definitely check the sample!

    Regarding the second part, you can use PhysicsWorld.CalculateDistance() with the "all hits" variant that gives you all hits within a radius. Also collects multiple hits from the same object if it's a mesh or a compound. Queries have 3 modes - all hits, closest hit and any hit. Use each of these when appropriate.
     
  5. Leonardo_Temperanza

    Leonardo_Temperanza

    Joined:
    Aug 18, 2014
    Posts:
    7
    Wow that's really cool! I've always been kind of frustrated by the low level of customization of the physics engine and collision queries, so discovering this new way to do things is exciting to say the least. It's definitely worth learning ECS and data oriented design, for me at least. Thanks again!
     
    petarmHavok likes this.