Search Unity

Question Find "Graphics" Entity from Physics Entity

Discussion in 'Physics for ECS' started by Krooq, Jun 5, 2022.

  1. Krooq

    Krooq

    Joined:
    Jan 30, 2013
    Posts:
    196
    In DOTS physics, your colliders all get baked into the parent physics body.
    If you want to to do a simple raycast and find the actual entity that authored the collider at runtime you can do it, there is an example in the sample.

    Below is the simple method to do this:
    Code (CSharp):
    1.     public Entity FindGraphicsEntityFromPhysics(Entity bodyEntity, ColliderKey leafColliderKey)
    2.         {
    3.             if (bodyEntity.Equals(Entity.Null))
    4.             {
    5.                 // No Physics so no Graphics
    6.                 return Entity.Null;
    7.             }
    8.  
    9.             // Set the Graphics Entity to the supplied Physics Entity
    10.             var renderEntity = bodyEntity;
    11.  
    12.             // Check if we have hit a leaf node
    13.             if (!leafColliderKey.Equals(ColliderKey.Empty))
    14.             {
    15.                 // Get the Physics Collider
    16.                 var rootCollider = EntityManager.GetComponentData<PhysicsCollider>(bodyEntity).Value;
    17.  
    18.                 // If we hit a CompoundCollider we need to find the original Entity associated
    19.                 // the actual leaf Collider that was hit.
    20.                 if (rootCollider.Value.Type == ColliderType.Compound)
    21.                 {
    22.                     #region Find a Leaf Entity and ColliderKey
    23.                     var leafEntity = Entity.Null;
    24.                     unsafe
    25.                     {
    26.                         var rootColliderPtr = rootCollider.AsPtr();
    27.  
    28.                         // Get the leaf Collider and check if we hit was a PolygonCollider (i.e. a Triangle or a Quad)
    29.                         rootColliderPtr->GetLeaf(leafColliderKey, out var childCollider);
    30.                         leafEntity = childCollider.Entity;
    31.  
    32.                         // PolygonColliders are likely to not have an original Entity associated with them
    33.                         // So if we have a Polygon and it has no Entity then we really need to check for
    34.                         // the higher level Mesh or Terrain Collider instead.
    35.                         var childColliderType = childCollider.Collider->Type;
    36.                         var childColliderIsPolygon = childColliderType == ColliderType.Triangle || childColliderType == ColliderType.Quad;
    37.                         if (childColliderIsPolygon && childCollider.Entity.Equals(Entity.Null))
    38.                         {
    39.                             // Get the ColliderKey of the Polygon's parent
    40.                             if (TryGetParentColliderKey(rootColliderPtr, leafColliderKey, out leafColliderKey))
    41.                             {
    42.                                 // Get the Mesh or Terrain Collider of the Polygon
    43.                                 TryGetChildInHierarchy(rootColliderPtr, leafColliderKey, out childCollider);
    44.                                 leafEntity = childCollider.Entity;
    45.                             }
    46.                         }
    47.                     }
    48.                     #endregion
    49.  
    50.                     // The Entities recorded in the leaves of a CompoundCollider may have been correct
    51.                     // at the time of conversion. However, if the Collider blob is shared, or came up
    52.                     // through a sub scene, we cannot assume that the baked Entities in the
    53.                     // CompoundCollider are still valid.
    54.  
    55.                     // On conversion Entities using a CompoundCollider have an extra dynamic buffer added
    56.                     // which holds a list of Entity/ColliderKey pairs. This buffer should be patched up
    57.                     // automatically and be valid with each instance, at least until you start messing
    58.                     // with the Entity hierarchy yourself e.g. by deleting Entities.
    59.  
    60.                     #region Check the Leaf Entity is valid
    61.                     // If the leafEntity was never assigned in the first place
    62.                     // there is no point in looking up any Buffers.
    63.                     if (!leafEntity.Equals(Entity.Null))
    64.                     {
    65.                         // Check for an Key/Entity pair buffer first.
    66.                         // This should exist if the Physics conversion pipeline was invoked.
    67.                         var colliderKeyEntityPairBuffers = GetBufferFromEntity<PhysicsColliderKeyEntityPair>(true);
    68.                         if (colliderKeyEntityPairBuffers.HasComponent(bodyEntity))
    69.                         {
    70.                             var colliderKeyEntityBuffer = colliderKeyEntityPairBuffers[bodyEntity];
    71.                             // TODO: Faster lookup option?
    72.                             for (int i = 0; i < colliderKeyEntityBuffer.Length; i++)
    73.                             {
    74.                                 var bufferColliderKey = colliderKeyEntityBuffer[i].Key;
    75.                                 if (leafColliderKey.Equals(bufferColliderKey))
    76.                                 {
    77.                                     renderEntity = colliderKeyEntityBuffer[i].Entity;
    78.                                     break;
    79.                                 }
    80.                             }
    81.                         }
    82.                         else
    83.                         {
    84.                             // We haven't found a Key/Entity pair buffer so the compound collider
    85.                             // may have been created in code.
    86.  
    87.                             // We'll assume the Entity in the CompoundCollider is valid
    88.                             renderEntity = leafEntity;
    89.  
    90.                             // If this CompoundCollider was instanced from a prefab then the entities
    91.                             // in the compound children would actually reference the original prefab hierarchy.
    92.                             var rootEntityFromLeaf = leafEntity;
    93.                             while (HasComponent<Parent>(rootEntityFromLeaf))
    94.                             {
    95.                                 rootEntityFromLeaf = GetComponent<Parent>(rootEntityFromLeaf).Value;
    96.                             }
    97.  
    98.                             // If the root Entity found from the leaf does not match the body Entity
    99.                             // then we have hit an instance using the same CompoundCollider.
    100.                             // This means we can try and remap the leaf Entity to the new hierarchy.
    101.                             if (!rootEntityFromLeaf.Equals(bodyEntity))
    102.                             {
    103.                                 // This assumes there is a LinkedEntityGroup Buffer on original and instance Entity.
    104.                                 // No doubt there is a more optimal way of doing this remap with more specific
    105.                                 // knowledge of the final application.
    106.                                 var linkedEntityGroupBuffers = GetBufferFromEntity<LinkedEntityGroup>(true);
    107.  
    108.                                 // Only remap if the buffers exist, have been created and are of equal length.
    109.                                 bool hasBufferRootEntity = linkedEntityGroupBuffers.HasComponent(rootEntityFromLeaf);
    110.                                 bool hasBufferBodyEntity = linkedEntityGroupBuffers.HasComponent(bodyEntity);
    111.                                 if (hasBufferRootEntity && hasBufferBodyEntity)
    112.                                 {
    113.                                     var prefabEntityGroupBuffer = linkedEntityGroupBuffers[rootEntityFromLeaf];
    114.                                     var instanceEntityGroupBuffer = linkedEntityGroupBuffers[bodyEntity];
    115.  
    116.                                     if (prefabEntityGroupBuffer.IsCreated && instanceEntityGroupBuffer.IsCreated
    117.                                         && (prefabEntityGroupBuffer.Length == instanceEntityGroupBuffer.Length))
    118.                                     {
    119.                                         var prefabEntityGroup = prefabEntityGroupBuffer.AsNativeArray();
    120.                                         var instanceEntityGroup = instanceEntityGroupBuffer.AsNativeArray();
    121.  
    122.                                         for (int i = 0; i < prefabEntityGroup.Length; i++)
    123.                                         {
    124.                                             // If we've found the renderEntity index in the prefab hierarchy,
    125.                                             // set the renderEntity to the equivalent Entity in the instance
    126.                                             if (prefabEntityGroup[i].Value.Equals(renderEntity))
    127.                                             {
    128.                                                 renderEntity = instanceEntityGroup[i].Value;
    129.                                                 break;
    130.                                             }
    131.                                         }
    132.                                     }
    133.                                 }
    134.                             }
    135.                         }
    136.                     }
    137.                     #endregion
    138.                 }
    139.             }
    140.  
    141.             // Finally check to see if we have a graphics redirection on the shape Entity.
    142.             if (HasComponent<PhysicsRenderEntity>(renderEntity))
    143.             {
    144.                 renderEntity = GetComponent<PhysicsRenderEntity>(renderEntity).Entity;
    145.             }
    146.  
    147.             return renderEntity;
    148.         }

    Now I understand that this physics stuff is a bit complicated but good gracious that is next level.
    Is that really how we are supposed to do it? It's like 150 lines long and it's not even burstable in this form.