Search Unity

Resolved How do I change the collision filter of an entity through code?

Discussion in 'Physics for ECS' started by Interjection, Oct 30, 2020.

  1. Interjection

    Interjection

    Joined:
    Jun 18, 2020
    Posts:
    63
    Here's what I tried (doesn't work):

    Code (CSharp):
    1. Unity.Entities.Entity myEntity = [...]
    2. Unity.Entities.EntityManager myManager = [...]
    3. Unity.Physics.CollisionFilter newFilter = [...]
    4.  
    5. Unity.Physics.PhysicsCollider pc = myManager.GetComponentData<Unity.Physics.PhysicsCollider>(myEntity);
    6. pc.Value.Value.Filter = newFilter;
    7. myManager.SetComponentData(myEntity, pc);
    In
    pc.Value.Value.Filter
    the first "Value" is a field and the second "Value" is a get-only property BUT it returns a ref, which is why I thought I should be able to set it. Guess not.

    How do I change the filter? Does it involve pc.ColliderPtr and unsafe code?
     
  2. Sab_Rango

    Sab_Rango

    Joined:
    Aug 30, 2019
    Posts:
    121
    Hello!

    I found the scene that makes custom filter, that is located in Physics samples, domo>Quiery > CustomCollector.scene

    But they did some magic here, Only game objects with named "Glass Wall" are converted to entity with custom filter which is "transparent"

    .
    But I don't know how they made this!

    You can find the code from there. BUt they are not located near the scene directory.

    https://drive.google.com/file/d/1izC1-DEO4wRLKh_DWD8eBSs4Gbm_T_OR/view?usp=sharing
     
  3. Sab_Rango

    Sab_Rango

    Joined:
    Aug 30, 2019
    Posts:
    121
  4. Interjection

    Interjection

    Joined:
    Jun 18, 2020
    Posts:
    63
    Have tried doing this but it didn't work:

    Code (CSharp):
    1. Unity.Entities.Entity myEntity = [...]
    2. Unity.Entities.EntityManager myManager = [...]
    3.  
    4. UnityEngine.Debug.Log(1u << (9));  //512 (original)
    5. UnityEngine.Debug.Log(1u << (5));  //32 (desired)
    6.  
    7. Unity.Physics.PhysicsCollider pc = myManager.GetComponentData<Unity.Physics.PhysicsCollider>(myEntity);
    8. UnityEngine.Debug.Log(pc.Value.Value.Filter.BelongsTo);  //512 (original filter)
    9. unsafe {
    10.     Unity.Physics.Collider* c1 = pc.ColliderPtr;
    11.     Unity.Physics.CollisionFilter cf1 = c1->Filter;
    12.     cf1.BelongsTo = 1u << (5);
    13.     cf1.CollidesWith = 1u << (5);
    14.     c1->Filter = cf1;
    15.     Unity.Physics.Collider* c2 = (Unity.Physics.Collider*) pc.Value.GetUnsafePtr();
    16.     Unity.Physics.CollisionFilter cf2 = c2->Filter;
    17.     cf2.BelongsTo = 1u << (5);
    18.     cf2.CollidesWith = 1u << (5);
    19.     c2->Filter = cf2;
    20. }
    21. UnityEngine.Debug.Log(pc.Value.Value.Filter.BelongsTo);  //512 (still original filter)
    22. myManager.SetComponentData(myEntity, pc);
    Do I have to create a new Unity.Physics.PhysicsCollider and can't modify the existing one?

    Edit:
    pc.ColliderPtr
    and
    pc.Value.GetUnsafePtr()
    points to the same thing. If I cast the pointer to Unity.Physics.MeshCollider instead of just Unity.Physics.Collider then
    c1->Filter
    becomes a get-only property instead of a get-set property. I really don't want to have to make a new MeshCollider just to update the filter, someone help me out here. Calling Unity.Physics.MeshCollider.Create() is expensive.
     
    Last edited: Oct 31, 2020
  5. Interjection

    Interjection

    Joined:
    Jun 18, 2020
    Posts:
    63
    Tried going through the leaves of the MeshCollider and changing their CollisionFilters (
    polyCol->Filter
    below is a get-set property). Didn't work.

    Code (CSharp):
    1. //{ (inside the change collision filter method)
    2.     Unity.Physics.PhysicsCollider pc = myManager.GetComponentData<Unity.Physics.PhysicsCollider>(myEntity);
    3.     unsafe {
    4.         Unity.Physics.Collider* c1 = pc.ColliderPtr;
    5.         if (c1->Type==Unity.Physics.ColliderType.Mesh) {
    6.             Unity.Physics.MeshCollider* mc = (Unity.Physics.MeshCollider*)pc.ColliderPtr;
    7.             LeafCollector collector = new LeafCollector();
    8.             mc->GetLeaves<LeafCollector>(ref collector);
    9.         } else {
    10.             //unimplemented
    11.         }
    12.     }
    13.     myManager.SetComponentData(myEntity, pc);
    14. //}
    15.  
    16. private struct LeafCollector : Unity.Physics.ILeafColliderCollector {
    17.     public void AddLeaf(Unity.Physics.ColliderKey key, ref Unity.Physics.ChildCollider leaf) {
    18.         unsafe {
    19.             Unity.Physics.CollisionFilter cf = new Unity.Physics.CollisionFilter();
    20.             cf.BelongsTo = 1u << (5);
    21.             cf.CollidesWith = 1u << (5);
    22.             Unity.Physics.PolygonCollider* polyCol = (Unity.Physics.PolygonCollider*)leaf.Collider;
    23.             polyCol->Filter = cf;
    24.         }
    25.     }
    26.     public void PopCompositeCollider(uint numCompositeKeyBits, Unity.Physics.Math.MTransform worldFromParent) {}
    27.     public void PushCompositeCollider(Unity.Physics.ColliderKeyPath compositeKey, Unity.Physics.Math.MTransform parentFromComposite, out Unity.Physics.Math.MTransform worldFromParent) {worldFromParent = parentFromComposite;}
    28. }
    Halp!
     
  6. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    Ah, this seems like an issue.

    Setting the filter directly on the mesh collider makes no sense, because it's just a combination of child filters. However, when you change individual filters of leaf colliders (triangles), mesh needs to rebuild that combined filter, and I suppose it doesn't.

    Unfortunately, I think you'll need to change the code a bit to make this work. After changing the filters of all leaf colliders, you need to "inform" the mesh of new filter. In the Create() method there is a block of code:

    // Calculate combined filter
    meshCollider->m_Header.Filter = mesh.Sections.Length > 0 ? mesh.Sections[0].Filters[0] : CollisionFilter.Default;
    for (int i = 0; i < mesh.Sections.Length; ++i)
    {
    for (var j = 0; j < mesh.Sections.Filters.Length; ++j)
    {
    var f = mesh.Sections.Filters[j];
    meshCollider->m_Header.Filter = CollisionFilter.CreateUnion(meshCollider->m_Header.Filter, f);
    }
    }

    Try putting it in a method and calling that method after you change the filters. Something like "UpdateMeshFilter()" or similar.

    I'll investigate a proper fix. Let me know if this works for you.
     
  7. Interjection

    Interjection

    Joined:
    Jun 18, 2020
    Posts:
    63
    @petarmHavok: I don't think I will venture into modifying Unity's code, if I edit Unity.Physics.MeshCollider.Create() now chances are I will need to do it again in the next version of DOTS, or it will no longer be needed in which case I've just wasted time that could have been spent on the actual game. So I'll wait for that proper fix.

    If not setFilter() or setMaterial() can be implemented then maybe a quicker version of Unity.Physics.MeshCollider.Create() that takes an already-created MeshCollider as 1st parameter and copies everything from it except the filter and material (parameter 2 and 3)?

    Edit: Changing the thread's prefix from "Help Wanted" to "Resolved" but it's not really resolved.
    I'm just waiting for that fix.
     
    Last edited: Nov 3, 2020
    petarmHavok likes this.
  8. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    Working on that fix at the moment. :) Hopefully I can get it in for next release (mid-December is current guess).
     
  9. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    Out of curiosity, what is your use case with changing the filter of the mesh collider?
     
  10. Interjection

    Interjection

    Joined:
    Jun 18, 2020
    Posts:
    63
    Nice!

    The game can have units that exist in the same spot but can't interact because they are on different "planes of existence" however they can pass into each others "planes" through certain spots and should then start colliding with stuff on that "plane". Kind of like if they are ghosts to each other until they move onto the same "plane".
     
    petarmHavok likes this.
  11. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    Just an update that the fix went in and will be available mid-January. Let me know if it works for you.
     
    Thygrrr likes this.