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

Gameobject Converted Hierarchy Transformation

Discussion in 'Entity Component System' started by sebas77, Apr 30, 2019.

  1. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,630
    I am having great difficulty to understand where the logic of the hierarchical transformation of an entity converted from a gameobject is.

    I am currently setting the position and rotation on a parent entity, but the position and rotation of the children are not updating and I can't figure out why.
     
    Last edited: Apr 30, 2019
  2. runner78

    runner78

    Joined:
    Mar 14, 2015
    Posts:
    764
  3. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    sebas77 likes this.
  4. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,630
    Thanks, for the root position in Local space should be the equivalent of the world space, am I right? I wrote an engine to operate only on the roots of the hierarchies, but either using the Translation and Rotation and using the LocalToWorld, I don't see the children being translated by the parent offset.
    It works only for entities without hierarchy. Currently I am using the LocalToWorld as it is actually better for my flow and I remove the Translation and Rotation components from the parents to avoid to the matrix be overwritten. Still the children remain unaffected. Help?
     
    Last edited: May 1, 2019
  5. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,655
    Not. It's position relative to your parent entity. If your parent on (0,1,0) and your child in center of your parant your child has (0,0,0) coords in local space, and (0,1,0) in world space from local to world matrix. And if you moving parent, for example, to (0,5,0) you child still on (0,0,0) in local space. in world space (from local to world matrix) they have same (0,5,0) position but if you move child relative to parent, for example to (0,1,0) in this case your parent have (0,5,0) and child (0,6,0) in world space.
     
  6. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,630
    Thanks, a root doesn't have a parent though. In any case I am trying the local to world route and still failing to see the children being transformed by the parent root transformation
     
  7. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,655
    On root of course local and world positions the same
     
    sebas77 likes this.
  8. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,630
    Please check my code:

    https://hastebin.com/ohovuqaqak.cpp

    This is my workflow:

    The artists create the prefabs as they used to (more or less), the code converts these prefabs in entity prefabs, using the code:

    Code (CSharp):
    1. if (renderWorld != null)
    2.             {
    3.                 prefabEntityID=
    4.                     GameObjectConversionUtility.ConvertGameObjectHierarchy(prototypeGameObject.Result, renderWorld);
    5.            
    6.                 renderWorld.EntityManager.AddSharedComponentData(prefabEntityID, new UECSResourceGroup(prefabID));
    7.                 renderWorld.EntityManager.AddComponent(prefabEntityID, ComponentType.ReadWrite<SveltoEGID>());
    8.        
    9.                 renderWorld.EntityManager.RemoveComponent<Translation>(prefabEntityID);
    10.                 renderWorld.EntityManager.RemoveComponent<Rotation>(prefabEntityID);
    11.                 renderWorld.EntityManager.RemoveComponent<NonUniformScale>(prefabEntityID);
    12.             }

    Anytime I need a new entity, I then instantiate the prefab using this code:

    Code (CSharp):
    1. var entity = manager.Instantiate(prefabEntityID);
    In the JobComponentSystem, I iterate all the entities with the following components:

    typeof(LocalToWorld), typeof(SveltoEGID), typeof(UECSResourceGroup)

    SveltoEGID is currently used in this context only to mark the root prefabs, as I want to iterate only the root (currently I didn't find another way to identify roots of gameobject hierarchies).

    I remove the Translation,Rotation and NonUniformScale from the prefab for the purpose to disable all the systems that write in the LocalToWorld matrix, as deducted from Joachim advices.

    I store in the _instanceData system field, all the entities grouped by prefabID (resourceStructResourceId). If there entities, then I schedule a job to apply the transformation matrix to this set of entities. I set a group filter to be sure that I am going to iterate only the entities with that resourceID.

    var uecsResourceGroup = new UECSResourceGroup(resourceStructResourceId); is a SCD that I use only to group the UECS entities by resource ID

    As result I expect that all the roots of the instances generated by the prefabID gameobjects will be iterated and the LocalToWorld set.

    I also expect that the children of these roots are transformed by this matrix, but this is NOT happening and it's my current problem I seed advice of.

    as side note "DO_THIS_ONCE_THE_SCD_WORKS" is currently disabled because of the problem that for some specific gameobjects the SCD is not working, generating a chunk for each entity as opposite of a chunk for each prefabid

    Note: please check the way I am scheduling the jobs too. I am not sure it's the optimal way. These jobs should be scheduled in parallel and not in serial, plus the entity debugger shows the entities touched by the last job scheduled and not all of them
     
    Last edited: May 1, 2019
  9. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    UECSResourceGroup being a shared component doesn't seem like a reasonable approach.

    Using IComponentData on the root and then scan to find the right one is better.

    LinkedEntityGroup already exists and makes Instantiate / Destroy perform those operations in whole groups (Remapping internal references). So LinkedEntityGroup already stores references to all entities in the same group.
    This is automatically added to any referenced prefabs that are being converted.
     
    sebas77 likes this.
  10. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,655
    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using Unity.Burst;
    5. using Unity.Collections;
    6. using Unity.Collections.LowLevel.Unsafe;
    7. using Unity.Entities;
    8. using Unity.Jobs;
    9. using Unity.Mathematics;
    10. using Unity.Rendering;
    11. using Unity.Transforms;
    12. using UnityEngine;
    13. using UnityEngine.Rendering;
    14.  
    15. public struct MyRoot : IComponentData
    16. {
    17.    
    18. }
    19.  
    20. public class TestSystem : MonoBehaviour
    21. {
    22.     public GameObject prefab;
    23.  
    24.     private void Start()
    25.     {
    26.         var w = World.Active;
    27.         var em = w.EntityManager;
    28.         var prefabEntityID =
    29.             GameObjectConversionUtility.ConvertGameObjectHierarchy(prefab, w);
    30.          
    31.         em.AddComponent(prefabEntityID, ComponentType.ReadWrite<MyRoot>());
    32.      
    33.         em.RemoveComponent<Translation>(prefabEntityID);
    34.         em.RemoveComponent<Rotation>(prefabEntityID);
    35.         em.RemoveComponent<NonUniformScale>(prefabEntityID);
    36.  
    37.         em.Instantiate(prefabEntityID);
    38.     }
    39. }
    40.  
    41. public class RootRotateSystem: JobComponentSystem
    42. {
    43.     private EntityQuery query;
    44.    
    45.     protected override void OnCreate()
    46.     {
    47.         query = GetEntityQuery(typeof(Rotation), typeof(MyRoot));
    48.     }
    49.  
    50.     [BurstCompile]
    51.     [RequireComponentTag(typeof(MyRoot))]
    52.     public struct MoveRootJob : IJobForEachWithEntity<LocalToWorld>
    53.     {
    54.         public float time;
    55.        
    56.         public void Execute(Entity entity, int index, ref LocalToWorld m)
    57.         {
    58.             var pos = m.Value.c3;
    59.             pos.y = math.sin(time) * 2f;
    60.             m.Value.c3 = pos;
    61.         }
    62.     }
    63.  
    64.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    65.     {
    66.         return new MoveRootJob()
    67.         {
    68.             time = Time.time
    69.         }.Schedule(this, inputDeps);
    70.     }
    71. }
    72.  
     
    sebas77 likes this.
  11. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,655
    Just FYI.
    Don't forget you remove it's only from prefab root, not from childs :)
     
    sebas77 likes this.
  12. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,655
    Root has LocalToWorld but hasn't LocalToParent, just querying LocalToWorld with exclude LocalToParent return all roots for us, isn't it?
     
    sebas77 likes this.
  13. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,630
    Hey thank you a lot for helping me figuring this out.

    I assumed that removing the components from the prefabs would be enough. Was I wrong? If so I where does the instance process take the components from (I guess the original archetype?). I am going to try this!
     
  14. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,630
    I am not sure I get this. In my case I am grouping the blocks by block type (cube, motor, battery and so on). I do not know beforehand the types of blocks the game is going to have as it's data driven, therefore I cannot attach a CubeComponent, BatteryComponent and so on the various entities. I do have IDs though (the resource ID), therefore I use a SCD (and it's hashing uniqueness) to group the blocks of type 1, 2, 3 and so on.

    I will research about LinkedEntityGroup, I assumed it was the list of children of the root, but from your words it seems to be something else that I am not getting yet.
     
  15. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,655
    Edit:
    Rewrite this answer for better understanding.
    Prefab it's just one entity, when you delete\add components to this it's of course not affect childs. When you instantiate prefab (which has LinkedEntityGroup which has child entities and root byself) it's instantiate all entities from LinkedEntityGroup
    upload_2019-5-1_14-35-45.png
     
    Last edited: May 1, 2019
  16. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,655
    It's buffer with root and all childs, it's group of entities which should be deleted (as example) when you destroy this root entity, or which slould be instantiated when you instantiate this root. It's in very simple words of course.
     
    Last edited: May 1, 2019
  17. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,630
    if I understood correctly, children do not have translation/rotation/scaling by default

    edit: I was wrong, they have it, going to think about it
     
  18. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,655
    They have
     
  19. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,630
    indeed
     
  20. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,630
    OK Rotation and Translation removed from the children and unluckily the behavior is still the same.

    I can see that the System EndFrameParentSystem is called as expected and the right entities are processed.

    I can see that the roots have the right LocalToWorld matrices set.
    upload_2019-5-1_14-26-59.png

    However Children LocalToWorld are unaffected:

    upload_2019-5-1_14-27-25.png

    systems running:

    upload_2019-5-1_14-54-15.png

    Edit: I forced the LocalToParent matrix to be identity, no changes

    Side question: can I combine the same job multiple times?
    if I do
    previousJob = JobHandle.CombineDependencies(previousJob, currentjob.Schedule()); although a computational waste, will the result be the same than passing the array of jobs?
     
    Last edited: May 1, 2019
  21. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,630
    @eizenhorn extra thank you for the video btw
     
  22. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,655
    FYI. LocalToParent system responsible for LocalToWorld matrices updating in UpdateHierarchy job. Show your EntityDebugger for EndFrameLocalToParentSystem and EndFrameParentSystem. Especially Child buffer from entity in LocalToParentSystem
     
    Last edited: May 1, 2019
  23. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,630
    @eizenhorn I can see that EndFrameToLocalParentSystem needs the child component

    upload_2019-5-1_16-29-19.png
     
  24. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,630
    I understood that the EndFrameParentSystem should create the hierarchy, but it's not, so I am trying to debug it now.

    Update: The system is created, but not updated once

    Even today I have to go home defeated. The System is not running because the query

    Code (CSharp):
    1. m_NewParentsGroup = GetEntityQuery(new EntityQueryDesc
    2.             {
    3.                 All = new ComponentType[]
    4.                 {
    5.                     ComponentType.ReadOnly<Parent>(),
    6.                     ComponentType.ReadOnly<LocalToWorld>(),
    7.                     ComponentType.ReadOnly<LocalToParent>()
    8.                 },
    9.                 None = new ComponentType[]
    10.                 {
    11.                     typeof(PreviousParent)
    12.                 },
    13.                 Options = EntityQueryOptions.FilterWriteGroup
    14.             });
    is always empty.

    This may be true because of at the begin entities are ONLY prefabs, however once I instantiated entities in run-time nothing changes, although the entity debugger doesn't agree as

    upload_2019-5-1_18-7-12.png

    is obviouslyt not 0
     
    Last edited: May 1, 2019
  25. sebas77

    sebas77

    Joined:
    Nov 4, 2011
    Posts:
    1,630
    I think I finally got some progress, It appears to be the case that if I remove the Translation and Rotation before the children hierarchy is computed, I have to compute the LocalToParent matrix myself.

    Progress 2: I actually do not need to do that, as in order to use my own LocalToWorld matrix, I have to remove the TRS components only from the root and not the children. I now need to understand why this wasn't previously working.

    Progress 3: because of a mistake the TransformSystemGroup was disabled, duh! Note: It was totally not obvious from the debugger (see my previous screenshots) that the TransformSystemGroup was disabled. This should really be highlighted better!

    So in conclusion in order to do what I needed to, I just have to do remove the TRS components from the root and that's it.

    Thank you all for all the help! At least now I have 100% more knowledge of UECS
     
    Last edited: May 2, 2019
  26. sigil_tech

    sigil_tech

    Joined:
    Sep 18, 2019
    Posts:
    17
    world.active no longer working as second input..