Search Unity

Question Undesired Collision Behavior - Collision Physics Execution Order?

Discussion in 'Physics for ECS' started by fomartin, Sep 5, 2020.

  1. fomartin

    fomartin

    Joined:
    Aug 31, 2015
    Posts:
    17
    Hello folks! I'm working on an archery project in DOTS to get my feet wet, and am noticing some weird behavior when my arrow collides against a wall using Unity.Physics.CollisionEvent.

    After the collision the rotation of the arrow is set incredibly weird. If I use Unity.Physics.TriggerEvent we get the desired effect, but I want to use CollisionEvent because I later want to be able to have the arrows bounce off the wall if too slow or at a an obtuse angle on collision. I have my arrow set up the following way, with PhysicsShape Material.CollisionResponse set to Collide Raise Collision Events:

    View attachment 694022

    So what I think is happening is the following:
    1. The arrow collides with the wall.
    2. Collision event is raised.
    3. Physics calculations are made on transform.
    4. Arrow is rendered with new transform.
    5. My ArrowCollisionSystem processes the collision event.
      1. CollisionJob sets the InverseInertia of the PhysicsMass to 0 to stop all velocity.
      2. AttachJob sets the arrows parent, in case the object moves, the arrow remains attached.
    If this is indeed what is happening then it means by the time we get to my ArrowCollisionSystem, the LocalToWorld component of the arrow has already been updated to a post collision transform where we are "bouncing" off the wall. Hence the weird rotation when attaching. I think this may be the case due to how the rotation of the arrow seems to correlate with the angle of the arrow to the wall on collision. If you see in the video, the more angled I shoot towards the wall, the more pronounced the rotation is. This seems to be true on all directions.

    To mitigate this, I decided to add another component to the ArrowEntity that will remember the previous frame's LocalToWorld component. This way I can hard reset the arrow rotation to the previous LocalToWorld.Rotation pre-collision. Here's the ArrowCollisionSystem right now:

    Code (CSharp):
    1. using Unity.Burst;
    2. using Unity.Collections;
    3. using Unity.Entities;
    4. using Unity.Jobs;
    5. using Unity.Mathematics;
    6. using Unity.Physics;
    7. using Unity.Physics.Systems;
    8. using Unity.Transforms;
    9.  
    10. namespace JuegosFrantasticos
    11. {
    12.     [UpdateAfter(typeof(EndFramePhysicsSystem))]
    13.     public class ArrowCollisionSystem : SystemBase
    14.     {
    15.         private BuildPhysicsWorld _buildPhysicsWorld;
    16.         private StepPhysicsWorld _stepPhysicsWorld;
    17.         private EntityQuery _rotationFollowsLinearVelocityGroup;
    18.         private EntityCommandBufferSystem _entityCommandBufferSystem;
    19.         private EntityQuery _arrowEntityGroup;
    20.  
    21.         protected override void OnCreate()
    22.         {
    23.             _buildPhysicsWorld = World.GetOrCreateSystem<BuildPhysicsWorld>();
    24.             _stepPhysicsWorld = World.GetOrCreateSystem<StepPhysicsWorld>();
    25.  
    26.             _rotationFollowsLinearVelocityGroup =
    27.                 GetEntityQuery(new EntityQueryDesc
    28.                 {
    29.                     All = new ComponentType[]
    30.                     {
    31.                         typeof(RotationFollowsLinearVelocityComponent)
    32.                     }
    33.                 });
    34.  
    35.             _entityCommandBufferSystem =
    36.                 World.GetOrCreateSystem<EntityCommandBufferSystem>();
    37.  
    38.             _arrowEntityGroup = GetEntityQuery(new EntityQueryDesc
    39.             {
    40.                 All = new ComponentType[]
    41.                 {
    42.                     typeof(ArrowPenetrationComponent),
    43.                     typeof(LocalToWorld),
    44.                 }
    45.             });
    46.         }
    47.  
    48.         protected override void OnUpdate()
    49.         {
    50.             if (_rotationFollowsLinearVelocityGroup.CalculateEntityCount() == 0)
    51.             {
    52.                 return;
    53.             }
    54.  
    55.             CollisionJob collisionJob = new CollisionJob
    56.             {
    57.                 PhysicsVelocityGroup =
    58.                     GetComponentDataFromEntity<PhysicsVelocity>(true),
    59.                 LocalToWorldGroup =
    60.                     GetComponentDataFromEntity<LocalToWorld>(),
    61.                 PhysicsMassGroup =
    62.                     GetComponentDataFromEntity<PhysicsMass>(),
    63.                 ArrowPenetrationGroup =
    64.                     GetComponentDataFromEntity<ArrowPenetrationComponent>(),
    65.                 RotationFollowsLinearVelocityGroup =
    66.                     GetComponentDataFromEntity<RotationFollowsLinearVelocityComponent>(),
    67.                 PreviousLocalToWorldGroup =
    68.                     GetComponentDataFromEntity<PreviousLocalToWorldComponent>(true),
    69.             };
    70.  
    71.             Dependency = collisionJob.Schedule(
    72.                 _stepPhysicsWorld.Simulation,
    73.                 ref _buildPhysicsWorld.PhysicsWorld,
    74.                 Dependency);
    75.  
    76.             AttachJob penetrationJob = new AttachJob
    77.             {
    78.                 EntityCommandBuffer =
    79.                     _entityCommandBufferSystem.CreateCommandBuffer().ToConcurrent(),
    80.                 ArrowPenetrationArchetypeChunk =
    81.                     GetArchetypeChunkComponentType<ArrowPenetrationComponent>(),
    82.                 EntityChunkType =
    83.                     GetArchetypeChunkEntityType()
    84.             };
    85.  
    86.             Dependency = penetrationJob.Schedule(_arrowEntityGroup, Dependency);
    87.         }
    88.  
    89.         [BurstCompile]
    90.         private struct CollisionJob : ICollisionEventsJob
    91.         {
    92.             public ComponentDataFromEntity<PhysicsMass>
    93.                 PhysicsMassGroup;
    94.             public ComponentDataFromEntity<ArrowPenetrationComponent>
    95.                 ArrowPenetrationGroup;
    96.             public ComponentDataFromEntity<RotationFollowsLinearVelocityComponent>
    97.                 RotationFollowsLinearVelocityGroup;
    98.             public ComponentDataFromEntity<LocalToWorld>
    99.                 LocalToWorldGroup;
    100.             [ReadOnly] public ComponentDataFromEntity<PreviousLocalToWorldComponent>
    101.                 PreviousLocalToWorldGroup;
    102.             [ReadOnly] public ComponentDataFromEntity<PhysicsVelocity>
    103.                 PhysicsVelocityGroup;
    104.  
    105.             public void Execute(CollisionEvent triggerEvent)
    106.             {
    107.  
    108.                 bool isEntityARotationFollowsLinearVelocity =
    109.                     RotationFollowsLinearVelocityGroup.Exists(triggerEvent.EntityA);
    110.                 bool isEntityBRotationFollowsLinearVelocity =
    111.                     RotationFollowsLinearVelocityGroup.Exists(triggerEvent.EntityB);
    112.  
    113.                 if (isEntityARotationFollowsLinearVelocity && isEntityBRotationFollowsLinearVelocity
    114.                     || !isEntityARotationFollowsLinearVelocity && !isEntityBRotationFollowsLinearVelocity)
    115.                 {
    116.                     return;
    117.                 }
    118.  
    119.                 Entity arrowEntity;
    120.                 if (isEntityARotationFollowsLinearVelocity)
    121.                 {
    122.                     arrowEntity = triggerEvent.EntityA;
    123.  
    124.                     RotationFollowsLinearVelocityGroup[arrowEntity] =
    125.                         new RotationFollowsLinearVelocityComponent() { IsActive = false };
    126.                 }
    127.                 else if (isEntityBRotationFollowsLinearVelocity)
    128.                 {
    129.                     arrowEntity = triggerEvent.EntityB;
    130.  
    131.                     RotationFollowsLinearVelocityGroup[arrowEntity] =
    132.                         new RotationFollowsLinearVelocityComponent() { IsActive = false };
    133.                 }
    134.                 else
    135.                 {
    136.                     return;
    137.                 }
    138.  
    139.                 //TODO: Remove collider or make it not throw any more events.
    140.                 if(ArrowPenetrationGroup[arrowEntity].IsPenetrated)
    141.                 {
    142.                     return;
    143.                 }
    144.  
    145.                 float4x4 debug = LocalToWorldGroup[arrowEntity].Value;
    146.  
    147.                 // Confusing collision behavior mitigation; have a new system
    148.                 // saving on to a component the arrow's previous LocalToWorld.
    149.                 // This way even if the physics engine updates the transform
    150.                 // before this collision event, we can reset it back to
    151.                 // pre-collision transform.
    152.                 // THIS DOES NOT CURRENTLY WORK
    153.                 LocalToWorldGroup[arrowEntity] =
    154.                     PreviousLocalToWorldGroup[arrowEntity].Value;
    155.  
    156.                 PhysicsMassGroup[arrowEntity] = new PhysicsMass
    157.                 {
    158.                     InverseInertia = float3.zero,
    159.  
    160.                     Transform = PhysicsMassGroup[arrowEntity].Transform,
    161.                     InverseMass = PhysicsMassGroup[arrowEntity].InverseMass,
    162.                     AngularExpansionFactor = PhysicsMassGroup[arrowEntity].AngularExpansionFactor,
    163.                     CenterOfMass = PhysicsMassGroup[arrowEntity].CenterOfMass,
    164.                     InertiaOrientation = PhysicsMassGroup[arrowEntity].InertiaOrientation,
    165.                 };
    166.  
    167.                 Entity otherEntity = !isEntityARotationFollowsLinearVelocity
    168.                     ? triggerEvent.EntityA
    169.                     : triggerEvent.EntityB;
    170.  
    171.                 ArrowPenetrationGroup[arrowEntity] =
    172.                         new ArrowPenetrationComponent(
    173.                             arrowEntity,
    174.                             LocalToWorldGroup[arrowEntity],
    175.                             otherEntity);
    176.             }
    177.         }
    178.  
    179.         [BurstCompile]
    180.         private struct AttachJob : IJobChunk
    181.         {
    182.             public EntityCommandBuffer.Concurrent EntityCommandBuffer;
    183.             public ArchetypeChunkComponentType<ArrowPenetrationComponent>
    184.                 ArrowPenetrationArchetypeChunk;
    185.  
    186.             [ReadOnly]
    187.             public ArchetypeChunkEntityType EntityChunkType;
    188.  
    189.             public void Execute(
    190.                 ArchetypeChunk chunk,
    191.                 int chunkIndex,
    192.                 int firstEntityIndex)
    193.             {
    194.                 NativeArray<Entity> entities =
    195.                     chunk.GetNativeArray(EntityChunkType);
    196.                 NativeArray<ArrowPenetrationComponent> arrowPenetrationArray =
    197.                     chunk.GetNativeArray(ArrowPenetrationArchetypeChunk);
    198.  
    199.                 for (int i = 0; i < entities.Length; ++i)
    200.                 {
    201.                     if (arrowPenetrationArray[i].IsPenetrated)
    202.                     {
    203.                         EntityCommandBuffer.AddComponent(
    204.                             chunkIndex,
    205.                             entities[i],
    206.                             new Parent
    207.                             {
    208.                                 Value = arrowPenetrationArray[i].PenetratedObject
    209.                             });
    210.  
    211.                         EntityCommandBuffer.SetComponent(
    212.                             chunkIndex,
    213.                             entities[i],
    214.                             arrowPenetrationArray[i].ArrowLocalToWorld);
    215.                     }
    216.                 }
    217.             }
    218.         }
    219.     }
    220. }
    And here's my PreviousArrowLocalToWorldUpdateSystem

    Code (CSharp):
    1. using Unity.Collections;
    2. using Unity.Entities;
    3. using Unity.Jobs;
    4. using Unity.Transforms;
    5.  
    6. namespace JuegosFrantasticos
    7. {
    8.     [UpdateAfter(typeof(ArrowCollisionSystem))]
    9.     public class PreviousArrowLocalToWorldUpdateSystem : SystemBase
    10.     {
    11.         protected override void OnUpdate()
    12.         {
    13.             Entities
    14.                 .WithName("PreviousArrowLocalToWorldUpdateJob")
    15.                 .WithAll<ArrowTagComponent>()
    16.                 .ForEach(
    17.                     (ref PreviousLocalToWorldComponent previousLocalToWorld,
    18.                     in LocalToWorld localToWorld) =>
    19.                     {
    20.                         previousLocalToWorld.Value = localToWorld;
    21.                     })
    22.                 .Schedule();
    23.         }
    24.     }
    25. }
    26.  
    This still doesn't work, so I'm unsure where to go from here. I could make it a TriggerEvent again and add components that record the CollisionPoint, Impulse, etc. and then decide if the arrow penetrates or bounces off. This would then require me to do all the physics work myself in the "bounces off" case. I feel like this should be something that should eventually work out-of-the-box and is just not the case while in preview. So I may just wait until it's more baked.

    Anyways if you can think of anything else I'd love to talk more about it. Thanks! Also if you're curious how this is going and how I'm trying to get VR <> ECS working let me know and we can chat. Probs make a new thread for that though.
     
  2. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    Hello!

    Let me try to explain a bit how collision events work. Typically in contact solver we decide if a contact had an impulse applied in order to register a collision event. Then, we provide basic info (entities, bodies, normal) and later we calculate the more detailed info (impulse, position). The reason we calculate position later is because solver is optimized in a way that it doesn't ever work with positions, only velocities, so at the point where collision event is recorded we don't have access to contact point positions.

    The way we calculate collision position is an approximation, and can go wrong with high velocities and multiple contacts in a single frame. But what we basically do is take the old position, calculate time to hit the reported normal, subintegrate contact point by that time, and that's our position. It can obviously sometimes go wrong, especially if the body has high angular velocities.

    However, your case isn't that strange. What you are having is an arrow that should stick to where it hits and probably get stuck like that. What we are seeing is it sliding a bit more and having its tail also stick, which I assume is what you are trying to avoid.

    Now to me it seems like it should work out of the box if you were to do your job (and system) after export and before end frame system. Now you do need to remember previous component data, but only for rotation. What this gives you is that you can actually put your arrow's tip at the reported collision position (use CollisionEvent.CalculateDetails() to get this position), while keeping the Rotation coming from component data of the previous frame. If you just use the new position the arrow will most likely slide off to the side, since it's a rigid body, not something that gets stuck by default.
     
    cultureulterior and NotaNaN like this.
  3. Gen_Scorpius

    Gen_Scorpius

    Joined:
    Nov 2, 2016
    Posts:
    65
    I think it would be very helpful if the documentation of the physics package could be extended to cover more in-depth topics regarding the collision solving, e.g. the simplex solver as is used in the sample, whenever you have the time to do so.
     
  4. fomartin

    fomartin

    Joined:
    Aug 31, 2015
    Posts:
    17
    Thanks for the reply. I'll give it a try this weekend and report back here. Like we've said, this shouldn't be an uncommon thing (i.e. I want to check and set some stuff at collision time before calculations), so if I can get it work I'll post as well for others.
     
    petarmHavok likes this.
  5. fomartin

    fomartin

    Joined:
    Aug 31, 2015
    Posts:
    17
    Actually if you can help me out a bit more, what exactly is the systems should I update before and after?

    Code (CSharp):
    1. [UpdateAfter(typeof(ExportPhysicsWorld))]
    2. [UpdateBefore(typeof(EndFramePhysicsSystem))]
    3. public class ArrowCollisionSystem : SystemBase
    4. {
    5. ...
    6. }
    Just to make sure. :)
     
  6. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    Yes, just also make sure you get the EndFramePhysicsSystem member and call AddInputDependency on it with your last job's handle, so that it properly waits for your jobs to finish.
     
  7. fomartin

    fomartin

    Joined:
    Aug 31, 2015
    Posts:
    17
    Problem still persists. I went super debug-hacky mode and made my PreviousLocalToWorldUpdateSystem have the LocalToWorld of the last 3 frames:

    Code (CSharp):
    1. using System;
    2. using Unity.Entities;
    3. using Unity.Transforms;
    4.  
    5. namespace JuegosFrantasticos
    6. {
    7.     [Serializable]
    8.     public struct PreviousLocalToWorldComponent : IComponentData
    9.     {
    10.         public LocalToWorld PreviousValue;
    11.         public LocalToWorld PreviousPreviousValue;
    12.         public LocalToWorld PreviousPreviousPreviousValue;
    13.     }
    14. }
    Code (CSharp):
    1. using Unity.Collections;
    2. using Unity.Entities;
    3. using Unity.Jobs;
    4. using Unity.Transforms;
    5.  
    6. namespace JuegosFrantasticos
    7. {
    8.     [UpdateBefore(typeof(ArrowCollisionSystem))]
    9.     public class PreviousArrowLocalToWorldUpdateSystem : SystemBase
    10.     {
    11.         protected override void OnUpdate()
    12.         {
    13.             Entities
    14.                 .WithName("PreviousArrowLocalToWorldUpdateJob")
    15.                 .WithAll<ArrowTagComponent>()
    16.                 .ForEach(
    17.                     (ref PreviousLocalToWorldComponent previousLocalToWorld,
    18.                     in LocalToWorld localToWorld) =>
    19.                     {
    20.                         previousLocalToWorld.PreviousPreviousPreviousValue =
    21.                             previousLocalToWorld.PreviousPreviousValue;
    22.                         previousLocalToWorld.PreviousPreviousValue =
    23.                             previousLocalToWorld.PreviousValue;
    24.                         previousLocalToWorld.PreviousValue = localToWorld;
    25.                     })
    26.                 .Schedule();
    27.         }
    28.     }
    29. }
    Here's my updated ArrowCollisionSystem:

    Code (CSharp):
    1. using System.Linq;
    2. using Unity.Burst;
    3. using Unity.Collections;
    4. using Unity.Entities;
    5. using Unity.Jobs;
    6. using Unity.Mathematics;
    7. using Unity.Physics;
    8. using Unity.Physics.Systems;
    9. using Unity.Transforms;
    10.  
    11. namespace JuegosFrantasticos
    12. {
    13.     [UpdateAfter(typeof(ExportPhysicsWorld))]
    14.     [UpdateBefore(typeof(EndFramePhysicsSystem))]
    15.     public class ArrowCollisionSystem : SystemBase
    16.     {
    17.         private PhysicsWorld _physicsWorld;
    18.         private BuildPhysicsWorld _buildPhysicsWorld;
    19.         private StepPhysicsWorld _stepPhysicsWorld;
    20.         private EndFramePhysicsSystem _endFramePhysicsSystem;
    21.         private EntityQuery _rotationFollowsLinearVelocityGroup;
    22.         private EntityCommandBufferSystem _entityCommandBufferSystem;
    23.         private EntityQuery _arrowEntityGroup;
    24.  
    25.         protected override void OnCreate()
    26.         {
    27.             _buildPhysicsWorld = World.GetOrCreateSystem<BuildPhysicsWorld>();
    28.             _stepPhysicsWorld = World.GetOrCreateSystem<StepPhysicsWorld>();
    29.             _endFramePhysicsSystem = World.GetOrCreateSystem<EndFramePhysicsSystem>();
    30.  
    31.             _rotationFollowsLinearVelocityGroup =
    32.                 GetEntityQuery(new EntityQueryDesc
    33.                 {
    34.                     All = new ComponentType[]
    35.                     {
    36.                         typeof(RotationFollowsLinearVelocityComponent)
    37.                     }
    38.                 });
    39.  
    40.             _entityCommandBufferSystem =
    41.                 World.GetOrCreateSystem<EntityCommandBufferSystem>();
    42.  
    43.             _arrowEntityGroup = GetEntityQuery(new EntityQueryDesc
    44.             {
    45.                 All = new ComponentType[]
    46.                 {
    47.                     typeof(ArrowPenetrationComponent),
    48.                     typeof(LocalToWorld),
    49.                 }
    50.             });
    51.         }
    52.  
    53.         protected override void OnUpdate()
    54.         {
    55.             if (_rotationFollowsLinearVelocityGroup.CalculateEntityCount() == 0)
    56.             {
    57.                 return;
    58.             }
    59.  
    60.             CollisionJob collisionJob = new CollisionJob
    61.             {
    62.                 PhysicsWorld = _buildPhysicsWorld.PhysicsWorld,
    63.                 PhysicsVelocityGroup =
    64.                     GetComponentDataFromEntity<PhysicsVelocity>(true),
    65.                 PhysicsMassGroup =
    66.                     GetComponentDataFromEntity<PhysicsMass>(),
    67.                 ArrowPenetrationGroup =
    68.                     GetComponentDataFromEntity<ArrowPenetrationComponent>(),
    69.                 RotationFollowsLinearVelocityGroup =
    70.                     GetComponentDataFromEntity<RotationFollowsLinearVelocityComponent>(),
    71.                 PreviousLocalToWorldGroup =
    72.                     GetComponentDataFromEntity<PreviousLocalToWorldComponent>(true),
    73.                 LocalToWorldGroup =
    74.                     GetComponentDataFromEntity<LocalToWorld>(true),
    75.                 RotationGroup =
    76.                     GetComponentDataFromEntity<Rotation>(),
    77.                 TranslationGroup =
    78.                     GetComponentDataFromEntity<Translation>(),
    79.             };
    80.  
    81.             Dependency = collisionJob.Schedule(
    82.                 _stepPhysicsWorld.Simulation,
    83.                 ref _buildPhysicsWorld.PhysicsWorld,
    84.                 Dependency);
    85.  
    86.             AttachJob penetrationJob = new AttachJob
    87.             {
    88.                 EntityCommandBuffer =
    89.                     _entityCommandBufferSystem.CreateCommandBuffer().ToConcurrent(),
    90.                 ArrowPenetrationArchetypeChunk =
    91.                     GetArchetypeChunkComponentType<ArrowPenetrationComponent>(),
    92.                 EntityChunkType =
    93.                     GetArchetypeChunkEntityType()
    94.             };
    95.            
    96.             Dependency = penetrationJob.Schedule(_arrowEntityGroup, Dependency);
    97.  
    98.             _endFramePhysicsSystem.AddInputDependency(Dependency);
    99.         }
    100.  
    101.         [BurstCompile]
    102.         private struct CollisionJob : ICollisionEventsJob
    103.         {
    104.             [ReadOnly] public PhysicsWorld PhysicsWorld;
    105.             public ComponentDataFromEntity<PhysicsMass>
    106.                 PhysicsMassGroup;
    107.             public ComponentDataFromEntity<ArrowPenetrationComponent>
    108.                 ArrowPenetrationGroup;
    109.             public ComponentDataFromEntity<RotationFollowsLinearVelocityComponent>
    110.                 RotationFollowsLinearVelocityGroup;
    111.             public ComponentDataFromEntity<Rotation>
    112.                 RotationGroup;
    113.             public ComponentDataFromEntity<Translation>
    114.                 TranslationGroup;
    115.             [ReadOnly] public ComponentDataFromEntity<PreviousLocalToWorldComponent>
    116.                 PreviousLocalToWorldGroup;
    117.             [ReadOnly] public ComponentDataFromEntity<PhysicsVelocity>
    118.                 PhysicsVelocityGroup;
    119.             [ReadOnly] public ComponentDataFromEntity<LocalToWorld>
    120.                 LocalToWorldGroup;
    121.  
    122.             public void Execute(CollisionEvent triggerEvent)
    123.             {
    124.  
    125.                 bool isEntityARotationFollowsLinearVelocity =
    126.                     RotationFollowsLinearVelocityGroup.Exists(triggerEvent.EntityA);
    127.                 bool isEntityBRotationFollowsLinearVelocity =
    128.                     RotationFollowsLinearVelocityGroup.Exists(triggerEvent.EntityB);
    129.  
    130.                 if (isEntityARotationFollowsLinearVelocity && isEntityBRotationFollowsLinearVelocity
    131.                     || !isEntityARotationFollowsLinearVelocity && !isEntityBRotationFollowsLinearVelocity)
    132.                 {
    133.                     return;
    134.                 }
    135.  
    136.                 Entity arrowEntity;
    137.                 if (isEntityARotationFollowsLinearVelocity)
    138.                 {
    139.                     arrowEntity = triggerEvent.EntityA;
    140.  
    141.                     RotationFollowsLinearVelocityGroup[arrowEntity] =
    142.                         new RotationFollowsLinearVelocityComponent() { IsActive = false };
    143.                 }
    144.                 else if (isEntityBRotationFollowsLinearVelocity)
    145.                 {
    146.                     arrowEntity = triggerEvent.EntityB;
    147.  
    148.                     RotationFollowsLinearVelocityGroup[arrowEntity] =
    149.                         new RotationFollowsLinearVelocityComponent() { IsActive = false };
    150.                 }
    151.                 else
    152.                 {
    153.                     return;
    154.                 }
    155.  
    156.                 //TODO: Remove collider or make it not throw any more events.
    157.                 if(ArrowPenetrationGroup[arrowEntity].IsPenetrated)
    158.                 {
    159.                     return;
    160.                 }
    161.  
    162.                 PhysicsMassGroup[arrowEntity] = new PhysicsMass
    163.                 {
    164.                     InverseInertia = float3.zero,
    165.  
    166.                     Transform = PhysicsMassGroup[arrowEntity].Transform,
    167.                     InverseMass = PhysicsMassGroup[arrowEntity].InverseMass,
    168.                     AngularExpansionFactor = PhysicsMassGroup[arrowEntity].AngularExpansionFactor,
    169.                     CenterOfMass = PhysicsMassGroup[arrowEntity].CenterOfMass,
    170.                     InertiaOrientation = PhysicsMassGroup[arrowEntity].InertiaOrientation,
    171.                 };
    172.  
    173.                 Entity otherEntity = !isEntityARotationFollowsLinearVelocity
    174.                     ? triggerEvent.EntityA
    175.                     : triggerEvent.EntityB;
    176.  
    177.                 PreviousLocalToWorldComponent previousLocalToWorldComponent =
    178.                     PreviousLocalToWorldGroup[arrowEntity];
    179.  
    180.                 CollisionEvent.Details collisionDetails =
    181.                     triggerEvent.CalculateDetails(ref PhysicsWorld);
    182.  
    183.                 ArrowPenetrationGroup[arrowEntity] =
    184.                         new ArrowPenetrationComponent(
    185.                             arrowEntity,
    186.                             PreviousLocalToWorldGroup[arrowEntity].PreviousPreviousPreviousValue.Rotation,
    187.                             collisionDetails.AverageContactPointPosition,
    188.                             otherEntity);
    189.             }
    190.         }
    191.  
    192.         [BurstCompile]
    193.         private struct AttachJob : IJobChunk
    194.         {
    195.             public EntityCommandBuffer.Concurrent EntityCommandBuffer;
    196.             public ArchetypeChunkComponentType<ArrowPenetrationComponent>
    197.                 ArrowPenetrationArchetypeChunk;
    198.  
    199.             [ReadOnly]
    200.             public ArchetypeChunkEntityType EntityChunkType;
    201.  
    202.             public void Execute(
    203.                 ArchetypeChunk chunk,
    204.                 int chunkIndex,
    205.                 int firstEntityIndex)
    206.             {
    207.                 NativeArray<Entity> entities =
    208.                     chunk.GetNativeArray(EntityChunkType);
    209.                 NativeArray<ArrowPenetrationComponent> arrowPenetrationArray =
    210.                     chunk.GetNativeArray(ArrowPenetrationArchetypeChunk);
    211.  
    212.                 for (int i = 0; i < entities.Length; ++i)
    213.                 {
    214.                     if (arrowPenetrationArray[i].IsPenetrated)
    215.                     {
    216.                         EntityCommandBuffer.AddComponent(
    217.                             chunkIndex,
    218.                             entities[i],
    219.                             new Parent
    220.                             {
    221.                                 Value = arrowPenetrationArray[i].PenetratedObject
    222.                             });
    223.  
    224.                         EntityCommandBuffer.SetComponent(
    225.                             chunkIndex,
    226.                             entities[i],
    227.                             new Rotation
    228.                             {
    229.                                 Value = arrowPenetrationArray[i].ArrowRotation
    230.                             });
    231.  
    232.                         EntityCommandBuffer.SetComponent(
    233.                             chunkIndex,
    234.                             entities[i],
    235.                             new Translation
    236.                             {
    237.                                 Value = arrowPenetrationArray[i].ArrowTranslation
    238.                             });
    239.                     }
    240.                 }
    241.             }
    242.         }
    243.     }
    244. }
    I've added the suggested UpdateBefore and UpdateAfter, and got a reference to EndFramePhysicsSystem to call AddInputDependency(...). Maybe I'm doing dependency injection wrong?

    I'm going to change my PreviousLocalToWorldComponent to PreviousRotationComponent to make it easier to read and debug. Also might make the PreviousArrowLocalToWorldUpdateSystem stop updating after penetration to have a stream of previous rotations and make sure that it's setting it to the one before collision and not somehow still getting them post collision.
     
  8. fomartin

    fomartin

    Joined:
    Aug 31, 2015
    Posts:
    17
    Ok so issue still persists, but I changed PreviousLocalToWorldComponent to PreviousRotationComponent to get a better look in EntityDebugger:
    upload_2020-9-11_14-46-26.png

    So we can see that I'm it's setting ArrowPenetrationComponent.ArrowRotation = PreviousRotationComponent.PreviousPreviousPreviousValue correctly, but the Rotation component is still equal to PreviousRotationComponent.PreviousValue. If I had to guess PreviousValue is the post collision rotation and hence the weird post collision rotation. What's also weird is that Rotation value is slowly moving, as if still slightly has impulse, even though I set the InverseInertia to zero.
    Code (CSharp):
    1. PhysicsMassGroup[arrowEntity] = new PhysicsMass
    2.                 {
    3.                     InverseInertia = float3.zero,
    4.  
    5.                     Transform = PhysicsMassGroup[arrowEntity].Transform,
    6.                     InverseMass = PhysicsMassGroup[arrowEntity].InverseMass,
    7.                     AngularExpansionFactor = PhysicsMassGroup[arrowEntity].AngularExpansionFactor,
    8.                     CenterOfMass = PhysicsMassGroup[arrowEntity].CenterOfMass,
    9.                     InertiaOrientation = PhysicsMassGroup[arrowEntity].InertiaOrientation,
    10.                 };
    So my two next questions are the following:
    • Why is Rotation ~= PreviousRotationComponent.PreviousRotation, even though we're setting the Rotation component in Line 224 (inside the AttachJob)?
    • Why is Rotation still changing if InverseInertia == float3.zero?
    Will see if I can find out what's going on, but suggestions are welcome :)
     
  9. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    You are setting the output dependency correctly, just make sure to also get the output dependency of the export system as your input dependency. It does seem like something else is overriding values you are setting to rotation, and the export system is a good guess.
     
  10. fomartin

    fomartin

    Joined:
    Aug 31, 2015
    Posts:
    17
    Been working on this on and off for a while, to no avail. Think I'm gonna give it a rest and try again later. I'll make sure to come back here if I somehow figure it out. Thanks all :)
     
    petarmHavok likes this.