Search Unity

Question RaycastHit backface culling

Discussion in 'Physics for ECS' started by MatiasCa, Feb 25, 2021.

  1. MatiasCa

    MatiasCa

    Joined:
    Feb 25, 2021
    Posts:
    10
    I need to ignore collision detection from ray generated inside a collider


    I was able to solve this with this function

    Code (CSharp):
    1.  
    2. public static bool IsBackFaceCollision(in Unity.Physics.RaycastHit hit,
    3.                                        in NativeArray<RigidBody> bodies)
    4. {
    5.     var body = bodies[hit.RigidBodyIndex];
    6.     ChildCollider childCollider;
    7.     if (body.Collider.Value.GetLeaf(hit.ColliderKey, out childCollider))
    8.     {
    9.         unsafe
    10.         {
    11.             var collider = (PolygonCollider*)childCollider.Collider;
    12.             if (collider->Planes.Length > 1)
    13.             {
    14.                 float3 planeNormal = collider->Planes[1].Normal;
    15.                 if (hit.SurfaceNormal.Equals(planeNormal))
    16.                 {
    17.                     return true;
    18.                 }
    19.             }
    20.         }
    21.     }
    22.     return false;
    23. }
    24.  
    25.  
    But I have some issue about it:
    1) It requires unsafe
    2) The cast to PolygonCollider seems like a hack
    3) It assumes that Planes[1] will always be the backface plane

    For all these reasons i think this could eventually break in a future release

    For me it seems that the best way to handle this will be a flag on the Filter or a filed in the RaycastHit but I couldn't find any of this
    Do you guys know a better way to filter this?

    Thanks in advance
     
  2. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    481
    1. Yeah, that can be somewhat scary. Removing the need for unsafe is something we are considering.
    2. You could check for a PolygonCollider rather than assuming.
      Code (CSharp):
      1. var childColliderType = childCollider.Collider->Type;
      2. var childColliderIsPolygon = childColliderType == ColliderType.Triangle || childColliderType == ColliderType.Quad
    3. collider->Planes[0].Flipped.Normal
      is another option (though this is the same as
      Planes[1]
      ). We should just add a
      Normal
      property to the PolygonCollider for convenience.
     
  3. MatiasCa

    MatiasCa

    Joined:
    Feb 25, 2021
    Posts:
    10
    Thank you for your response, you won more questions!

    2. when we query the collider using colliderKey from a successful hit is it possible to get something that it's not a polygon?
    My concern about the cast is that it's seems to be an internal structure since there is no public method to request it which normally means "don't do this" to me, but if its possible to get something else then this solution will not work and ill need something else for those cases.

    3. About adding something to the interface it could be really nice if we can filter this cases with and extra settings on the filter or get a flag in the hit response, that will remove the requirement to provide
    in NativeArray<RigidBody> bodies
    to every job that needs to filter this case

    not sure if its is something simple to calculate at

    Code (CSharp):
    1. public static bool RayQuad
    2. public static bool RayTriangle
     
  4. milos85miki

    milos85miki

    Joined:
    Nov 29, 2019
    Posts:
    197
    2. Depends on what your cast hits. If it hits a compound collider, its children can be anything. However, it's not complicated and you can see example code in Unity.Physics.Collider.GetChild() .

    3. This is only valid for meshes, so it seems safer to let users do it when needed. There might be similar, but slightly different exclusion needs, so adding extra checks for input and results would slow things down for everyone. It might be good to have an example of that filtering in our samples project, though.
     
  5. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    481
    2. Using
    GetLeaf
    with the colliderKey to get the collider hit, will always return a convex shape (Polygon, Box, Sphere etc) at the base of a hierarchy. colliderKey will be invalid if there was no hierarchy. Reading the collider type is always valid regardless of the collider hit, so checking if the collider type is a Triangle or Quad, and then casting to a PolygonCollider, will always be safe (even if in an unsafe block :))

    3a. I believe you are really looking to have the hit collider returned as part of the RaycastHit result, rather than having to look it up? Its a possibility, but to @milos85miki 's point, some folk will want the main body hit and some folk will want the leaf hit. Passing around Colliders (especially ones that end up being passed by value) would probably not be a good idea. As a compromise, the query hit result could include the collider Type that was hit. You'd still have to pass the Bodies array and call GetLeaf for lower level operations but you could check the Type first before needing to any extra lookup.

    3b. What you really want though is a back face ignore flag at the top of your raycast. In the same vein, we need an ignore initial shape/entity flag as well.
     
    WAYNGames likes this.
  6. MatiasCa

    MatiasCa

    Joined:
    Feb 25, 2021
    Posts:
    10
    Not really, just discaring an invalid RaycastHIt, I undestand that copying collider info in the result might be to much, so i was wondering about having more information in the raycasthit, in the same way we have surface normal, with flags that we can use to discard this so we can avoid all the other query.
    But I originally assumed that it only required setting the flag on the collision detection function, I understand that if it requires more calculation it might be a problem for the global performance.
    Another idea is to add a flag on the Physics shape to prevent it to generate backface but I'm not sure if that's how it works

    Interesting, how should we handle this in case it's not a polygon, lets say that the ray start inside the sphere, will it return a backface normal? how can we test for it in that case? do we need to create a different test for every case?
     
  7. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    481
    Ultimately all the ray tests boil down to queries in Library\PackageCache\com.unity.physics\Unity.Physics\Collision\Queries\Raycast.cs
    You don't need to worry about individual shape types with volume. Any 'inside' hits will return true, a hit fraction with 0 and a hit normal pointing back along the ray.