2
\$\begingroup\$

I'm doing a SphereCast for a GroundCheck of a player. I have my Raycast hitInfo, and here in the picture at the left, I Debug.drawRay in black the direction of the hitInfo.normal every frame

It seems like hitInfo.normal give me an interpolation of the normal, not the real normal of the surface...

I only want the real normal of the surface... (red normals I have draw on the right), and may be the green one (the perfect normal between 2 surface), but if I can have only the red one, it would be great

How can I do it ?

Thanks ! enter image description here

\$\endgroup\$
1
  • 1
    \$\begingroup\$ When you use a spherecast, you're firing a sphere against the surface. When a sphere touches a corner, the normal of the collision is parallel to the sphere's normal at that point, not the normal of the flat wall on either side. So there's no interpolation happening here, just your choice of shape. \$\endgroup\$
    – DMGregory
    Commented Feb 9, 2019 at 12:28

1 Answer 1

1
\$\begingroup\$

Ok, I found an temporary solution that give me the red normal IF I want to keep my SphereCast Test, I have to do a second Raycast for having this surface normal (C'mon Unity, why we haven't a hitInfo.surfaceNormal information ??)

//here my sphereCast in someFunction
RaycastHit hitInfo;
Vector3 position;     //origin of the sphereCast
float radiusRayCast;  //radius of the sphereCast
Vector3 dirCast;      //direction of the SphereCast
float magnitudeCast;  //magnitude of my sphereCast
int layerMask;        //layerMask used for both SphereCast & Raycast
float rayCastMargin;  //margin magnitude of the second raycast

if (Physics.SphereCast(position, radiusRayCast, dirCast, out hitInfo,
                               magnitudeCast, layerMask))
{
    //here my second raycast Test
    Vector3 surfaceNormal = GetSurfaceNormal(position,
                                             radiusRayCast,
                                             magnitudeCast,
                                             radiusRayCast,
                                             hitInfo.point,
                                             rayCastMargin,
                                             layerMask);
}

And here my static fonction, who calculate:

public static Vector3 GetCollisionCenterSphereCast(Vector3 castOrigin, Vector3 direction, float magnitude)
{
    Vector3 collisionCenter = castOrigin + (direction * magnitude);
    return (collisionCenter);
}

public static Vector3 CalculateRealNormal(Vector3 origin, Vector3 direction, float magnitude, float rayCastMargin, int layermask)
{
    //Ray ray = new Ray(origin, direction);
    RaycastHit hit;
    if (Physics.Raycast(origin, direction, out hit, magnitude + rayCastMargin, layermask))
    {
        //Debug.Log("Did Hit");
        return (hit.normal);
    }
    Debug.DrawRay(origin, direction.normalized * (magnitude + rayCastMargin));
    Debug.LogWarning("we are not suppose to miss that one...");
    return (Vector3.zero);
}

public static Vector3 SetSurfaceNormal(Vector3 castOrigin, Vector3 direction,
        float magnitude, float radius, Vector3 hitPoint,
        float rayCastMargin, int layerMask)
{
    Vector3 centerCollision = GetCollisionCenterSphereCast(castOrigin, direction, magnitude);
    Vector3 dirCenterToHit = hitPoint - castOrigin;
    float sizeRay = dirCenterToHit.magnitude;
    Vector3 surfaceNormal = CalculateRealNormal(centerCollision, dirCenterToHit, sizeRay, rayCastMargin, layerMask);

    Debug.DrawRay(centerCollision, surfaceNormal, Color.black, 5f);
    return (surfaceNormal);
}

As you see in this pictures below, black Ray are indeed the exacte normal of the surface, and the yellow Ray, the normal created by the SphereCast. It works !

Unfortunatly, it demand a second Raycast, and we can't have the perfect normal Intersection, but for now, it's good enought for me.

Unity Result Explanation Schema

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .