Search Unity

TransformMatrixComponent and Scaling?

Discussion in 'Entity Component System' started by Rennan24, Mar 28, 2018.

  1. Rennan24

    Rennan24

    Joined:
    Jul 13, 2014
    Posts:
    38
    I was messing around with the new ECS and I couldn't figure out how to change the scale of the TransformMatrixComponent. It doesn't look like Unity.Transforms has any Components for scale, all I saw was the RotationComponent and the PositionComponent. Am I missing something or is it just because it hasn't been implemented yet?
     
  2. DwinTeimlon

    DwinTeimlon

    Joined:
    Feb 25, 2016
    Posts:
    300
    It hasn't been implemented yet AFAIK. If you in need a transform system which supports scaling (without hierarchy), I can post some code here.
     
    Rennan24 likes this.
  3. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    1,154
    i have used the transform matrix component for the instance renderer, but have only used it indirectly through position, I guess you. CAn just mess with it directly?
     
    Rennan24 likes this.
  4. Rennan24

    Rennan24

    Joined:
    Jul 13, 2014
    Posts:
    38
    If you want to post some code here I would greatly appreciate it :)

    Yeah you can really only mess with the Position and Rotation so far it seems like, hopefully as the ECS package keeps getting updated, Unity will put the Scaling component in! ;)
     
  5. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    1,154
    That's not what I meant. I think you should be able to set the value of the transform matrix component directly (without using unity's build in systems for position and rotation) - this would give you access to scale
     
  6. Rennan24

    Rennan24

    Joined:
    Jul 13, 2014
    Posts:
    38
    Oh I see what you mean, I started tinkering around with it and came up with this!

    Code (CSharp):
    1. using Unity.Collections.LowLevel.Unsafe;
    2. using Unity.Collections;
    3. using Unity.Entities;
    4. using Unity.Mathematics;
    5. using Unity.Transforms;
    6. using Unity.Jobs;
    7. using UnityEngine;
    8.  
    9. public class ScaleComponent : ComponentDataWrapper<Scale> { }
    10.  
    11. [System.Serializable]
    12. public struct Scale : IComponentData
    13. {
    14.     public float3 Value;
    15. }
    16.  
    17. [UnityEngine.ExecuteInEditMode]
    18. public class TransformSystem : JobComponentSystem
    19. {
    20.     struct TransformGroup
    21.     {
    22.         [ReadOnly]
    23.         public ComponentDataArray<Position> Positions;
    24.  
    25.         [ReadOnly]
    26.         public ComponentDataArray<LocalRotation> Rotations;
    27.  
    28.         [ReadOnly]
    29.         public ComponentDataArray<Scale> Scales;
    30.  
    31.         public ComponentDataArray<TransformMatrix> Transforms;
    32.         public int Length;
    33.     }
    34.  
    35.     [Inject]
    36.     TransformGroup transformGroup;
    37.  
    38.     [ComputeJobOptimization]
    39.     struct TransformGroupJob : IJobParallelFor
    40.     {
    41.         [ReadOnly]
    42.         public ComponentDataArray<Position> Positions;
    43.  
    44.         [ReadOnly]
    45.         public ComponentDataArray<LocalRotation> Rotations;
    46.  
    47.         [ReadOnly]
    48.         public ComponentDataArray<Scale> Scales;
    49.  
    50.         public ComponentDataArray<TransformMatrix> Transforms;
    51.  
    52.         public void Execute(int i)
    53.         {
    54.             Transforms[i] = new TransformMatrix
    55.             {
    56.                 Value = math.mul(math.rottrans(Quaternion.Euler(Rotations[i].Value.value.xyz), Positions[i].Value), math.scale(Scales[i].Value))
    57.             };
    58.         }
    59.     }
    60.  
    61.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    62.     {
    63.         var transformJob = new TransformGroupJob
    64.         {
    65.             Transforms = transformGroup.Transforms,
    66.             Positions = transformGroup.Positions,
    67.             Rotations = transformGroup.Rotations,
    68.             Scales = transformGroup.Scales,
    69.         };
    70.  
    71.         return transformJob.Schedule(transformGroup.Length, 64, inputDeps);
    72.     }
    73. }
    74.  
    Probably not the most fastest running code but it does let me tinker with Entities until Unity decides to add a Scale Component to the ECS. Another annoying thing that I noticed with the Entity debugger was that when you disable a system, after hitting play, that system would re-enable itself. Also I didn't actually know how to reorder the systems so that my system happens before Unity's own TransformSystem, since they create a new matrix completely invalidating the one I made in this new system.
     
  7. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    1,154
    I have not looked into your implementation, but I think that if you want to avoid interference with Unity's Transform System, you should avoid their built-in position, rotation components and roll your own ones.

    This way their Transform System should not kick-in at all and you can deal with your own "MyPosition", "MyRotation", "MyScale" components in your own system, i.e. setting the TransformMatrix.
     
    Rennan24 likes this.
  8. DwinTeimlon

    DwinTeimlon

    Joined:
    Feb 25, 2016
    Posts:
    300
    Here is the gist as promised. I fiddled a little with the code as I removed my namespaces and put all the components into one file. Let me know if it works. Please also note that you now need an "Active" component on each object you want to render.
    https://gist.github.com/JoeCoo7/f497af9b1ba2ab5babae3060635a9c6a
     
    Last edited: Mar 30, 2018
  9. pvloon

    pvloon

    Joined:
    Oct 5, 2011
    Posts:
    591
    Looks pretty clean!

    One minor question / comment - I think it's safe to pass the injection group struct to a job? Saves having to type out all the arrays / permissions twice!
     
    DwinTeimlon likes this.
  10. DwinTeimlon

    DwinTeimlon

    Joined:
    Feb 25, 2016
    Posts:
    300
    Yes, that is a good suggestion.
     
  11. jj_unity328

    jj_unity328

    Joined:
    Jun 7, 2018
    Posts:
    22
    I had the same idea and all worked fine at first but then I had memory overflow and whatnot when I tried to spawn more entities. Be cautious, do tests!
     
  12. Afonso-Lage

    Afonso-Lage

    Joined:
    Jul 8, 2012
    Posts:
    70
    This doesn't sounds to be a good idea, since when you write the permissions on a Job and then mark it as a
    [BrustCompile]
    (previous
    [JobComputeOptimization]
    ) the Brust Compile will take a look on those permissions, create some context, do some optimizations and safety handling based on that. If you just pass the entire group you are basically using it as a simple Job, without much of the advantages of using brust compiler.

    Remember that on of the main goals of Brust Compiler is to use SIMD instructions, which needs to be heavy tied with linear memory layout. That's also the same reason why they are working with special types like
    StructOfArrays
    , which I didn't fully understood yet..
     
  13. NudelGames

    NudelGames

    Joined:
    May 9, 2017
    Posts:
    1
    Also wanted to post my solution, which modifies the TransformMatrix from the TransformSystem. So it will work with all combinations of Position, Heading, Rotation, etc.

    Code (CSharp):
    1. using Unity.Collections;
    2. using Unity.Entities;
    3. using Unity.Mathematics;
    4. using Unity.Transforms;
    5.  
    6. [System.Serializable]
    7. public struct Scale : IComponentData
    8. {
    9.     public float3 Value;
    10. }
    11. public class ScaleComponent : ComponentDataWrapper<Scale> { }
    12.  
    13. [UpdateAfter(typeof(TransformSystem))]
    14. public class ScaleSystem : ComponentSystem
    15. {
    16.     public struct ScaleGroup
    17.     {
    18.         public readonly int Length;
    19.         [ReadOnly] public ComponentDataArray<Scale> Scale;
    20.         public ComponentDataArray<TransformMatrix> TransformMatrix;
    21.         public SubtractiveComponent<VoidSystem<TransformSystem>> VoidSystemTransformSystem;
    22.         public SubtractiveComponent<VoidSystem<ScaleSystem>> VoidSystemScaleSystem;
    23.     }
    24.     [Inject] public ScaleGroup Scale;
    25.  
    26.     protected override void OnUpdate()
    27.     {
    28.         for (int i = 0; i < Scale.Length; i++)
    29.         {
    30.             var scale = Scale.Scale[i].Value;
    31.             Scale.TransformMatrix[i] = new TransformMatrix { Value = math.mul(Scale.TransformMatrix[i].Value, new float4x4(scale.x, 0, 0, 0, 0, scale.y, 0, 0, 0, 0, scale.z, 0, 0, 0, 0, 1)) };
    32.         }
    33.     }
    34. }
     
  14. Caiuse

    Caiuse

    Joined:
    Jan 6, 2010
    Posts:
    30
    @NudelGames Thank you for this, the cleanest solution that doesn't involve modifying the ECS source.

    And for anyone looking to preset the scale value:
    Code (CSharp):
    1.  
    2.         var scaleComponents = new NativeArray<Scale>(scaleCount, Allocator.TempJob);
    3.         var setScaleJob = new MemsetNativeArray<Scale>()
    4.         {
    5.             Source = scaleComponents,
    6.             Value = new Scale()
    7.             {
    8.                 Value = new float3(1f)
    9.             }
    10.         }.Schedule(scaleCount, 64);
    11.  
     
  15. omegabytestudio

    omegabytestudio

    Joined:
    Nov 9, 2015
    Posts:
    77
    Hey Caiuse,


    I just started playing with Pure ECS, and I don't really get your code.

    What do you mean by preset abd how do you use it?

    I'm using NudelGames Code to spawn trees that are different size

    Code (CSharp):
    1. entityManager.SetComponentData(tree, new Scale { Value = new float3(ecosystemSettings.treeSX, ecosystemSettings.treeSY, ecosystemSettings.treeSZ) });
    Should I use your method?
     
  16. MatthieuPr

    MatthieuPr

    Joined:
    May 4, 2017
    Posts:
    56
    So I have been looking into scaling and noticed that TransformMatrix no longer exists. So looking around the samples found a solution around it:

    Code (CSharp):
    1.  
    2. using System;
    3. using Unity.Collections;
    4. using Unity.Entities;
    5. using Unity.Jobs;
    6. using Unity.Mathematics;
    7. using Unity.Transforms;
    8. using UnityEngine.Jobs;
    9.  
    10. public class ScaleSystem : JobComponentSystem
    11. {
    12. struct Resources
    13. {
    14. public readonly int Length;
    15.  
    16. public ComponentDataArray<Scale> scales;
    17. public TransformAccessArray Transforms;
    18. }
    19. public struct ScaleGroup : IJobParallelForTransform
    20. {
    21. public ComponentDataArray<Scale> scales;
    22. public void Execute(int index, TransformAccess transform)
    23. {
    24. transform.localScale = scales[index].scale;
    25. }
    26.  
    27. }
    28.  
    29. [Inject]
    30. Resources _resources;
    31.  
    32. protected override JobHandle OnUpdate(JobHandle inputDeps)
    33. {
    34. ScaleGroup job = new ScaleGroup
    35. {
    36. scales = _resources.scales
    37. };
    38. return job.Schedule(_resources.Transforms, inputDeps);
    39. }
    40. }
    41.  
    42.  
    43. using System;
    44. using Unity.Entities;
    45. using Unity.Mathematics;
    46.  
    47. [Serializable]
    48. public struct Scale : IComponentData {
    49.     public float3 scale;
    50. }
    51.  
    52. [UnityEngine.DisallowMultipleComponent]
    53. public class ScaleComponent : ComponentDataWrapper<Scale> { }
    54.  
    I can see the scale properly being applied on the transform of the GameObject, but the game object itself doesn't change size. scale 1 or scale 250. I added hard coded scales in the code above for testing purpose, the working code would be the one commented out. If anybody knows why it sets transform local scale correctly but fails to actually resize the mesh, would be greatly appreciated :)
     
  17. Levr01

    Levr01

    Joined:
    Jun 6, 2017
    Posts:
    26
    When im try to use this - Scale is not float3 it just float
    Cannot implicitly convert type 'Unity.Mathematics.float3' to 'float'
     
  18. edalbeci

    edalbeci

    Joined:
    Jan 21, 2018
    Posts:
    36
    tl;dr got it to work, code below

    I saw this as well. It initially seemed like NonUniformScale was the way to go but...

    Likewise here, when I set the Unity.Transforms.Scale component.

    I ended up changing the prefab's scale just to see what'd happen. Luckily, ConvertToEntity then added a new component called CompositeScale. I just modified this component's float4x4 for the appropriate scaling. To generate the float4x4, it looks like Unity.Mathematics.float4x4 has a number of nice Scale utilities. For a simple "hello world" Unity scaling demo in ECS, create a new project:

    1. add a cube prefab with a ConvertToEntity component.
    2. Change the prefab's scale, so that ConvertToEntity creates a CompositeScale component during conversion.
    3. add the following system.

    Code (CSharp):
    1. using Unity.Entities;
    2. using Unity.NetCode;
    3. using Unity.Mathematics;
    4. using Unity.Physics;
    5. using Unity.Transforms;
    6. using Unity.Collections;
    7. using Unity.Physics.Systems;
    8. using Unity.Physics.Extensions;
    9.  
    10. public class TestComponentSystem : ComponentSystem
    11. {
    12.     protected override void OnUpdate()
    13.     {
    14.         Entities.ForEach((ref CompositeScale scale) =>
    15.         {
    16.             scale.Value = float4x4.Scale(2, 1, 4);
    17.         });
    18.     }
    19. }
    Notes:
    • Steps 1 and 2 can be replaced with your favorite method of spawning an entity with a CompositeScale component. I just found the above approach (prefab -> convert -> instantiate prefab if necessary), used in the netcode tutorial, to be easiest.
    • Note the above will discard the original state. Maybe this is obvious to some, but just pointing out that you likely want something like math.mul(scale.Value, float4x4.Scale(...)).
     
    Baggers_ and lclemens like this.