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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question [1.0.0-pre.15] Unable to create ECS Transform hierarchy in code

Discussion in 'Entity Component System' started by stu_g, Dec 11, 2022.

  1. stu_g

    stu_g

    Joined:
    Feb 13, 2016
    Posts:
    5
    Hi all,

    I have been trying for a few days to get an entity hierarchy happening just using code (no GameObjects). I have something like the following:

    Code (CSharp):
    1.             var topEntity = ecb.CreateEntity();
    2.             ecb.SetName(topEntity, "Parent");
    3.             ecb.AddComponent<LocalTransform>(topEntity);
    4.             ecb.SetComponent(topEntity, new LocalTransform { Position = new float3(1, 1, 1) });
    5.             ecb.AddComponent<LocalToWorld>(topEntity);
    6.             ecb.AddComponent<WorldTransform>(topEntity);
    7.  
    8.             var childEntity = ecb.CreateEntity();
    9.             ecb.SetName(topEntity, "Child");
    10.             ecb.AddComponent<LocalTransform>(childEntity);
    11.             ecb.SetComponent(childEntity, new LocalTransform { Position = new float3(2, 2, 2) });
    12.             ecb.AddComponent<LocalToWorld>(childEntity);
    13.             ecb.AddComponent<WorldTransform>(childEntity);
    14.             ecb.AddComponent<ParentTransform>(childEntity);
    15.             ecb.AddComponent(childEntity, new Parent { Value = topEntity });
    The entities appear in the hierarchy correctly. My understanding is that that LocalToWorld xyz show the actual location of the entity in the world. Parent above shows (1,1,1) as expected. Child I would expect to show (3,3,3) as it takes into account it's own LocalTransform and the parent's too. However when I run the code the Child has (1,1,1) as it's LocalToWorld.

    When I set up exactly the same as above using GameObjects it works as expected and the child has (3,3,3). Does anyone know why this is happening? There is very little documentation or example code regarding this setup which seems like it should be fairly straightforward.

    Thanks!

    Stu
     
  2. stu_g

    stu_g

    Joined:
    Feb 13, 2016
    Posts:
    5
    Just bumping this .. does anyone have an example of working code using 1.0.0 that creates a working transform hierarchy from code please? I must be doing something wrong but I can't find any sample code for creating a transform hierarchy using the latest version.
     
  3. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    3,885
    Also having issues with LocalToWorld not working, what is the correct way to replace this? It would be nice if breaking changes like this were made clearer to users
     
  4. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    3,885
  5. argibaltzi

    argibaltzi

    Joined:
    Nov 13, 2014
    Posts:
    218
    I have problem with transforms on children of rigidbodies (all setup done manually via code)
    Rigid Body Parent
    Mesh Child

    The children are always at 0,0,0
    Things dont work as expected with transforms in 1.0, there are hidden components or something i dont know
     
  6. desper0s

    desper0s

    Joined:
    Aug 4, 2021
    Posts:
    14
    You need to setup LinkedEntityGroup, LocalTransform and Parent components when creating entities. Others like Child, ParentTransform are calculated automatic by Unity internal systems.
     
  7. argibaltzi

    argibaltzi

    Joined:
    Nov 13, 2014
    Posts:
    218
    When the parent becomes a rigid body though the children stop getting updated.
     
  8. FONTOoMas

    FONTOoMas

    Joined:
    Sep 26, 2015
    Posts:
    7
    Maybe they become unparented.
    upload_2022-12-21_2-0-59.png
     
  9. argibaltzi

    argibaltzi

    Joined:
    Nov 13, 2014
    Posts:
    218
    baking works fine, the problems rise when doing things via code. Simply adding physics velocity and the other components to make an entity a dynamic body, makes the children stop updating
     
  10. argibaltzi

    argibaltzi

    Joined:
    Nov 13, 2014
    Posts:
    218
    you need to add this on the root object for children to work

    entityManager.AddComponentData<PropagateLocalToWorld>(entity, new PropagateLocalToWorld() { });
     
  11. stu_g

    stu_g

    Joined:
    Feb 13, 2016
    Posts:
    5
    Thanks for the help above but I still haven't been able to solve this. I really love the idea of ECS and DOTS but I don't think I'm alone in saying that finding good examples and clear documentation is very hard and frustrating.

    I would have thought that a pure ECS approach to constructing a transform hierarchy using 1.0.0 would be a core concept that needs to be documented, working and have clear examples. Too often the documents are outdated, moved or don't match the actual behaviour .. or as in my case only cover using a hybrid approach and not an approach that doesn't use GameObjects.

    Can anyone show me some code that achieves what is in the above code sample and actually works .. please? =)
     
    Ndogg27 and DustinMatthew like this.
  12. mcapdegelle

    mcapdegelle

    Joined:
    Nov 7, 2014
    Posts:
    29
    Can't see anything wrong with your parenting.
    Are those entities static?
    In that case, maybe the LocalToWorldSystem filters out their update thinking they didn't changed.
    Try to remove the WorldTransform & ParentTransform Components on both entities. The LocalToWorldSystem adds them anyway, and it should trigger an update.
     
  13. mcapdegelle

    mcapdegelle

    Joined:
    Nov 7, 2014
    Posts:
    29
    Oh and don't forget to setup scale & rotation in your LocalTransform, or the scale will be 0 and the entity won't be visible.

    Code (CSharp):
    1. new LocalTransform { Position = new float3(1, 1, 1), Scale = 1, Rotation = quaternion.identity }
    Actually, this might be the problem...
     
    Last edited: Jan 24, 2023
  14. nanaktaev

    nanaktaev

    Joined:
    May 21, 2022
    Posts:
    10
    I have the same issue. Parent component just disappears from the child entity (or is not created in the first place).
     
  15. nanaktaev

    nanaktaev

    Joined:
    May 21, 2022
    Posts:
    10
    @stu_g did you manage to make it?
     
  16. nanaktaev

    nanaktaev

    Joined:
    May 21, 2022
    Posts:
    10
    I end up making my own primitive parenting system for now.
     
  17. SGStino

    SGStino

    Joined:
    Jul 8, 2014
    Posts:
    10
    I wrote a unit(y) test just to check my own sanity. This is what I ended up with that seems to be working
    Code (CSharp):
    1.  
    2.     [Test]
    3.     public void TestParenting()
    4.     {
    5.         var parent = EntityManager.CreateEntity();
    6.         var child = EntityManager.CreateEntity();
    7.  
    8.         EntityManager.AddComponentData(parent, new LocalTransform() { Position = float3(0, -1, 0), Rotation = Unity.Mathematics.quaternion.identity, Scale = 1 });
    9.         EntityManager.AddComponentData(child, new LocalTransform() { Position = float3(0, 2, 0), Rotation = Unity.Mathematics.quaternion.identity, Scale = 1 });
    10.         EntityManager.AddComponent<LocalToWorld>(parent);
    11.         EntityManager.AddComponent<LocalToWorld>(child);
    12.         World.Update();
    13.         EntityManager.AddComponentData<Parent>(child, new Parent { Value = parent });
    14.         World.Update();
    15.  
    16.         Assert.IsTrue(EntityManager.HasComponent<Parent>(child), "child should have the parent component");
    17.         Assert.IsTrue(EntityManager.HasBuffer<Child>(parent), "parent should have the child buffer");
    18.  
    19.      
    20.         var childWorld = EntityManager.GetComponentData<WorldTransform>(child);
    21.         Assert.AreEqual(float3(0, 1, 0), childWorld.Position, "child should be at 0, 1, 0");
    22.  
    23.  
    24.         EntityManager.SetComponentData(parent, new LocalTransform
    25.         {
    26.             Position = float3(1, 0, 1),
    27.             Rotation = Unity.Mathematics.quaternion.identity,
    28.             Scale = 1
    29.         });
    30.  
    31.         World.Update();
    32.      
    33.         childWorld = EntityManager.GetComponentData<WorldTransform>(child);
    34.         Assert.AreEqual(float3(1, 2, 1), childWorld.Position, "child should be at 1, 2, 1 after moving the parent");
    35.     }
    What strikes me as odd is that the WorldTransform gets added automatically by the LocalToWorldSystem:
    Code (CSharp):
    1.  
    2.             if (!_entityWithoutWorldTransformQuery.IsEmptyIgnoreFilter)
    3.                 state.EntityManager.AddComponent(_entityWithoutWorldTransformQuery, ComponentType.ReadWrite<WorldTransform>());
    4.             if (!_parentWithoutParentTransformQuery.IsEmptyIgnoreFilter)
    5.                 state.EntityManager.AddComponent(_parentWithoutParentTransformQuery, ComponentType.ReadWrite<ParentTransform>());
    6.             if (!_parentTransformWithoutParentQuery.IsEmptyIgnoreFilter)
    7.                 state.EntityManager.RemoveComponent(_parentTransformWithoutParentQuery, ComponentType.ReadWrite<ParentTransform>());
    But the LocalToWorld component doesn't get added, so if you add that manually, then the system's main query picks up your entity:
    Code (CSharp):
    1.  var builder = new EntityQueryBuilder(Allocator.Temp)
    2.                 .WithAll<LocalTransform>()
    3.                 .WithAllRW<WorldTransform, LocalToWorld>()
    4.                 .WithNone<Parent>()
    5.                 .WithOptions(EntityQueryOptions.FilterWriteGroup);
    6.             _rootsQuery = state.GetEntityQuery(builder);
    and then the hierarchy starts working if you add a Parent component, where you can move the parent, and the child moves with it
     
    nanaktaev likes this.
  18. nanaktaev

    nanaktaev

    Joined:
    May 21, 2022
    Posts:
    10
    Thanks! It helped a lot.
    Also: it's enough to set LocalToWorld only for Parent entity.