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
.
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:
Back up the
Collision.contacts[0].point
along its hit normalRaycast down the negated hit normal for
float.MaxValue
, onCollision.collider
If that fails, repeat steps 1 and 2 with the non-negated normal
If that fails, try steps 1 to 3 with
Collision.contacts[1]
Repeat 4 until successful or until all contact points exhausted.
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?
EDIT If this really is just the way things are with 3D collision, an overview of why in the general case would be just as welcome as something specific to Unity.