Why doesn't Unity's OnCollisionEnter give me surface normals, and what's the most reliable way to get them?

Posted by michael.bartnett on Game Development See other posts from Game Development or by michael.bartnett
Published on 2012-10-16T05:50:44Z Indexed on 2012/10/16 11:25 UTC
Read the original article Hit count: 365

Unity's on collision event gives you a Collision object that gives you some information about the collision that happened (including a list of ContactPoints with hit normals).

But what you don't get is surface normals for the collider that you hit. Here's a screenshot to illustrate. The red line is from ContactPoint.normal and the blue line is from RaycastHit.normal.

enter image description here

Is this an instance of Unity hiding information to provide a simplified API? Or do standard 3D realtime collision detection techniques just not collect this information?

And for the second part of the question, what's a surefire and relatively efficient way to get a surface normal for a collision?

I know that raycasting gives you surface normals, but it seems I need to do several raycasts to accomplish this for all scenarios (maybe a contact point/normal combination misses the collider on the first cast, or maybe you need to do some average of all the contact points' normals to get the best result).

My current method:

  1. Back up the Collision.contacts[0].point along its hit normal

  2. Raycast down the negated hit normal for float.MaxValue, on Collision.collider

  3. If that fails, repeat steps 1 and 2 with the non-negated normal

  4. If that fails, try steps 1 to 3 with Collision.contacts[1]

  5. Repeat 4 until successful or until all contact points exhausted.

  6. Give up, return Vector3.zero.

This seems to catch everything, but all those raycasts make me queasy, and I'm not sure how to test that this works for enough cases. Is there a better way?

© Game Development or respective owner

Related posts about collision-detection

Related posts about math