Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Resolved Resizing colliders at runtime and in jobs with burst.

Discussion in 'Physics for ECS' started by l_Lobsternator, Feb 12, 2021.

  1. l_Lobsternator

    l_Lobsternator

    Joined:
    Aug 31, 2019
    Posts:
    12
    So recently I've been working on a project that requires me to be able to resize the colliders of prefabs that I'm instantiating in an ICollisionEventsJob but the only way I've found to do that is by first getting the collider pointer and changing the geometry of it via unsafe code. Preferably I would like to avoid unsafe code if possible but if not I would at least want to be able to use it in parallel safely and efficiently.

    So in my project, I am using a CommandBuffer as a parallel writer in the ICollisionEventsJob which I then use to instantiate and initialize an entity during a specific type of collision. Problem is that I need to change the size of the instantiated entity dynamically, but just changing (for instance) the CompositeScale component doesn't affect the collider's size as it is baked in at the start of the simulation.

    I looked around for a fix and I stumbled upon an example scene by (I presume) Unity which uses code like this:
    Code (CSharp):
    1. unsafe
    2. {
    3.     // grab the sphere pointer
    4.     SphereCollider* scPtr = (SphereCollider*)collider.ColliderPtr;
    5.     oldRadius = scPtr->Radius;
    6.     newRadius = math.lerp(oldRadius, radius.Target, 0.05f);
    7.     // if we have reached the target radius get a new target
    8.     if (math.abs(newRadius - radius.Target) < 0.01f)
    9.     {
    10.          radius.Target = radius.Target == radius.Min ? radius.Max : radius.Min;
    11.     }
    12.  
    13.     // update the collider geometry
    14.     var sphereGeometry = scPtr->Geometry;
    15.     sphereGeometry.Radius = newRadius;
    16.     scPtr->Geometry = sphereGeometry;
    17. }
    To change the collider size. Now the problem with this is that it requires that you either have access to the collider of the entity or that you know how to make a new one from scratch, both things of which I don't know how to do.

    Getting access to the entity's collider might at first seem like a fairly easy task but not in this case. (In my understanding) you have to use a ComponentDataFromEntity<PhysicsCollider> to get access to the PhysicsCollider component of an entity. To make one of those I have to have access to a system and create one right after I created the new entity. Problem is that a system is a reference type, which does not play nicely with jobs. Also, I am unsure whether burst plays nicely with unsafe code or not.

    So really, in my mind, there is only one solution which is to create a new collider from scratch which I do not know how to do in code. However, to me, even that seems like a roundabout and inefficient way of doing it. I would really appreciate any kind of help, thanks.
     
  2. milos85miki

    milos85miki

    Joined:
    Nov 29, 2019
    Posts:
    197
    Unfortunately, we currently don't support collider runtime scaling. We have it in sight as an important feature, though.

    You can use
    public static unsafe BlobAssetReference<Collider> Create(...)
    to create a collider and
    public unsafe void Initialize(...)
    to change existing one. The key part is setting up the *Geometry struct for the shape. Going into the physics code often helps if you're not sure about what some things do or what to pass in.

    Unsafe code does look a bit intimidating, but it just requires you to know exactly what you're doing and it will serve you well (Burst won't complain).

    The following samples might be useful:
    Assets/Demos/5. Modify/5b. Change Collider Size.unity
    Assets/Demos/5. Modify/5c. Change Collider Type.unity
    Assets/Demos/5. Modify/5g. Change Collider Filter.unity

    Please let me know if this helps.
     
    l_Lobsternator and Occuros like this.
  3. Shinyclef

    Shinyclef

    Joined:
    Nov 20, 2013
    Posts:
    478
    I get a bit confused with this statement that collider runtime scaling is not supported. In my thread here https://forum.unity.com/threads/collider-create-performance.1055930/ I change the geometry of an already created collider like this:

    Code (CSharp):
    1. unsafe
    2. {
    3.     BoxCollider* bcPtr = (BoxCollider*)collider.GetUnsafePtr();
    4.     BoxGeometry boxGeom = bcPtr->Geometry;
    5.     boxGeom.Size = size;
    6.     bcPtr->Geometry = boxGeom;
    7. }
    Is this different to runtime scaling?
     
  4. argibaltzi

    argibaltzi

    Joined:
    Nov 13, 2014
    Posts:
    216
    I think you need to rebuild the PhysicsMass (PhysicsMass.CreateDynamic) after you change the size of a collider
    just changing the collider alone is not enough
     
    Last edited: Feb 15, 2021
    l_Lobsternator likes this.
  5. milos85miki

    milos85miki

    Joined:
    Nov 29, 2019
    Posts:
    197
    @Shinyclef , sorry for the confusion. You can change the whole geometry, I meant that we don't support changing scale only. Currently, scale is baked into the geometry, so the way you're going is the only one right now.

    @argibaltzi, that's correct, thank you! You should update entity's PhysicsMass component with
    PhysicsMass.CreateDynamic(collider.MassProperties, mass) 
    .
     
    l_Lobsternator likes this.
  6. l_Lobsternator

    l_Lobsternator

    Joined:
    Aug 31, 2019
    Posts:
    12
    Sorry for the late reply.

    I'm sorry but I don't think I understand how those two functions work; Initialize
    and BlobAssetReference<Collider>.Create. Create takes either a byte[] (byte[] of what?) or a collider (But that seems kinda backwards to me) or a void* and length (Again, to what?). Also I don't really understand where you're finding this "Initialize" function, could you elaborate? Sorry if I seem brazen I would just like to understand.

    I do understand @argibaltzi point, but again, I'm unsure as to how I'm supposed to go about getting a new collider.
     
  7. argibaltzi

    argibaltzi

    Joined:
    Nov 13, 2014
    Posts:
    216
    you need to study the samples and do some experiments to understand how things work
     
  8. Alex33333333

    Alex33333333

    Joined:
    Jan 3, 2017
    Posts:
    11
    Hi, juliusensen.
    I use this way to rescale the collider. This code is working fine in the level editor. I'm not 100% sure is it the right way to do it in the actual game or not.

    Code (CSharp):
    1. EntityManager manager = World.DefaultGameObjectInjectionWorld.EntityManager;
    2. Entity ent = manager.CreateEntity();
    3.  
    4. SphereGeometry sphere = new SphereGeometry
    5. {
    6. Center = float3.zero,
    7. Radius = 100
    8. };
    9. BlobAssetReference<Unity.Physics.Collider> colliderRef = Unity.Physics.SphereCollider.Create(sphere);
    10.  
    11. manager.AddComponentData(ent, new PhysicsCollider { Value = colliderRef });
    12.  
    Or you can use this way, mentioned above. Not tested it, but looks like it will work fine.
    Code (CSharp):
    1. EntityManager manager = World.DefaultGameObjectInjectionWorld.EntityManager;
    2.         Entity ent = manager.CreateEntity();
    3.  
    4.         PhysicsCollider collider = manager.GetComponentData<PhysicsCollider>(ent);
    5.         unsafe
    6.         {
    7.             SphereCollider* bcPtr = (SphereCollider*)collider.Value.GetUnsafePtr();
    8.             SphereGeometry sphereGeom = bcPtr->Geometry;
    9.             sphereGeom.Center = float3.zero;
    10.             sphereGeom.Radius = 100;
    11.             bcPtr->Geometry = sphereGeom;
    12.         }

    And quick guess about jobs. Probably it won't work, but may be it will push you to the right solution. It is pseudocode and I have no time to test this approach.
    Code (CSharp):
    1. void OnUpdate()
    2. {
    3. NativeList<Entity> entities = new NativeList<Entity>();
    4.         EntityCommandBuffer buffer = new EntityCommandBuffer();
    5.         InstantiateJob instJob = new InstantiateJob()
    6.         {
    7.             buffer = buffer,
    8.             entities = entities
    9.         };
    10.         var instHandle = instJob.Schedule();
    11.         instHandle.Complete();
    12.  
    13.         buffer.Playback(World.EntityManager);
    14.         var data = GetComponentDataFromEntity<PhysicsCollider>();
    15.  
    16.         ResizeColliderJob resizeJob = new ResizeColliderJob
    17.         {
    18.             radius = 200,
    19.             dataFromEntity = data,
    20.             entities = entities
    21.         };
    22.         var resizeHandle = resizeJob.Schedule(entities.Length, 4);
    23.         resizeHandle.Complete();
    24.  
    25.         entities.Dispose();
    26. }
    27. public struct InstantiateJob : ICollisionEventsJob
    28. {
    29.     public EntityCommandBuffer buffer;
    30.     public NativeList<Entity> entities;
    31.  
    32.     public void Execute(CollisionEvent collisionEvent)
    33.     {
    34.         Entity tempEnt = buffer.Instantiate();
    35.         entities.Add(tempEnt);
    36.     }
    37. }
    38.  
    39. public struct ResizeColliderJob : IJobParallelFor
    40. {
    41.     public float radius;
    42.     public ComponentDataFromEntity<PhysicsCollider> dataFromEntity;
    43.     public NativeList<Entity> entities;
    44.  
    45.     public void Execute(int index)
    46.     {
    47.         unsafe
    48.         {
    49.             Unity.Physics.SphereCollider* sPtr = (Unity.Physics.SphereCollider*)dataFromEntity[entities[index]].ColliderPtr;
    50.             var sphereGeometry = sPtr->Geometry;
    51.             sphereGeometry.Radius = radius;
    52.             sPtr->Geometry = sphereGeometry;
    53.         }
    54.     }
    55. }


     
    Last edited: Mar 16, 2021
    l_Lobsternator likes this.
  9. l_Lobsternator

    l_Lobsternator

    Joined:
    Aug 31, 2019
    Posts:
    12
    Thanks so much! The first method works perfectly for what I'm trying to do.
     
  10. Alex33333333

    Alex33333333

    Joined:
    Jan 3, 2017
    Posts:
    11
    it's nice to hear that. I'm glad I could help :)
     
    petarmHavok likes this.