Search Unity

Resolved Create compound collider at runtime cause editor crash!

Discussion in 'Physics for ECS' started by BobFlame, Feb 19, 2021.

  1. BobFlame

    BobFlame

    Joined:
    Nov 12, 2018
    Posts:
    95
    The steps follows:
    1, A physcial body's translation and rotation is modified in system A.
    2, An ECB system performs, jobs in A is completed.
    3, System B reconstruct a compound collider from it's children and assign to physical body.
    4, Fixed Group Update.

    It will not crash at first time, but it will crash finally.

    If I leave translation and rotation unmodified, it works fine, or if I don't reconstruct compound collider, it works fine. So I think there may be some confliction or restriction, or maybe a bug. Could anyone help please?

    Edit:
    It's nothing with transform. I switch to unity.physics backend, and everything is fine, but when I switch to havok end, it will crash. So maybe a havok bug? physics/havok version 0.6, in unity 2020.2.2f1
     
    Last edited: Feb 20, 2021
  2. BobFlame

    BobFlame

    Joined:
    Nov 12, 2018
    Posts:
    95
    Job in System A :

    Code (CSharp):
    1.  
    2.             var ecb = middleSimBufferSystem.CreateCommandBuffer().AsParallelWriter();
    3.             var stayWorldTransformAccess = GetComponentDataFromEntity<StayWorldTransform>(true);
    4.             var localToWorldAccess = GetComponentDataFromEntity<LocalToWorld>(false);
    5.             var positionAccess = GetComponentDataFromEntity<Translation>(false);
    6.             var rotationAccess = GetComponentDataFromEntity<Rotation>(false);
    7.             var parentAccess = GetComponentDataFromEntity<Parent>(false);
    8.  
    9.             Entities.WithBurst().WithNativeDisableParallelForRestriction(localToWorldAccess).WithReadOnly(stayWorldTransformAccess)
    10.                 .WithNativeDisableParallelForRestriction(positionAccess).WithNativeDisableParallelForRestriction(rotationAccess)
    11.                 .WithNativeDisableParallelForRestriction(parentAccess).ForEach((
    12.                     Entity topoEntity, int entityInQueryIndex, in TopologyComp topoComp, in DynamicBuffer<NodeRegistration> nodeRegs) => {
    13.  
    14.                         if (topoComp.coreChanged) {
    15.                             var coreLTW = localToWorldAccess[topoComp.coreNode];
    16.                             var coreWTL = math.inverse(coreLTW.Value);
    17.                             positionAccess[topoEntity] = new Translation { Value = coreLTW.Position };
    18.                             rotationAccess[topoEntity] = new Rotation { Value = coreLTW.Rotation };
    19.  
    20.                             var regNodes = nodeRegs.Reinterpret<Entity>();
    21.                             for (int i = 0; i < regNodes.Length; i++) {
    22.                                 var node = regNodes[i];
    23.                                 if (stayWorldTransformAccess.HasComponent(node)) {
    24.                                     var localToParent = new LocalToWorld { Value = math.mul(coreWTL, localToWorldAccess[node].Value) };
    25.                                     positionAccess[node] = new Translation { Value = localToParent.Position };
    26.                                     rotationAccess[node] = new Rotation { Value = localToParent.Rotation };
    27.                                     ecb.RemoveComponent<StayWorldTransform>(entityInQueryIndex, node);
    28.                                 }
    29.                                 parentAccess[node] = new Parent { Value = topoEntity };
    30.                             }
    31.                         }
    32.                     }).ScheduleParallel();
    33.  
    34.             middleSimBufferSystem.AddJobHandleForProducer(Dependency);
    Job In System B:

    Code (CSharp):
    1.  
    2.         // Topo Collider Generating and Mass Applying
    3.             var nodeCompAccess = GetComponentDataFromEntity<NodeComp>(true);
    4.             var nodeMassAccess = GetComponentDataFromEntity<NodeMass>(true);
    5.             var nodeColliderAccess = GetComponentDataFromEntity<NodeCollider>();
    6.  
    7.         // For nodes, since they are already child of topolgy, translation and rotation means local.
    8.             var translationAccess = GetComponentDataFromEntity<Translation>(true);
    9.             var rotationAccess = GetComponentDataFromEntity<Rotation>(true);
    10.  
    11.             Entities.WithBurst().WithReadOnly(nodeCompAccess).WithReadOnly(nodeMassAccess).WithReadOnly(nodeColliderAccess)
    12.                 .WithReadOnly(translationAccess).WithReadOnly(rotationAccess).ForEach((
    13.                     ref PhysicsCollider topoCollider, ref PhysicsMass topoMass, in TopologyComp topoComp, in DynamicBuffer<NodeRegistration> nodeRegs) => {
    14.  
    15.                         if (topoComp.structureChanged || topoComp.builtStateChanged) {
    16.                             var childMasses = new NativeList<ChildMass>(nodeRegs.Length, Allocator.Temp);
    17.                             var childColliders = new NativeList<CompoundCollider.ColliderBlobInstance>(nodeRegs.Length, Allocator.Temp);
    18.  
    19.                             for (int i = 0; i < nodeRegs.Length; i++) {
    20.                                 var nodeEntity = nodeRegs[i].node;
    21.                                 var nodeComp = nodeCompAccess[nodeEntity];
    22.                                 if (nodeComp.builtState == BuiltState.Built && nodeColliderAccess.HasComponent(nodeEntity)) {
    23.                                     var compoundFromChild = new RigidTransform { pos = translationAccess[nodeEntity].Value, rot = rotationAccess[nodeEntity].Value };
    24.                                     var nodeCollider = nodeColliderAccess[nodeEntity];
    25.                                     var nodeMass = nodeMassAccess[nodeEntity];
    26.                                     childColliders.Add(new CompoundCollider.ColliderBlobInstance {
    27.                                         Collider = nodeCollider.collider,
    28.                                         CompoundFromChild = compoundFromChild,
    29.                                     });
    30.                                     childMasses.Add(new ChildMass { childToCompound = compoundFromChild, mass = nodeMass.mass });
    31.                                 }
    32.                             }
    33.                             if (childColliders.Length > 0) {
    34.                                 if (topoCollider.Value.IsCreated)
    35.                                     topoCollider.Value.Dispose();
    36.  
    37.                                 var _collidersArray = new NativeArray<CompoundCollider.ColliderBlobInstance>(childColliders.Length, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
    38.                                 for (int i = 0; i < childColliders.Length; i++)
    39.                                     _collidersArray[i] = childColliders[i];
    40.                                 topoCollider.Value = CompoundCollider.Create(_collidersArray);
    41.  
    42.                                 var topoMassProp = BuildMassProperties(childMasses);
    43.                                 topoMass = PhysicsMass.CreateDynamic(topoMassProp, 1f);
    44.                             }
    45.                         }
    46.                     }).Schedule();
     
  3. milos85miki

    milos85miki

    Joined:
    Nov 29, 2019
    Posts:
    197
    When do your systems update, could you please show the UpdateBefore and UpdateAfter class attributes?
     
  4. BobFlame

    BobFlame

    Joined:
    Nov 12, 2018
    Posts:
    95
    Sure, System A update in precede middle group, System B update in succeed middle group.
    Code (CSharp):
    1.  
    2.     /// <summary>  </summary>
    3.     [UpdateInGroup(typeof(SimulationSystemGroup), OrderFirst = true)]
    4.     [UpdateAfter(typeof(BeginSimulationEntityCommandBufferSystem))]
    5.     [UpdateBefore(typeof(MiddleSimulationEntityCommandBufferSystem))]
    6.     public class PrecedeMiddleSimulationGroup : SimSystemGroup
    7.     {
    8.     }
    9.  
    10.     [UpdateInGroup(typeof(SimulationSystemGroup), OrderFirst = true)]
    11.     [UpdateAfter(typeof(BeginSimulationEntityCommandBufferSystem))]
    12.     [UpdateBefore(typeof(FixedStepSimulationSystemGroup))]
    13.     public class MiddleSimulationEntityCommandBufferSystem : EntityCommandBufferSystem
    14.     {
    15.     }
    16.  
    17.     [UpdateInGroup(typeof(SimulationSystemGroup), OrderFirst = true)]
    18.     [UpdateAfter(typeof(MiddleSimulationEntityCommandBufferSystem))]
    19.     [UpdateBefore(typeof(FixedStepSimulationSystemGroup))]
    20.     public class SucceedMiddleSimulationGroup : SimSystemGroup
    21.     {
    22.     }
     
  5. BobFlame

    BobFlame

    Joined:
    Nov 12, 2018
    Posts:
    95
    And I also have a multi-worlds architecture, but I test in single world, others are emtpy. So I think it should not be relevant.
     
    Last edited: Feb 20, 2021
  6. milos85miki

    milos85miki

    Joined:
    Nov 29, 2019
    Posts:
    197
    Can you please try the following:
    - add
    World.GetOrCreateSystem<BuildPhysicsWorld>().AddInputDependencyToComplete(Dependency);
    to the end of the OnUpdate() in system B
    - I think you should change allocations to use Allocator.TempJob, since they're done in a job

    Also, it'd be easier to root cause the problem with a call stack and any other error info you're getting.
     
  7. BobFlame

    BobFlame

    Joined:
    Nov 12, 2018
    Posts:
    95
    The problem is I can't get any information about this. No error log in console, can't hit any breakpoint in debug mode. This is how I usually debugging, maybe there is some other techniques I don't konw.

    Adding dependency into BuildPhysicsWorld can't help, I just tried.

    And I refactored my code, now collider generating is in two systems X and Y, system X generate from points cloud to ConvexCollider and some Convex into CompoundCollider, and system Y generate from Componund from X into larger Compound.
    For now, using unity physics is fine. But havok is not crashing editor for this time, it make editor lost response, seems run into some infinite loop (memory in task manager is not increasing).

    If you need my code in system, please let me know. However for my project, I will currently stick to unity.physics as my solution.
     
  8. BobFlame

    BobFlame

    Joined:
    Nov 12, 2018
    Posts:
    95
    I thought tempjob is for allocation across jobs, e.g. you allocate in main thread, and retrive data after job finish. Temp is when you allocate at local (for job internal use)
     
  9. milos85miki

    milos85miki

    Joined:
    Nov 29, 2019
    Posts:
    197
    You're right, sorry for my error. Did AddInputDependencyToComplete? If not, what's the error you're getting?
     
  10. BobFlame

    BobFlame

    Joined:
    Nov 12, 2018
    Posts:
    95
    There is no error at all. Editor just lost response. It have to be turn off from task manager.
    Before my refactor my code. Editor will crash instantly. Not a single error ouputs.
    Both situation will only happen in havok backend. In unity.physcis backend, everything is fine.
     
  11. milos85miki

    milos85miki

    Joined:
    Nov 29, 2019
    Posts:
    197
    Could you please check editor.log (it's usually in C:\Users\<your user name>\AppData\Local\Unity\Editor\Editor.log)?
    It'd be great if you could share a minimal repro project, so I could debug locally.
     
  12. BobFlame

    BobFlame

    Joined:
    Nov 12, 2018
    Posts:
    95
    I would do it maybe these days.
     
    petarmHavok likes this.
  13. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    481
    In System B you Dispose topoCollider.Value before creating the new Compound. However, you are creating the new Compound from Children in the original! Not sure why this won't affect Unity as well as Havok Physics but can you try disposing the original topoCollider after creating the new one?
     
  14. BobFlame

    BobFlame

    Joined:
    Nov 12, 2018
    Posts:
    95
    What do you mean "you are creating the new Compound from Children in the original!". Original compound is disposed and after that the value is assigned a newly created compound. What's the problem in it?
    However I tried what you said. It seems work.