Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

SphereCast hitting an edge -- how to get normals on either side?

Discussion in 'Scripting' started by Iron-Warrior, Jul 5, 2014.

  1. Iron-Warrior

    Iron-Warrior

    Joined:
    Nov 3, 2009
    Posts:
    836
    Hey,

    I've recently noticed that when a SphereCast contacts directly onto the edge of a surface, the Hit.normal that is returned is actually an interpolation of the normals of the faces on either side of the edge and the position the cast hit the edge at. This is fine, since obviously an "edge" does not have a normal like a face, but I'm having trouble getting the normals of the surfaces on either side of the edge. Here's an example of what I want:



    The cyan arrow is the normal that SphereCast hit returns, while the red and blue normals are the ones I want to retrieve. Here's what I did to get this:

    Code (csharp):
    1.  
    2.         Vector3 o = OffsetPosition(feet.Offset) + (Up * Tolerance);
    3.        
    4.         RaycastHit hit;
    5.  
    6.         if (Physics.SphereCast(o, radius, Down, out hit, walkable))
    7.         {
    8.             // Remove the tolerance from the distance travelled
    9.             hit.distance -= Tolerance;
    10.  
    11.             Vector3 toCenter = (hit.point - transform.position).normalized * Tolerance;
    12.  
    13.             toCenter = Math3D.ProjectVectorOnPlane(hit.normal, toCenter);
    14.  
    15.             Vector3 nearPoint = hit.point + toCenter;
    16.             Vector3 farPoint = hit.point - toCenter;
    17.  
    18.             RaycastHit nearHit;
    19.             RaycastHit farHit;
    20.  
    21.             hit.collider.Raycast(new Ray(nearPoint, -hit.normal), out nearHit, Mathf.Infinity);
    22.             hit.collider.Raycast(new Ray(farPoint, -hit.normal), out farHit, Mathf.Infinity);
    23.  
    24.             currentGround = new Ground(hit, nearHit, farHit);
    25.         }[
    26.  
    The origin of the cast ("o") would be just above the green gizmo circle drawn. "Down" is just down. This works fine when the interpolated normal is fairly close to the average of the two normals on each side of the edge, as seen above...but when you move the cast further over...



    The interpolated normal becomes almost parallel with one of the edges. I'm still able to retrieve the red normal here, but I could see this causing problems, and it doesn't seem to be a robust solution. I just need those two normals any way I can get them!

    Thanks for any help,

    Erik
     
  2. Iron-Warrior

    Iron-Warrior

    Joined:
    Nov 3, 2009
    Posts:
    836
    One bump before I give up and try something different.
     
  3. Sameer1472

    Sameer1472

    Joined:
    Apr 1, 2020
    Posts:
    4
    Hey, did you ever find a solution to this? I just ran into this problem
     
  4. AshwinTheGammer

    AshwinTheGammer

    Joined:
    Sep 23, 2016
    Posts:
    68
  5. YukkuriGameMaker

    YukkuriGameMaker

    Joined:
    Mar 23, 2021
    Posts:
    2
    We can always cast another ray slightly beside the initial ray to check whether it hits an edge or a point.
    Anyway, that's awful.
    We need a better solution.