Search Unity

  1. Unity Asset Manager is now available in public beta. Try it out now and join the conversation here in the forums.
    Dismiss Notice

Question [DOTS] How to raycast only front face

Discussion in 'Physics Previews' started by Looooooooong, Mar 30, 2021.

  1. Looooooooong

    Looooooooong

    Joined:
    Apr 20, 2017
    Posts:
    6
    Apparently, DOTS Physics raycast can also hit the back face. I implemented a custom
    ICollector<RaycastHit>
    to filter out the back face by looking at the hit normal. However,
    RaycastHit.SurfaceNormal
    is the back face normal in case the ray hit the back face. I want to get the front face normal from raycast result, even if the ray hit the back face. How can I solve this problem?

    Here is the code:
    Code (CSharp):
    1.   struct FrontFaceClosestHitCollector : ICollector<RaycastHit> {
    2.     public bool EarlyOutOnFirstHit => false;
    3.     public float MaxFraction { get; private set; }
    4.     public int NumHits { get; private set; }
    5.  
    6.     public RaycastHit ClosestHit { get; private set; }
    7.  
    8.     public float3 RayDirection;
    9.  
    10.     public FrontFaceClosestHitCollector(float3 rayDirection) {
    11.       MaxFraction = 1f;
    12.       NumHits = 0;
    13.       ClosestHit = default;
    14.       RayDirection = rayDirection;
    15.     }
    16.  
    17.     public bool AddHit(RaycastHit hit) {
    18.       if (dot(RayDirection, hit.SurfaceNormal) > 0f) return false;
    19.  
    20.       MaxFraction = hit.Fraction;
    21.       ClosestHit = hit;
    22.       NumHits = 1;
    23.       return true;
    24.     }
    25.   }
     
    Last edited: Mar 30, 2021
  2. AlanMattano

    AlanMattano

    Joined:
    Aug 22, 2013
    Posts:
    1,501
    Hello Looooooooooooo and well come to this forum.

    If it is a close 3d object the ray I presume will not hit the backface. And if is an open object like a leaf, I presume you can put a boolean flag toggle?

    More exactly, what is the problem?

    Looking the API like the idea of
    https://docs.unity3d.com/ScriptReference/RaycastHit-normal.html
    Code (CSharp):
    1. // Draw lines to show the incoming "beam" and the reflection.
    2. Debug.DrawLine(gunObj.position, hit.point, Color.red);
    3. Debug.DrawRay(hit.point, reflectVec, Color.green);
     
    Last edited: Mar 30, 2021
  3. Looooooooong

    Looooooooong

    Joined:
    Apr 20, 2017
    Posts:
    6
    Sometimes, I have to raycast from inside a collider. And I don't want to hit the back face of said collider. And even if I raycast from outside all the colliders, it's not guaranteed to always hit the front face first. What if the ray hit the back face of an open mesh, a plane or a quad? The thing is, DOT Physics doesn't seem to have an option to disable back face ray cast query, like in the old Physics module.
     
    Last edited: Mar 30, 2021
  4. milos85miki

    milos85miki

    Joined:
    Nov 29, 2019
    Posts:
    197
  5. Looooooooong

    Looooooooong

    Joined:
    Apr 20, 2017
    Posts:
    6
    @milos85miki Thank you for your reference. The provided code didn't work itself at first, so I had to modify it a bit. The child polygon collider's normal needs to be transformed to world space before comparing with the raycast hit surface normal. Here is the final raycast collector code:

    Code (CSharp):
    1.  
    2. struct FrontFaceClosestHitCollector : ICollector<RaycastHit> {
    3.   // ICollector
    4.   public bool EarlyOutOnFirstHit => false;
    5.   public float MaxFraction { get; private set; }
    6.   public int NumHits { get; private set; }
    7.  
    8.   // Input
    9.   public NativeSlice<RigidBody> Bodies;
    10.  
    11.   // Output
    12.   public RaycastHit ClosestHit { get; private set; }
    13.  
    14.   public FrontFaceClosestHitCollector(NativeSlice<RigidBody> bodies) {
    15.     MaxFraction = 1f;
    16.     NumHits = 0;
    17.     ClosestHit = default;
    18.     Bodies = bodies;
    19.   }
    20.  
    21.   public bool AddHit(RaycastHit hit) {
    22.     if (!IsFrontFaceHit(hit)) return false;
    23.  
    24.     MaxFraction = hit.Fraction;
    25.     ClosestHit = hit;
    26.     NumHits = 1;
    27.     return true;
    28.   }
    29.  
    30.   unsafe bool IsFrontFaceHit(RaycastHit hit) {
    31.     var body = Bodies[hit.RigidBodyIndex];
    32.  
    33.     if (!body.Collider.Value.GetLeaf(hit.ColliderKey, out var childCollider)) return false;
    34.  
    35.     var childColliderType = childCollider.Collider->Type;
    36.     var childColliderIsPolygon = childColliderType == ColliderType.Triangle || childColliderType == ColliderType.Quad;
    37.  
    38.     if (!childColliderIsPolygon) return false;
    39.  
    40.     var collider = (PolygonCollider*)childCollider.Collider;
    41.     var localNormal = collider->Planes[0].Normal;
    42.     var worldNormal = rotate(body.WorldFromBody, localNormal);
    43.  
    44.     return all(abs(hit.SurfaceNormal - worldNormal) <= EPSILON);
    45.   }
    46. }
     
    Last edited: Apr 5, 2021
    ZERO025 and petarmHavok like this.