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
  2. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  3. Unity support for visionOS is now available. Learn more in our blog post.
    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,500
    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.