Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

GroupIndex and Raycast

Discussion in 'Physics for ECS' started by MatiasCa, May 30, 2021.

  1. MatiasCa

    MatiasCa

    Joined:
    Feb 25, 2021
    Posts:
    10
    I have multiple entities of the same type that would like to be able to see each other using raycast.

    Since the raycast comes from the center of the entity the raycast will detect itself and I'm only interested on the first one, I think the best way to get this is to use the GroupIndex with a negative value for every entity and the raycast

    But I have some issues to make it work:

    1) Not been able to set the GroupIndex value in the editor.

    2) I Created a system to set this value from a initialization system:

    Code (CSharp):
    1. protected override void OnUpdate()
    2.     {
    3.         var ecb = mEndSimulationEcbSystem.CreateCommandBuffer().AsParallelWriter();
    4.         Entities      
    5.             .WithAll<AssignColliderGroup>()
    6.             .ForEach((Entity entity, int entityInQueryIndex,
    7.                       ref PhysicsCollider collider) =>
    8.             {
    9.                 var filter = collider.Value.Value.Filter;
    10.                 filter.GroupIndex = entity.Index * -1;
    11.                 collider.Value.Value.Filter = filter;
    12.                 ecb.RemoveComponent<AssignColliderGroup>(entityInQueryIndex, entity);
    13.             }).ScheduleParallel();
    14.     }
    This is failing because it seems that all instance are sharing the same collider so when I update the filter I alter the other ones as well.

    I understand that it might be useful to share a collider shape with multiple entities like any mesh but maybe it could be good to have the filter as a separate shareable object?

    3) Last try was to clone the collider but this is not working, cant figure out why the first one is not been considered for test when running a
    collisionWorld.OverlapAabb(collisionArea, ref affectedEntities);
    with an Aabb with the a bigger size than the scene, (this one quite hard to debug because sometimes it start working as expected without any changes, so its hard to reproduce), this is probably related on how I'm trying yo clone the collider I'm not sure what is the best way to work with BlobAssetReference

    Code (CSharp):
    1. var ecb = mEndSimulationEcbSystem.CreateCommandBuffer().AsParallelWriter();
    2.         Entities
    3.             .WithAll<AssignColliderGroup>()
    4.             .ForEach((Entity entity, int entityInQueryIndex,
    5.                       ref PhysicsCollider collider) =>
    6.             {
    7.                 var filter = collider.Value.Value.Filter;
    8.                 filter.GroupIndex = entity.Index * -1;
    9.                 var tempCollider = collider.Value;
    10.                 var newCollider = BlobAssetReference<Collider>.Create(collider.Value.Value);
    11.                 newCollider.Value.Filter = filter;
    12.                 collider.Value = newCollider;
    13.  
    14.                 ecb.RemoveComponent<AssignColliderGroup>(entityInQueryIndex, entity);
    15.             }).ScheduleParallel();
    Right now it seems to me that the best alternative is to cast a ray that return a list of all collision and discard the ones that have the same entity in the body than the one calling the raycast. but I would like to understand what I doing wrong with this approach for the future.

    Thanks in Advance
     
    Last edited: May 30, 2021
  2. MatiasCa

    MatiasCa

    Joined:
    Feb 25, 2021
    Posts:
    10
    Ok I was able to solve my issue by creating a custom HitCollector based on the closesHitColector


    Code (CSharp):
    1. public struct FilteredHitCollector<T> : ICollector<T> where T : struct, IQueryResult
    2.     {
    3.         public bool EarlyOutOnFirstHit => false;
    4.         public float MaxFraction { get; private set; }
    5.         public int NumHits { get; private set; }
    6.  
    7.         public Entity FilteredEntity;
    8.  
    9.         private T m_ClosestHit;
    10.         public T ClosestHit => m_ClosestHit;
    11.  
    12.         public FilteredHitCollector(float maxFraction, Entity filter)
    13.         {
    14.             MaxFraction = maxFraction;
    15.             m_ClosestHit = default(T);
    16.             NumHits = 0;
    17.             FilteredEntity = filter;
    18.         }
    19.  
    20.         #region ICollector
    21.  
    22.         public bool AddHit(T hit)
    23.         {
    24.             Assert.IsTrue(hit.Fraction <= MaxFraction);
    25.             if (hit.Entity == FilteredEntity)
    26.             {
    27.                 return false;
    28.             }
    29.             MaxFraction = hit.Fraction;
    30.             m_ClosestHit = hit;
    31.             NumHits = 1;
    32.             return true;
    33.         }
    34.  
    35.         #endregion
    36.     }
    I'm still interested in the issues I have before if anyone can help me to understand
     
  3. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    481
    1) Yeah, we haven't exposed that yet. Not sure about the best interface at the minute.
    2) This could be achieved with a custom authoring component and conversion system that runs after the default Physics conversion systems. I recommend checking out the SpawnExplosionAuthoring component, which clones the collider and sets the Group Index for spawned bodies. There is also a 'Force Unique' flag on the PhysicsShape authoring component if you do not want to share colliders.
    3) I'll refer to the Spawn Explosion component again.

    Regardless of the above points, the FilteredHitCollector is a great way to go.
     
  4. MatiasCa

    MatiasCa

    Joined:
    Feb 25, 2021
    Posts:
    10
    Thanks for the response Ill take a look at the explosion example.

    I'll stick with my solution since it seems better than cloning the collider on every entity but I'm still wonder why we need to clone the whole shape to have different filter, sounds like using different filter might still be more performant or be required on other use case and sharing collider data might still worth it
     
  5. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    481
    The filter is part of the blob but we do need to investigate removing some elements into a common header. That said, for simple primitives (like spheres, capsules), there won't be much difference anyway. The real savings would be on the colliders with larger blocks of sharable data like convex hulls or meshes. Some of this is legacy and details are in this video.