Search Unity

How to setup entities with a random material, scale and position on startup?

Discussion in 'Entity Component System' started by Arowx, May 11, 2020.

  1. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    I'm using a system to randomly re-arrange items in a scene and also need to setup random materials from an array/list...

    Two issues:
    1. How do you pass into a System the array of materials, with components you just set the array as public and then set it up in the editor. It would be cool if this were possible with systems?
    2. Where is the material and colour settings for entities that the system can then change?
    PS I'm using Tiny does that make a difference?
     
    Last edited: May 11, 2020
  2. vildauget

    vildauget

    Joined:
    Mar 10, 2014
    Posts:
    121
    1. One possible way might be to put a component in its own entity and call it a singleton,
    https://docs.unity3d.com/Packages/c...ity_Entities_EntityQuery_SetSingleton__1___0_

    Works fine for me as test here, but I set all values in code so far;

    Code (CSharp):
    1. // GLOBAL SETTINGS AS SINGLETON ENTITY
    2.         var globalSettingsEntity = manager.CreateEntity(typeof(GlobalSettings));
    3.         manager.SetName(globalSettingsEntity, "GlobalSettings");
    4.         var globalSettingsEntityQuery = manager.CreateEntityQuery(typeof(GlobalSettings));
    5.         globalSettingsEntityQuery.SetSingleton<GlobalSettings>(new GlobalSettings
    6.         {
    7.             Awesomeness= 7,
    8.             floatiness = 1.2f,
    9.             worldSquareSize = 100,
    10.             worldSquareCreateDistance = 1,
    11.             seed = 12345,
    12.             metersBetweenVerts = 10
    13.         });
    14.         GlobalSettings settings = globalSettingsEntityQuery.GetSingleton<GlobalSettings>();
    15.         settings.Awesomeness = 5;
    2. material is part or the Shared component RenderMesh;

    Code (CSharp):
    1. EntityManager.SetSharedComponentData<RenderMesh>(entity, new RenderMesh
    2.             {
    3.                 mesh = mesh,
    4.                 material = material,
    5.                 castShadows = ShadowCastingMode.On,
    6.                 receiveShadows = true,
    7.                 //needMotionVectorPass = true
    8.             });
     
  3. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    My workaround was to just assign the game objects with different materials and allow the random translation to randomise them.

    Another issue is with Scale I would like to randomly scale them but this seems impossible...?

    I've tried including Scale, NonUniformScale, LocalToWorld to the System that updated them and then applying a scale setting to each of them but nothing works?

    Seems very odd that I can Translate and Rotate (two seperate systems) entities but not update their scale?
     
  4. vildauget

    vildauget

    Joined:
    Mar 10, 2014
    Posts:
    121
  5. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    I've tried that.

    Actually the diagrams seem to hint at the need for Translate, Rotate and Scale (or NonUnifromScale) to be present along with LocalToWorld or to act on LTW...

    For such a fundamental aspect of the DOTS system some simple code examples should be included.
     
  6. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    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.Transforms;
    7. using UnityEngine;
    8. //using static Unity.Mathematics.math;
    9. using Rnd = Unity.Mathematics.Random;
    10.  
    11. public class CellCreationSystem : SystemBase
    12. {  
    13.     protected override void OnUpdate()
    14.     {
    15.         Rnd rnd = new Rnd((uint)(Time.ElapsedTime*1000f+1f));
    16.         float radius = 50f;
    17.      
    18.         // Entities.ForEach((ref Scale scale, ref Cell cell) =>     // Does not work
    19.         Entities.ForEach((ref Translation trans, ref Cell cell) => // DOES WORK
    20.         {          
    21.             float3 t = rnd.NextFloat3(-1f, 1f) * radius;
    22.             float s = rnd.NextFloat(1f, 20f);
    23.  
    24.             //scale.Value = s;  // This does not work
    25.             trans.Value = t;    // This works
    26.                              
    27.             //ltw.Value *= float4x4.TRS(t, quaternion.identity, new float3(s)); // this does not work
    28.  
    29.         }).Run();
    30.  
    31.         //this.Enabled = false; // run once
    32.     }
    33. }
    Just scaling does not work TRS fails to move and scale???

    I'm confused why something so fundamental and simple does not work.

    Tempted to use my manual workaround of scaling them in editor...
     
    Last edited: May 15, 2020
  7. florianhanke

    florianhanke

    Joined:
    Jun 8, 2018
    Posts:
    426
    Have you checked the Entity Debugger if your cells are picked up by the systems in the TransformSystemGroup?
     
  8. MhmdAL1111

    MhmdAL1111

    Joined:
    Oct 25, 2017
    Posts:
    30
    Code (CSharp):
    1. ltw.Value = float4x4.TRS(ltw.Position, ltw.Rotation, new float3(2));
    This works for me
     
  9. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    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.Transforms;
    7. using UnityEngine;
    8. //using static Unity.Mathematics.math;
    9. using Rnd = Unity.Mathematics.Random;
    10.  
    11. public class CellCreationSystem : SystemBase
    12. {
    13.     protected override void OnUpdate()
    14.     {
    15.         Rnd rnd = new Rnd((uint)(Time.ElapsedTime*1000f+1f));
    16.         float radius = 50f;
    17.  
    18.         // Entities.ForEach((ref Scale scale, ref Cell cell) =>     // Does not work
    19.         //Entities.ForEach((ref Translation trans, ref Cell cell) => // DOES WORK
    20.         Entities.ForEach((ref LocalToWorld ltw, ref Cell cell) => // DOES WORK
    21.         {        
    22.             float3 t = rnd.NextFloat3(-1f, 1f) * radius;
    23.             float s = rnd.NextFloat(1f, 20f);
    24.  
    25.             //scale.Value = s;  // This does not work
    26.             //trans.Value = t;    // This works
    27.                            
    28.             ltw.Value = float4x4.TRS(ltw.Position, ltw.Rotation, new float3(s)); // Does Not Work
    29.  
    30.         }).Run();
    31.  
    32.         //this.Enabled = false; // run once
    33.     }
    34. }
    Not working for me?

    The annoying part is when a system does nothing there is no feedback from the console or debugger to indicate what might be wrong?
     
    Last edited: May 15, 2020
  10. MhmdAL1111

    MhmdAL1111

    Joined:
    Oct 25, 2017
    Posts:
    30
    Is the system listed under the "used by systems" of the entity in the entity debugger? Is the LocalToWorld changing at all in the entity debugger?
     
  11. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    I've disabled a rotation system and the relocation and scale system now works?!

    So it seems like a system conflict one translating and scaling the other rotating but no warnings about conflicting systems in the console?

    How to allow both systems to work together?
     
  12. MhmdAL1111

    MhmdAL1111

    Joined:
    Oct 25, 2017
    Posts:
    30
    I don't know what exactly is happening, perhaps modifying scale with float4x4.TRS is not the correct way, but adding [UpdateAfter(typeof(TransformSystemGroup))] fixed it when I tried. Use at your own risk because I don't know if it is the right approach.
     
  13. florianhanke

    florianhanke

    Joined:
    Jun 8, 2018
    Posts:
    426
    The systems running in the
    TransformSystemGroup
    as described in https://docs.unity3d.com/Packages/com.unity.entities@0.10/manual/transform_system.html as referenced by @vildauget write to
    LocalToWorld
    : "If any combination of Translation (float3), Rotation (quaternion), or Scale (float) components are present along with a LocalToWorld component, a transform system will combine those components and write to LocalToWorld."

    So if the changes before that group to ltw do not correspond to changes done to translation etc., the changes to ltw will be overwritten by the
    TransformSystemGroup
    if any of the other components are present. This is why changes to ltw in this case only work when done after
    TransformSystemGroup
    as described by @MhmdAL1111. I hope that helps! The Entities transform system page is very informative and a must read.
     
    Last edited: May 15, 2020
    MhmdAL1111 likes this.
  14. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    I'm trying to combine the two systems into one and only use the LocalToWorld matrix but there seems to be a problem how do you extract the current Scale from LTW to propogate it back via TRS?
     
  15. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    OK so if you run two systems that update LTW and or Rotation, Translation, Scale they clash even if you apply UpdateBefore or UpdateAfter.

    However there are no warnings in the console when you do this and the documentation does not give clear warnings telling you not to do this.

    Even moving both systems into one has issues as then the relocation and scale take place in an OnStartRunning() method but even that seems to clash with LTW updates!
     
  16. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    This is really weird this is my current combined system and it fails to do the initial relocation and scale???

    Code (CSharp):
    1.  
    2. using Unity.Entities;
    3. using Unity.Transforms;
    4. using Unity.Mathematics;
    5. public class RotateSystem : SystemBase
    6. {
    7.     /*
    8.     protected override void OnStartRunning()
    9.     {    
    10.         Random rnd = new Random(1234);
    11.         float radius = 50f;
    12.         Entities.ForEach((ref LocalToWorld ltw, ref Cell cell, ref RotateComponent rc) =>
    13.         {
    14.             if (math.length(rc.vector) == 0f)
    15.             {
    16.                 rc.vector = rnd.NextFloat3(-1f, 1f);
    17.                 rc.speed = rnd.NextFloat(-1f, 1f);
    18.             }
    19.             float3 t = rnd.NextFloat3(-1f, 1f) * radius;
    20.             float s = rnd.NextFloat(1f, 10f);
    21.             ltw.Value = float4x4.TRS(ltw.Position + t, ltw.Rotation, new float3(s)); // this does not work
    22.         }).ScheduleParallel();    
    23.     }
    24.     */
    25.     protected override void OnUpdate()
    26.     {
    27.         Random rnd = new Random(1234);
    28.         float dt = Time.DeltaTime;
    29.         float radius = 50f;
    30.         Entities.ForEach((ref LocalToWorld ltw, ref RotateComponent rc) =>
    31.         {
    32.             if (math.length(rc.vector) == 0f)
    33.             {
    34.                 rc.vector = rnd.NextFloat3(-1f, 1f);
    35.                 rc.speed = rnd.NextFloat(-1f, 1f);
    36.                 float3 t = rnd.NextFloat3(-1f, 1f) * radius;
    37.                 float s = rnd.NextFloat(1f, 10f);
    38.                 ltw.Value = float4x4.TRS(ltw.Position + t, math.mul(ltw.Rotation, quaternion.EulerXYZ(rc.vector * dt * rc.speed)), s); // this does not work!!
    39.             }
    40.             else
    41.             {            
    42.                 ltw.Value = float4x4.TRS(ltw.Position, math.mul(ltw.Rotation, quaternion.EulerXYZ(rc.vector * dt * rc.speed)), 1f); // this does work!
    43.             }        
    44.         }).ScheduleParallel();  
    45.     }
    46.  
    47. }
    Also why can't quaternions be multiplied e.g. q1 * q2, having to use math.mul() seems very poor and much more complex?
     
    Last edited: May 15, 2020
  17. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    Can a LTW updating system run so fast it updates multiple times a frame and cancels out previous updates to the LTW?
     
  18. temps12

    temps12

    Joined:
    Nov 28, 2014
    Posts:
    41
    Only change LocalToWorld if your entity doesn't have Translation, Rotation, Scale, NonUniforScale or any of the weird transform components described in the documentation. If you have none of those then writing to LocalToWorld in your own systems shouldn't be a problem.

    No it cant run so fast it updates multiple times because you only schedule it once every frame.
     
  19. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    I'm using LTW because Scale and NonUniform Scale do not work so using LTW.TRS() was the apparent solution.

    Translate(T) and Rotation(R) work.

    The above code if setup to just R or just T and Scale (TS) it does work.

    But when I try and get it to do the TS in the first frame and then just R. It only does R hence the idea that it might be running multiple times within a frame.

    How else can you explain this not working?
     
  20. temps12

    temps12

    Joined:
    Nov 28, 2014
    Posts:
    41
    If you check out one of your cell entities in the Entity Debugger, are they using Scale or NonUniformScale?
    Also just to be sure, try to use a hard coded scale instead of random to just make sure its the random that is not giving you weird results.
     
  21. florianhanke

    florianhanke

    Joined:
    Jun 8, 2018
    Posts:
    426
    What components are on your entities? And what does your current code look like? Are there other systems operating on the entities?
     
  22. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    OK managed to get something that works but it seems hacky, extended my RotationComponent to store position and scale and updated the system to this:

    Code (CSharp):
    1. using Unity.Entities;
    2. using Unity.Transforms;
    3. using Unity.Mathematics;
    4.  
    5. public class RotateSystem : SystemBase
    6. {
    7.    
    8.     protected override void OnStartRunning()
    9.     {      
    10.         Random rnd = new Random((uint)(Time.DeltaTime * 1234f));
    11.         float radius = 50f;
    12.  
    13.         Entities.ForEach((ref LocalToWorld ltw, ref RotateComponent rc) =>
    14.         {
    15.              if (!rc.setup)
    16.             {
    17.                 rc.setup = true;
    18.                 rc.vector = rnd.NextFloat3(-1f, 1f);
    19.                 rc.speed = rnd.NextFloat(-1f, 1f);
    20.  
    21.  
    22.                 rc.newPosition = rnd.NextFloat3(-1f, 1f) * radius;
    23.                 rc.newScale = rnd.NextFloat(1f, 10f);
    24.             }
    25.  
    26.         }).Run();      
    27.     }  
    28.  
    29.     protected override void OnUpdate()
    30.     {      
    31.         float dt = Time.DeltaTime;      
    32.  
    33.         Entities.ForEach((ref LocalToWorld ltw, ref RotateComponent rc) =>
    34.         {          
    35.        
    36.             ltw.Value = float4x4.TRS(rc.newPosition, math.mul(ltw.Rotation, quaternion.EulerXYZ(rc.vector * dt * rc.speed)), rc.newScale); // this works but I have to renew the position and scale every frame?!
    37.  
    38.         }).ScheduleParallel();    
    39.     }
    40.    
    41. }
    42.  
    Not sure why I have to continuously update the position and scale and to do so store the extra data in a component?!
     
  23. florianhanke

    florianhanke

    Joined:
    Jun 8, 2018
    Posts:
    426
    charleshendry and temps12 like this.
  24. temps12

    temps12

    Joined:
    Nov 28, 2014
    Posts:
    41
    So I checked because I was curious. Scale doesn't seem to be added to entities if the scale is 1,1,1. How the transforms components are added right now is quite fuzzy and annoying I think. Would be great to get some improvements to that. Anyway, in your authoring components for cell, add NonUniformScale and you should be able to query against it.

    The code below should work and this is the "correct" way to run things only once. Just add an IntializeCellTag in your cell authoring script. And then of course the NonUniformScale component. To finalize it you should put the systems in the correct order but to get this going you don't have to care.

    Code (CSharp):
    1.     public struct InitializeCellTag : IComponentData { }
    2.  
    3.     public struct RotateComponent : IComponentData
    4.     {
    5.         public float3 vector;
    6.         public float speed;
    7.     }
    8.  
    9.     public class InitializeCellsSystem : SystemBase
    10.     {
    11.         EntityQuery _Query;
    12.  
    13.         protected override void OnUpdate()
    14.         {
    15.             Random rnd = new Random((uint)(Time.DeltaTime * 1234f));
    16.             float radius = 50f;
    17.  
    18.             Entities
    19.               .WithStoreEntityQueryInField(ref _Query)
    20.               .WithAll<InitializeCellTag>()
    21.               .ForEach((ref Translation translation, ref NonUniformScale scale, ref RotateComponent rc) =>
    22.             {
    23.                 translation.Value = rnd.NextFloat3(-1f, 1f) * radius;
    24.                 scale.Value = rnd.NextFloat(1f, 10f);
    25.                 rc.vector = rnd.NextFloat3(-1f, 1f);
    26.                 rc.speed = rnd.NextFloat(-1f, 1f);
    27.             }).Run();
    28.  
    29.             EntityManager.RemoveComponent<InitializeCellTag>(_Query);
    30.         }
    31.     }
    32.  
    33.     public class RotateSystem : SystemBase
    34.     {
    35.         protected override void OnUpdate()
    36.         {
    37.             float dt = Time.DeltaTime;
    38.  
    39.             Entities.ForEach((ref Rotation rotation, in RotateComponent rc) =>
    40.             {
    41.                 rotation.Value = quaternion.EulerXYZ(rc.vector * dt * rc.speed);
    42.             }).Run();
    43.         }
    44.     }
     
    Last edited: May 18, 2020
    Arowx likes this.
  25. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    That's great but how many clicks is that information away from a developer using Unity and why isn't there a warning generated when you use systems that update LTW incorrectly. That warning could also link to the documentation which IMHO could be made a lot easier to understand with warning information and examples.
     
  26. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    Q: Why doesn't your Initialization System query for it's tag?
     
  27. temps12

    temps12

    Joined:
    Nov 28, 2014
    Posts:
    41
    Ah damn... yeah there should be a WithAll<IntializeCellTag>() in the query... I'll edit in it..