So the documentation for RaycastHit says that the ‘normal’ property is the normal of the surface hit by the cast:
But this actually isn’t true in the case of SphereCast and CapsuleCast (underneath SphereCast is actually a CapsuleCast, so DotPeek enlightened me to).
Instead the normal returned is the inverse normal of the capsule/sphere that hit the normal.
This is fine when hitting a flat surface head on, as the surface normal, and the inverse normal of the sphere/capsule are identical.
But if you cast at an edge, and the sphere/capsule hit slightly off. You get something like:

From what I can tell this is the expected value to come back as per PhysX documentation. Which basically just says to me Unity just misdocumented the RaycastHit.normal in their documentation, and that it’s not actually a bug. Which would make sense, because RaycastHit in the case of Raycast DOES return the surface normal. It just doesn’t for Capsule/Sphere cast.
Furthermore, this normal can be very useful for various things.
BUT, the actual surface normal would be useful as well.
Currently I have a function to get the surface normal. What I do is check if the hit collider was a MeshCollider and calculate the surface normal based on the mesh data. If it’s not a MeshCollider than I do a short Raycast at the surface to calculate the surface normal. The latter of which means 2 consecutive casts each time AND a slight potential for error.
You can see this here:
public static Vector3 RepairHitSurfaceNormal(RaycastHit hit, int layerMask)
{
if(hit.collider is MeshCollider)
{
var collider = hit.collider as MeshCollider;
var mesh = collider.sharedMesh;
var tris = mesh.triangles;
var verts = mesh.vertices;
var v0 = verts[tris[hit.triangleIndex * 3]];
var v1 = verts[tris[hit.triangleIndex * 3 + 1]];
var v2 = verts[tris[hit.triangleIndex * 3 + 2]];
var n = Vector3.Cross(v1 - v0, v2 - v1).normalized;
return hit.transform.TransformDirection(n);
}
else
{
var p = hit.point + hit.normal * 0.01f;
Physics.Raycast(p, -hit.normal, out hit, 0.011f, layerMask);
return hit.normal;
}
}
I was wondering what the rest of you do? If you use a similar method to me, or if maybe there’s a BETTER option?
