Search Unity

Unity Physics with per-entity collider geometry

Discussion in 'Physics for ECS' started by kingstone426, Oct 18, 2019.

  1. kingstone426

    kingstone426

    Joined:
    Jun 21, 2013
    Posts:
    44
    I am trying to resize collider geometry for individual entities working from Unity Physics Sample 5b:

    https://github.com/Unity-Technologies/EntityComponentSystemSamples/blob/master/UnityPhysicsSamples/Assets/Demos/5. Modify/Scripts/ChangeSphereColliderRadiusBehaviour.cs

    However, all my entities seem to share the same collider geometry, and therefore overwrite the same data.

    Code (csharp):
    1.  
    2. public struct ScaleCylinderColliderJob : IJobForEach<BlobRadiusComponent, PhysicsCollider>
    3. {
    4.         public unsafe void Execute(ref BlobRadiusComponent radius, ref PhysicsCollider collider)
    5.         {
    6.             if (collider.ColliderPtr->Type != ColliderType.Cylinder)
    7.             {
    8.                 return;
    9.             }
    10.  
    11.             var scPtr = (CylinderCollider*)collider.ColliderPtr;
    12.             var cylinderGeometry = scPtr->Geometry;
    13.             cylinderGeometry.Radius = radius.size;
    14.             scPtr->Geometry = cylinderGeometry;
    15.         }
    16.     }
    17. }
    18.  
    These entities have all been instantiated from the same entity prefab (using IConvertGameObjectToEntity and PhysicsShapeAuthoring). I guess it makes sense in many use cases to share collider geometry between instances (especially if it's large mesh colliders) but I really need to resize them individually.

    How can I update collider geometry for my entities individually?
     
  2. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,770
    Technically I should work for you. I do resize my cubes entities, which are created in similar manner as yours.
    So not sure what you are missing. Can you check again, against sample?

    Are you positive that your radius.size is different for each entity?
     
  3. kingstone426

    kingstone426

    Joined:
    Jun 21, 2013
    Posts:
    44
    It doesn't seem to be that the entities have shared radius components. When I add the following debug code to the job

    Code (csharp):
    1.  
    2. Debug.Log("Radius: " + radius.size + " Collider: " + scPtr->Geometry.Radius);
    3.  
    I get the following output (when there are 2 entities):

    Radius: 3.662142 Collider: 4.427896
    Radius: 4.427609 Collider: 3.662142
    Radius: 3.661845 Collider: 4.427609
    Radius: 4.427312 Collider: 3.661845
    (and so on)

    So it seems radius.size is different for each entity, but setting Geometry.Radius for one entity overwrite Geometry.Radius of the next entity.

    Could I be doing something wrong during instantiation / authoring?
     
    Last edited: Oct 18, 2019
  4. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,770
    Can you try do same thing but for cube, or and sphere?
     
  5. kingstone426

    kingstone426

    Joined:
    Jun 21, 2013
    Posts:
    44
    Yes, I will try to isolate the problem further. If your cubes have individual collider scale then it should work me as well.

    Thanks!
     
  6. kingstone426

    kingstone426

    Joined:
    Jun 21, 2013
    Posts:
    44
    Alright I've managed to create a tiny reproducible:

    • Open SpawnFromEntity scene in ECS Samples
    • Add Package: Unity Physics 0.2.4
    • Add PhysicsShapeAuthoring to RotatingCube prefab
    • Create ScaleColliders.cs with this contents:

    Code (csharp):
    1.  
    2. using Unity.Entities;
    3. using Unity.Physics;
    4. using UnityEngine;
    5. using BoxCollider = Unity.Physics.BoxCollider;
    6. using Random = Unity.Mathematics.Random;
    7.  
    8. public class ScaleColliders : ComponentSystem
    9. {
    10.     Random random = new Random(1);
    11.    
    12.     protected override unsafe void OnUpdate()
    13.     {
    14.         Entities.ForEach((Entity entity, ref PhysicsCollider collider) =>
    15.         {
    16.             var scPtr = (BoxCollider*)collider.ColliderPtr;
    17.             var cylinderGeometry = scPtr->Geometry;
    18.             var newSize = random.NextFloat3(1, 2);
    19.             Debug.Log( entity.Index +  " Size: " + cylinderGeometry.Size + " -> " + newSize);
    20.             cylinderGeometry.Size = newSize;
    21.             scPtr->Geometry = cylinderGeometry;
    22.         });
    23.     }
    24. }
    25.  
    The output shows that each entity gets the newSize set in the previous iteration.
    Also, when I Debug.Log("pointer: " + (int)scPtr) it seems to be the same for all entities.
     
  7. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,770
    I just compared to my job, and looks nearly the same with the approach.
    The only main difference is, I use IJobChunk. I least expect that has anything to do. But I would give a go at least.
    Or maybe try on main thread only?

    What if you modify demo, by adding another sphere?
    Well in fact, there was demo, with few resizing balls in runtime.

    I just don't see, why your code does not produce expected results.

    Is your var newSize = random.NextFloat3(1, 2); produces random values for each entity??
     
  8. kingstone426

    kingstone426

    Joined:
    Jun 21, 2013
    Posts:
    44
    Yes, actually the code in my last post uses Entites.ForEach which I believe should always run on the main thread.

    Yes, sorry that was probably not very clear.

    The result I see is that each iteration sets a new random scale, but that scale also applied to all other entities. My conclusion is that they all use the same Geometry. I have not found a way to recreate geometries without also recreating the entire collider (which removes other important collider settings).
     
  9. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,770
    Ok, I just checked again my system, which creates collider for entity. So I maybe said initially wrong. however, I use following, rather relay on collider from entity conversion, I just manually create colliders.

    Code (CSharp):
    1.  
    2. BlobAssetReference <Unity.Physics.Collider> boxCollider = Unity.Physics.BoxCollider.Create
    3. (
    4.     float3.zero,
    5.     quaternion.identity,
    6.     new float3 (1), // Scale
    7.     0.05f,
    8.     Unity.Physics.Extensions.Filters._CollisionFilter ( 2, 0 ) // Filter // Does not collide with same layer.
    9. ) ;
    10.  
    Code (CSharp):
    1. BasePhysicsDemo.CreateDynamicBodyWithEntity ( entity, boxCollider, float3.zero, float3.zero, 1.0f ) ;
    On side note I just noticed, there are some upcoming changes with BoxCollider.Create in U2020.
     
  10. kingstone426

    kingstone426

    Joined:
    Jun 21, 2013
    Posts:
    44
    Alright, so it seems you will have to manually recreate the collider when spawning new instances.

    Here's my code for anyone stumbling on the same problem:

    Code (csharp):
    1.  
    2. var prefabCollider = *(CylinderCollider*) colliders[prefab].ColliderPtr;
    3. var newCollider = new PhysicsCollider()
    4. {
    5.     Value = CylinderCollider.Create(new CylinderGeometry
    6.     {
    7.         Radius = prefabCollider.Geometry.Radius,
    8.         Height = prefabCollider.Geometry.Height,
    9.         SideCount = prefabCollider.Geometry.SideCount,
    10.         Center = prefabCollider.Geometry.Center,
    11.         BevelRadius = prefabCollider.Geometry.BevelRadius,
    12.         Orientation = prefabCollider.Geometry.Orientation
    13.     }, prefabCollider.Filter, prefabCollider.Material)
    14. };
    15.  
    16. commandBuffer.SetComponent(index, entity, newCollider );
    17.  
    The prefabCollider values are the one defined with the ColliderShapAuthoring component.
     
    Last edited: Oct 20, 2019
  11. kingstone426

    kingstone426

    Joined:
    Jun 21, 2013
    Posts:
    44
    From the physics session at Unite 2019, near-term physics features include data interfaces for mutable runtime shapes, e.g., scaling colliders.

     
  12. VolatileCoder

    VolatileCoder

    Joined:
    Sep 21, 2014
    Posts:
    18

    The same blob collider reference is shared among prefabs by default to save memory. Check the "Force Unique" checkbox in the Physics Shape authoring component in order to force a separate collider for each instance.
     
    kingstone426 likes this.