When you do a raycast in 2D or 3D you sometimes get normals that are very unlike the shape you made. These appear the moment your raycast hits the edge of a collider and it gives an interpolated normal between the 2 surfaces that this edge is connected to.
- How can I detect when the raycast I’m doing is returning a corner normal and not a surface normal?
- Is there a way to raycast and hav only surface normals that are returned?
EDIT: Actually in 3D, the simple Raycast doesn’t have this problem. It’s only when using SphereCast or the likes that the normal gives back corner normals.

I hate to resurrect this, but I’ve actually been struggling with this for weeks and just found a workaround (not quite a solution because I still don’t know why this happens) and hope that this helps someone else.
When I hit something in a BoxCast, I check the surface normal. If the dot product between my movement’s direction and the surface normal is close to -1, I can assume I’m either walking into a flat wall, or, a corner. In my project, I separate horizontal movement from vertical, so I only check this when moving in my “side pass” Either way, I perform a single Raycast (Collider.Raycast, so I’m only checking against that one collider). If I hit the obstacle again, I update my previous collision’s surface normal with the “true” surface normal, because Raycast doesn’t seem to have this issue, only box/capsule casts.
This may not catch every possible case, but so far so good for me! Hope this helps.
// In some cases, walking into a corner can result in a normal that is the inverse of the desired movement
if (pass == EPass.SIDE)
{
float threshold = -0.98f;
if (Vector3.Dot(direction, closestHit.normal) <= threshold)
{
// Raycast from the volume's center, into the collision point we know we hit before
Vector3 rayOrigin = m_Collider.transform.position + m_Collider.center;
Vector3 rayDirection = (closestHit.point - rayOrigin).normalized;
float rayDistance = Vector3.Distance(closestHit.point, rayOrigin) + m_Params.ContactOffset;
Ray ray = new Ray(rayOrigin, rayDirection);
// If we were able to hit the collider, grab the "true" surface normal so the volume can project collisions correctly
if (closestHit.collider.Raycast(ray, out RaycastHit hitInfo, Vector3.Distance(closestHit.point, rayOrigin) + Physics.defaultContactOffset))
{
closestHit.normal = hitInfo.normal;
}
}
}
