Search Unity

Getting the normals of the surfaces at a collision point.

Discussion in 'Physics' started by Tudor, May 17, 2018.

  1. Tudor

    Tudor

    Joined:
    Sep 27, 2012
    Posts:
    150
    I have a tool that hits an object. I need to do stuff based on the angle of the surface of that tool at the collision point, and the normal of the surface of the object at the collision point.

    What's the best way to do that? Not entirely sure what `other.contacts[0].normal` does, but it doesn't seem to be what I need.

    Can I somehow pick some ClosestPoints to calculate normals? Is that slow? Do I pick 2 random points?
    Should I split my mesh colliders into a large array of small box colliders so I'd easily guess their normals?
    Should I iterate over collider mesh vertices to find the ones near the collision point? (slow!?)
    Should I say screw the physics system and just do this on the GPU entirely instead (e.g. compute)?

    [Edit]
    Ok I verified that the `other.contacts[0].normal` is pretty much the normal of the object you've collided with. But I don't know how to get the normal of my own object.
     
    Last edited: May 18, 2018
  2. Tudor

    Tudor

    Joined:
    Sep 27, 2012
    Posts:
    150
    I have 2 solutions that seem to be the fastest and most unity-agnostic ways to do it.

    1. If you can afford to have a rigidbody on both your tool and any of your target objects, then do that and have an `OnCollisionEnter` event on both of them. On each, you can get the `other.contacts.normal`. This is awkward to rig together software-architecture-wise, but it would work.

    2. What I ended up doing, was vector math.
    - I only used the `OnCollisionEnter` event in my tool object, and I get the target object's surface's normal via `other.contacts.normal`.
    - Then I swizzle this normal to get a second somewhat random vector:

    swizzledNormal.x = other.contacts[i].normal.z;
    swizzledNormal.y = other.contacts[i].normal.x;
    swizzledNormal.z = other.contacts[i].normal.y;

    - Then I do the `Vector3.Cross()` product of `other.contacts.normal` and `swizzledNormal` to get a correct `tangent_01` to the surface.
    - Then I do another `Vector3.Cross()` product, of the `other.contacts.normal` and the `tangent_01` to get a correct `tangent_02`.
    - Now I use these tangents to spawn 2 `baseOffset` points very close to the `other.contacts.point`, and use those to find them on my own collider:

    other.contacts[i].thisCollider.ClosestPoint(baseOffset1)
    other.contacts[i].thisCollider.ClosestPoint(baseOffset2)

    - These resulting points are tangents on my own collider and I can use their cross product to get the normal of my own collider at our collision point.
     
    Last edited: May 18, 2018
  3. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    3,980
    I was going to post that you can get the normal the same way for each collider as long as you keep a reference to both, but you worked it out on your own :)
     
  4. Deeeds

    Deeeds

    Joined:
    Mar 15, 2018
    Posts:
    739
    Can this be done similarly in 2D physics?
     
  5. Tudor

    Tudor

    Joined:
    Sep 27, 2012
    Posts:
    150
    I haven't payed super close attention to 2d physics recently, maybe someone else can help. I know you have the `ContactPoint2D.normal`, so you can do what Daemonhahn also suggested.

    Don't know how/if `ClosestPoint` works in 2D if you're looking to hit the edge/outline of the sprite.
     
    Deeeds likes this.