Search Unity

  1. We are migrating the Unity Forums to Unity Discussions. On July 12, the Unity Forums will become read-only.

    Please, do not make any changes to your username or email addresses at id.unity.com during this transition time.

    It's still possible to reply to existing private message conversations during the migration, but any new replies you post will be missing after the main migration is complete. We'll do our best to migrate these messages in a follow-up step.

    On July 15, Unity Discussions will become read-only until July 18, when the new design and the migrated forum contents will go live.


    Read our full announcement for more information and let us know if you have any questions.

Question Bitwise AND for layermasks with CollisionFilter

Discussion in 'Physics for ECS' started by slushieboy99, Jan 10, 2024.

  1. slushieboy99

    slushieboy99

    Joined:
    Aug 29, 2014
    Posts:
    90
    Hi all,
    I thought this would be simple, I want to do an OverlapBox collision query where CollidesWith must have both of two collision layers assigned and BelongsTo is just one collision layer. I thought I could do this:

    Code (CSharp):
    1. CollisionFilter primaryNodeFilter = new CollisionFilter(){
    2.                 BelongsTo = (uint)CollisionLayers.Selection,
    3.                 CollidesWith = (uint)CollisionLayers.WoodForagable & (uint)CollisionLayers.PrimaryStaticNode,
    4.                 GroupIndex = 0,
    5.             };
    But this doesn't seem to work. Anyone have a better understanding of this?
     
  2. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,661
    To set two possible layers in a layermask, you would want OR, not AND.

    collidesWith = (uint)CollisionLayers.WoodForagable |
    (uint)CollisionLayers.PrimaryStaticNode


    When Unity wants to see if an object is applicable to a layermask, it checks:

    bool collisionPossible = ((1 << objectsLayerIndex) & layerMask) != 0;
     
    slushieboy99 and spiney199 like this.
  3. slushieboy99

    slushieboy99

    Joined:
    Aug 29, 2014
    Posts:
    90
    OR is not what I'm looking for though, I only want my box to collide with entities who's physics shape belongs to both layermasks, not either or. I've tried using or and using + and neither gives the behavior I'm looking for.
     
  4. slushieboy99

    slushieboy99

    Joined:
    Aug 29, 2014
    Posts:
    90


    Code (CSharp):
    1.  
    2. bool collisionPossible = ((1 << objectsLayerIndex) & layerMask) != 0;
    3.  
    Even if objectsLayerIndex includes all layers the object belongs to, I can't think of any bit manipulation for layerMask that will make this true only when objectsLayerIndex includes all layers in layerMask. I'm going to try just doing multiple casts and comparing my queries but if anyone has any better suggestions please let me know!
     
    Last edited: Jan 12, 2024
  5. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,661
    I think you're mixing layer indices with layer masks.

    By default every collider has a single layer index from 0 to 31, and can only reside on a single layer. Let's say your collider is on layer 13, the layer index is 13 and the smallest layer mask including it is bit 13, calculated as
    (1 << 13)
    or written as
    0b0010_0000_0000_0000
    or seen as an integer as 8192.

    Through the use of CollisionFilters, you can say a collider effectively belongs to more than one layer. You combine multiple layer indices with
    (1 << indexA) | (1 << indexB)
    and you now have a layer mask containing the union of all mentioned indices.

    The BelongsTo argument here is a layer mask.

    The CollidesWith argument here is also a layer mask.

    When checking the collision filtering, Unity does this by finding the intersection of two layer masks. Unity just does
    if ((my.BelongsTo & their.CollidesWith) != 0)
    and the inverse. If both masks have nonzero results, it's a collision. It cannot determine more than nonzero like "all bits," it's either zero or nonzero.

    I don't see a path to have Unity Physics learn your rule "if all of the BelongsTo nonzero bits are also nonzero in CollidesWith". The notional source code for a collision check is included on this page, and you'll note that the function to check it is static and not virtual, and CollisionFilter is a struct anyway, so you can't even extend to override this behavior. Anyone is welcome to prove me wrong, I still see the docs saying "the default filter" here and there but I assume it just means the default CollisionFilter value aka
    CollisionFilter.Default
    .
     
    slushieboy99 likes this.
  6. slushieboy99

    slushieboy99

    Joined:
    Aug 29, 2014
    Posts:
    90
    Thanks for the explanation. Yeah I wish there was a CollisionFilter where it could check if
    Code (CSharp):
    1. if ((my.BelongsTo & their.CollidesWith) == my.BelongsTo)
    I tried to find where the code is and see if I could just add some functionality myself, but didn't have any luck, maybe for the reasons you listed. The solution I've found is to do the CollisionFilter with all layers I want OR'd, then iterate over all hits and check if it belongs to all layers, I just wish there were a better solution because this could potentially be a huge slowdown.