Search Unity

[Solved] 2x JobComponentSystem & commandBuffer : Value update lags behind

Discussion in 'Entity Component System' started by Antypodish, Aug 16, 2018.

  1. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    I have problem with value lagging behind, when dependent from more than one system.

    I am trying apply simplistic gravity force to a point in a space. As if moon orbiting earth (naming for reference)
    Earth is static and used as reference with 0 coordinates.
    While moon starts at 0,0,2. Which means, moon should move in oscilated manner, from on side to of earth, to the dark side, uhmm I mean other side of earth. And repeat over.

    However, oscillation is unstable, and accelerates over the number of iterations, due to lag between systems updates.


    2 Job Component System (s)
    To do this task I use 2 Job Component System (s), with each having command buffer.

    - First system is the Gravity System.
    It applies gravity as velocity, on any entity with Gravity Component

    - Second system, is the Move System
    It applies position displacement, according to velocity, of every entity with Velocity Component.

    Both systems use
    Code (CSharp):
    1. public void Execute () {}
    methods, in
    Code (CSharp):
    1. struct MyJob : IJob
    with for loop, where calculations happens, for relevant entities.

    - Gravity System applies velocity change and passes into command buffer, based on calculated gravity,
    which takes
    Code (CSharp):
    1. float3 f3_gravityDirection = ( targetPos - sourcePos ) ;
    In this case target position is moon, and source position is earth
    ... one liner velocity calculation here (bla bla) of f3_velocity
    And apply velocity to entity
    Code (CSharp):
    1. commandsBuffer.SetComponent ( targetEntity, new VelocityComponent { Value = f3_velocity } ) ;
    - Similarly Move System takes the velocity and calculates new position
    f3_position += f3_velocity ;
    commandsBuffer.SetComponent ( targetEntity, new Value{ Value = f3_position } ) ;


    Issue
    What happens now, is that in Gravity System, when position is taken at first step, and velocity passed to command buffer, Move System is taking yet old velocity, as command buffer didn't update it yet.
    Then Move System, calculates position based on old velocity, and passes to command buffer.
    And then similarly, Gravity System is taking old position and applies gravity (new velocity).
    So in the result, I am lagging 2 iterations behind, before getting actual value.

    Not only that.
    Because I get old value of position and velocity, I calculate incorrect gravity. Which in the result, over number of iterations, the Moon is oscillating further and faster. Until reaching critical position, making Value float3 infinity. Or NaN. Well of course is error anyway.


    Tried1
    So I tried put position update in Gravity System, instead in Move System, which works perfectly fine.
    Also tried set
    Code (CSharp):
    1. commandBuffer.PlayBack ( entityManager ) ;
    but I failed on that. Maybe I put in wrong place. I assume should be in
    Execute ()
    method of
    Code (CSharp):
    1. struct GravityJob : IJob
    Tried2
    Also attempted use
    Code (CSharp):
    1. [UpdateAfter ( typeof ( GravitySystem ) ) ]
    to Move system. But as expected, no difference.


    Question
    How do I force value to update, in command buffer, so ensuring, I have not value lagging effect.
    Or otherwise, how should I approach this problem, when there is circular value dependencies as position.
     
  2. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    Added short video, with the problem

    Blue box is pure ECS, with incorrect runaway behavior. Gravity center is yellow sphere.
    White box is OOP based gravity correct behavior. Gravity is on the right of starting position (invisible).
    I can achieve same result of OOP with pure ECS, if I have calculated both velocity and position set in the same job system.

    Starting point is irrelevant. The matter is the blue box runaway.



    Forgot to add, but if let running a bit longer, then it start throwing errors about AABB, beyond valid position.
     
  3. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    You need to update after your barrier, not system

    [UpdateAfter(typeof(Barrier))]


    Side note, there is a move system included with the entity package - look at MoveForwardSystem.
     
  4. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    Hi thx for a tip.

    See Edit3 below:

    Only the problem I am facing now, when applying
    [UpdateAfter(typeof(Barrier))]

    I got error

    ArgumentException: It is not allowed to have two components of the same type on the same entity. (TransformMatrix and TransformMatrix)

    Full error
    ArgumentException: It is not allowed to have two components of the same type on the same entity. (TransformMatrix and TransformMatrix)
    Unity.Entities.ArchetypeManager.AssertArchetypeComponents (Unity.Entities.ComponentTypeInArchetype* types, System.Int32 count) (at C:/Users/.../AppData/Local/Unity/cache/packages/packages.unity.com/com.unity.entities@0.0.12-preview.4/Unity.Entities/ArchetypeManager.cs:309)
    Unity.Entities.ArchetypeManager.GetOrCreateArchetype (Unity.Entities.ComponentTypeInArchetype* types, System.Int32 count, Unity.Entities.EntityGroupManager groupManager) (at C:/Users/.../AppData/Local/Unity/cache/packages/packages.unity.com/com.unity.entities@0.0.12-preview.4/Unity.Entities/ArchetypeManager.cs:346)
    Unity.Entities.EntityDataManager.AddComponent (Unity.Entities.Entity entity, Unity.Entities.ComponentType type, Unity.Entities.ArchetypeManager archetypeManager, Unity.Entities.SharedComponentDataManager sharedComponentDataManager, Unity.Entities.EntityGroupManager groupManager, Unity.Entities.ComponentTypeInArchetype* componentTypeInArchetypeArray) (at C:/Users/.../AppData/Local/Unity/cache/packages/packages.unity.com/com.unity.entities@0.0.12-preview.4/Unity.Entities/EntityDataManager.cs:443)
    Unity.Entities.EntityManager.AddComponent (Unity.Entities.Entity entity, Unity.Entities.ComponentType type) (at C:/Users/.../AppData/Local/Unity/cache/packages/packages.unity.com/com.unity.entities@0.0.12-preview.4/Unity.Entities/EntityManager.cs:375)
    Unity.Entities.EntityCommandBuffer.Playback (Unity.Entities.EntityManager mgr) (at C:/Users/.../AppData/Local/Unity/cache/packages/packages.unity.com/com.unity.entities@0.0.12-preview.4/Unity.Entities/EntityCommandBuffer.cs:451)
    Unity.Entities.BarrierSystem.FlushBuffers (System.Boolean playBack) (at C:/Users/.../AppData/Local/Unity/cache/packages/packages.unity.com/com.unity.entities@0.0.12-preview.4/Unity.Entities/ComponentSystem.cs:551)
    Unity.Entities.BarrierSystem.OnUpdate () (at C:/Users/.../AppData/Local/Unity/cache/packages/packages.unity.com/com.unity.entities@0.0.12-preview.4/Unity.Entities/ComponentSystem.cs:538)
    Unity.Entities.ComponentSystem.InternalUpdate () (at C:/Users/.../AppData/Local/Unity/cache/packages/packages.unity.com/com.unity.entities@0.0.12-preview.4/Unity.Entities/ComponentSystem.cs:290)
    Unity.Entities.ScriptBehaviourManager.Update () (at C:/Users/.../AppData/Local/Unity/cache/packages/packages.unity.com/com.unity.entities@0.0.12-preview.4/Unity.Entities/ScriptBehaviourManager.cs:82)
    Unity.Entities.ScriptBehaviourUpdateOrder+DummyDelagateWrapper.TriggerUpdate () (at C:/Users/.../AppData/Local/Unity/cache/packages/packages.unity.com/com.unity.entities@0.0.12-preview.4/Unity.Entities/ScriptBehaviourUpdateOrder.cs:732)

    Ok, I do understand that I can not have multiple components of the same type. But without
    [UpdateAfter(typeof(Barrier))]
    It works and do not complain.

    But since this error, I don't know what is the issue exactly. I tried not to add any components. I tried strip system form almost everything. And few other things.

    On the video, I show where I press on entity. There is no duplicates. Unless Position and Rotation are treated as separate TransfomMatrix, hence error?

    Also MeshInstanceRenderer need scaling, so nee TransformMatrix.
    Entity 0 holds even less components.

    Atm. I am unable to narrow down the issue.

    One of my systems, InputSystem, is one which allow to accept
    [UpdateAfter(typeof(Barrier))]
    But it does not use JobComponentSystem. And after that, inputs are not processed.
    But is not where UpdateAfter should be. It was just to check, if this is global issue, or per script/System.

    Any thought?

    Edit1:
    Also came to realization, by rewatching video, that position.z component, is not matching TransformMatrix position.z properties. Is also lagging. I thought, setting position directly sets matrix. But seams there is another system to do so.

    Edit2:
    Yes I am aware of forward component. But I haven't really used it yet. I may check, but I need move any direction, not only forward (my assumption).

    Edit3:
    I think I resolved issue with [UpdateAfter(typeof(Barrier))] itself. At least I have no errors. But I am still missing something, as it still running away.

    Edit4:
    Looking at GravityDemo. Withouth earlier realization, I followed very similar steps, as in the demo. It has AsteroidMove and Gravity systems. However, AsteroidMove has [UpdateAfter(typeof(GravitySystem))]. And somehow it works. Now I am baffled. I will try compare and see, what major difference is, between my and GravityDemo. One thing for sure is, Demo uses SomeJob:IJobParallelFor, where I use SomeJob:IJob Wonder if this has anything to do?
     
    Last edited: Aug 16, 2018
  5. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    Right, finally got resolve solution.
    As per Edit4 I did follow GravityDemo example.

    I did replace cuouple elements in move and gravity systems.
    - I changed struct (s) MyJob from IJob, to IJObParallelFor
    - changed public void Execute() to public void Execute(int index)
    - modified slightly Data structs, with addition of public readonly int Length;

    In JobHandle
    - OnUpdate(JobHandle inputDeps), I changed return new GravityJob to var jobHandle = new GravityJob. Similarly in MoveSystem.
    - // }.Schedule(inputDeps) ; // for IJob was replaced with }.Schedule( data.Length, 64, inputDeps) ; // for IJobParallelFor
    - and finally adding return jobHandle ; // for IJobParallelFor

    On top of that
    - MoveInstanceSystem : JobComponentSystem, has now [UpdateAfter ( typeof ( GravitySystem ) ) ]
    - barrier was removed, which previously was used for commandsBuffer.SetComponent ( ... ) ;
     
  6. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    I thought I will share, some experimental results.

    Some gravity, mouse raycasting + key inputs mix, with Pure ECS.

     
  7. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    Looks cool, but you're getting some pretty big frame spikes in there. Should look to remove those, any idea of the cause?

    -edit- oh, maybe just just console debugging?
     
  8. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    Just double checked.
    You may notice in very left bottom corner, is console Debug.Log () messages.
    Basically I am logging clicks and created entity ID. So it will be major contributor to the spikes.
    I have noticed also Overhead, periodical spikes, like Rendering EarlyUpdate.PlayerCleanupCacheData. But this is for smaller count of entities around 0.24 ms.

    Edit:
    >> TexRendering.CleanUp.