Search Unity

Analyzing and Optimizing Unity Sphere/Capsule Casts

Discussion in 'Scripting' started by JasonL663, Mar 10, 2014.

  1. JasonL663

    JasonL663

    Joined:
    Mar 10, 2014
    Posts:
    1
    Hi all,

    It seems that there's a common issue regarding the behavior of the Unity SphereCast and CapsuleCast operations that can be a bit of a pain for Unity developers. For those who wish to implement their own collision detection system in Unity instead of using the standard Unity physics, this bug can be a huge stumbling block.

    The issue arises when the starting point of either the SphereCast and CapsuleCast is already intersecting a collider. Under these conditions, the cast will either return a unpredictably defined hit point and normal or ignore the collider completely. This causes a huge problem if you're trying to implement standard collision as even the slightest intersection with a wall or surface (which could be caused by float imprecision or errors in the detection algorithm itself) will cause your collision system to break.



    As I'm currently in the middle of implementing my own collision detection, here's my analysis of the behavior of the Unity Sphere/Capsule Casts so far:


    Besides the intersection glitch, the SphereCast behavior is actually pretty straightforward:




    The only thing that may catch some people off guard is the location and direction of the hitpoint and normal as well as their relationship with the RaycastHit.distance parameter. It turns out that the hitpoint is set in relation to the point on the edge of the sphere that hit the collider while the normal points in the direction from the hitpoint towards the center of the sphere where the hit took place. The distance parameter is the actual distance the sphere should travel before it hits the hitpoint. This means that if you traveled from the cast origin in the cast direction by the distance provided in the RaycastHit info, you would get the origin of the sphere to which the hitpoint lies on the edge of.




    The CapsuleCast actually works pretty similarly to the SphereCast. The only point that you need to watch out for is the positioning of the hitpoint. Specifically, the hitpoint will always try to remain closest to the endpoint of the capsule (the second point you pass into Physics.CapsuleCastAll). If the endpoint of the capsule exceeds the edge of the collider, the hitpoint will stick to that edge until the startpoint of the capsule passes over it.


    Here's the hitpoint seeking the endpoint of the capusle (the top point).


    And here it is sticking to the edge of the surface.



    As I said before, the main issue arises when any of the startpoints of the cast are already intersecting with any other collider. In the best case scenario, the collider will simply be ignored, but if not, the hitpoint and normal produced by the cast are difficult to predict.


    Here, the normal produced actually angles towards the left
    even though the direction of the cast is perpendicular to the surface.




    Using the analysis so far, I've come up with a basic model for the behavior of the Sphere/Capsule Cast:




    Essentially, the area marked in green is free of any errors and behaves as it should. The area of the cast marked in black will always ignore all colliders contained within it. The area marked in yellow is unpredictable and will either ignore the collider or return invalid hit data. It is this yellow area where all the main issues occur.


    The solution I've found for the yellow area is relatively simple: all you need to do is move your cast startpoint backwards by the radius of the sphere and then increase the length of the cast by that same radius.




    As you can see, by shifting the cast, we get a much larger predictable area of the actual cast we wish to achieve. However we now have a small bit of excess area that we do not wish to include in our cast. We can actually remove this excess by filtering our resulting hitpoints to only those who's hit distance is beyond the actual cast origin or those that are inside the actual cast start sphere and not inside our shifted start sphere.


    Anyways, I hope someone finds this helpful in better understanding the behavior of the Unity Sphere/Capsule Casts. I'll attach the script I used for visualizing and testing the casts. To use it, just copy the two files into your project and attach the RaycastHelper script onto any object that has two children - the cast shown will be from the first child to the second child. Feel free to improve on it if you'd like as well.
     

    Attached Files:

    Last edited: Mar 10, 2014
    Krull, Ruchir, andrew-lukasik and 2 others like this.
  2. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,191
    Very interesting! I have been searching and searching trying to figure out exactly what the RaycastHit.normal was returning for a sphere cast, but to no avail. Until now that is. Also, I hadn't realized that the RaycastHit.distance was returning the distance from the sphere cast center to the center of the "hit sphere." I just assumed it was the distance from the origin to the hit point.

    Previously I was calculating the center of the sphere at the collision via the normals, like so:

    Code (CSharp):
    1. Vector3 collisionCenter = hitInfo.point + (sphereRadius * hitInfo.normal);
    Unfortunately as anyone who has worked with SphereCast knows, the hitInfo.normal is trouble some. For instance, when a sphere is cast into a flat ground, the normal at the hit point should be directed perpendicular to the ground. Yet the hitInfo.normal is slightly off by like .0003.

    With your knowledge, however, I can calculate the position of the collisionCenter using this formula:

    Code (CSharp):
    1. Vector3 collisionCenter = castOrigin + (direction * hitInfo.distance);
    Following that, I can deduce the normals via this formula:

    Code (CSharp):
    1. Vector3 normals = (collisionCenter - hitInfo.point) / sphereRadius;
    This gives the expected perpendicular normal when the sphere collides with flat ground or a flat wall, which is crucial for me as I need to know if a flat geometry is hit (vs a collider edge).

    Thank you!
     
    Last edited: Aug 23, 2014
  3. Creasu

    Creasu

    Joined:
    Feb 1, 2020
    Posts:
    7
    Hello is there any way that the pictures can be updated so they are visible again? I see that there is interesting information here that might be useful for me.