Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

ECS sprites

Discussion in 'Entity Component System' started by jldevoy, Aug 14, 2018.

  1. jldevoy

    jldevoy

    Joined:
    May 2, 2014
    Posts:
    33
    Does anyone know of an ECS sprite example that works on 2018.2? There is an old one on github but its totally broken on recent builds.

    Thanks
     
  2. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,754
    I suppose, is not much different, than normal game object prefab for ECS. Applying mesh, applying material. Sphere, box, or quad, should be the same.

    Is there anything specific about sprites, to other shapes?
     
  3. jldevoy

    jldevoy

    Joined:
    May 2, 2014
    Posts:
    33
    ECS has a meshInstanceRenderer for meshes but it doesnt seem to render sprites, and sprites seem to have no equivalent.
     
  4. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,754
    But sprite, is nothing more than quad, or other plane, which is often rotated toward camera.
    So by my understanding, you can create equivalent very easy.
     
  5. Filtiarn_

    Filtiarn_

    Joined:
    Jan 24, 2013
    Posts:
    173
  6. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    It's not the case in Unity where a sprite can have quite a few verts and change per frame.
     
  7. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,181
    I am using the version @Necromantic from that thread and it is working well, though keep in mind this is a very raw approach and doesn't utilize culling or lighting (as far as I can tell). It does allow you to have different colors for the sprite instances though. You can download the necessary files for it here.

    One thing to keep in mind. The included Transform2DSystem that the enties package comes with sets up the TransformMatrix component on the X and Z axes. This is counter intuitive considering Unity's current 2D system works with the X and Y axes. I have created custom transform systems that builds the Transform Matrix on the X and Y Axes. It is actually 4 different systems, one that works on entities that have just a Position2D component (but no Scale2D or Heading2D component), one on entities that have Position2D and Scale2D (but not Heading2D), one on entities with Position2D and Heading2D (but not Scale2D), and one on entities with Position2D, Scale2D, and Heading2D. All entities must have a TransformMatrix component.

    Doing it this way, the systems should be able to run in parallel (whereas if it was all in one system they would not be), since they will always act on different entities (using the RequireSubtractiveComponent ensures this).

    The Scale2D component comes from Necromantic's project, but it is just a component with a float2 value.

    Note that the Transform2DSystem will still run doing things this way. You can either disable the system (not sure how, but I think it's possible), or create a new component with a different name than Position2D (maybe RenderPosition2D) with a float2 Value. Update the systems in the code below to use the new component, and replace other uses of Position2D with your new component name.

    Code (CSharp):
    1. using Unity.Collections;
    2. using Unity.Entities;
    3. using Unity.Jobs;
    4. using Unity.Burst;
    5. using Unity.Mathematics;
    6. using Unity.Transforms;
    7. using Unity.Transforms2D;
    8. using UnityEngine.Scripting;
    9.  
    10. public class Transform2DGroup { }
    11.  
    12. [Preserve]
    13. [UpdateInGroup(typeof(Transform2DGroup))]
    14. public class TransToMatrixSystem : JobComponentSystem
    15. {
    16.     [BurstCompile]
    17.     [RequireSubtractiveComponent(typeof(Heading2D), typeof(Scale2D))]
    18.     struct TransToMatrix : IJobProcessComponentData<Position2D, TransformMatrix>
    19.     {
    20.         public void Execute([ReadOnly]ref Position2D position, ref TransformMatrix matrix)
    21.         {
    22.             float2 positionV = position.Value;
    23.             matrix = new TransformMatrix
    24.             {
    25.                 Value = float4x4.translate(new float3(positionV.x, positionV.y, 0.0f))
    26.             };
    27.         }
    28.     }
    29.  
    30.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    31.     {
    32.         var transToMatrixJob = new TransToMatrix();
    33.         return transToMatrixJob.Schedule(this, 64, inputDeps);
    34.     }
    35. }
    36.  
    37. [Preserve]
    38. [UpdateInGroup(typeof(Transform2DGroup))]
    39. public class ScaleTransToMatrixSystem : JobComponentSystem
    40. {
    41.     [BurstCompile]
    42.     [RequireSubtractiveComponent(typeof(Heading2D))]
    43.     struct ScaleTransToMatrix : IJobProcessComponentData<Position2D, Scale2D, TransformMatrix>
    44.     {
    45.         public void Execute([ReadOnly]ref Position2D position, [ReadOnly]ref Scale2D scale, ref TransformMatrix matrix)
    46.         {
    47.             float2 positionV = position.Value;
    48.             float2 scaleV = scale.Value;
    49.             float4x4 pos = float4x4.translate(new float3(positionV.x, positionV.y, 0.0f));
    50.             matrix = new TransformMatrix
    51.             {
    52.                 Value = math.mul(pos, float4x4.scale(new float3(scaleV.x, scaleV.y, 1f)))
    53.             };
    54.         }
    55.     }
    56.  
    57.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    58.     {
    59.         var scaleTransToMatrixJob = new ScaleTransToMatrix();
    60.         return scaleTransToMatrixJob.Schedule(this, 64, inputDeps);
    61.     }
    62. }
    63.  
    64. [Preserve]
    65. [UpdateInGroup(typeof(Transform2DGroup))]
    66. public class RotTransToMatrixSystem : JobComponentSystem
    67. {
    68.     [BurstCompile]
    69.     [RequireSubtractiveComponent(typeof(Scale2D))]
    70.     struct RotTransToMatrix : IJobProcessComponentData<Position2D, Heading2D, TransformMatrix>
    71.     {
    72.         public void Execute([ReadOnly]ref Position2D position, [ReadOnly]ref Heading2D heading, ref TransformMatrix matrix)
    73.         {
    74.             float2 positionV = position.Value;
    75.             float2 headingV = math.normalize(heading.Value);
    76.             matrix = new TransformMatrix
    77.             {
    78.                 Value = new float4x4
    79.                 {
    80.                     c0 = new float4(headingV.y, -headingV.x, 0f, 0.0f),
    81.                     c1 = new float4(headingV.x, headingV.y, 0f, 0f),
    82.                     c2 = new float4(0f, 0f, 1f, 0f),
    83.                     c3 = new float4(positionV.x, positionV.y, 0.0f, 1.0f)
    84.                 }
    85.             };
    86.         }
    87.     }
    88.  
    89.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    90.     {
    91.         var rotTransToMatrixJob = new RotTransToMatrix();
    92.         return rotTransToMatrixJob.Schedule(this, 64, inputDeps);
    93.     }
    94. }
    95.  
    96. [Preserve]
    97. [UpdateInGroup(typeof(Transform2DGroup))]
    98. public class ScaleRotTransToMatrixSystem : JobComponentSystem
    99. {
    100.     struct ScaleRotTransGroup
    101.     {
    102.         public ComponentDataArray<TransformMatrix> matrices;
    103.         [ReadOnly] public ComponentDataArray<Position2D> positions;
    104.         [ReadOnly] public ComponentDataArray<Heading2D> headings;
    105.         [ReadOnly] public ComponentDataArray<Scale2D> scales;
    106.         public readonly int Length;
    107.     }
    108.  
    109.     [Inject] ScaleRotTransGroup m_ScaleRotTransGroup;
    110.  
    111.     //Have to use IJobParallelFor since IJobProcessComponentData currently only supports up to 3 types
    112.     [BurstCompile]
    113.     struct ScaleRotTransToMatrix : IJobParallelFor
    114.     {
    115.         [ReadOnly] public ComponentDataArray<Position2D> positions;
    116.         [ReadOnly] public ComponentDataArray<Heading2D> headings;
    117.         [ReadOnly] public ComponentDataArray<Scale2D> scales;
    118.         public ComponentDataArray<TransformMatrix> matrices;
    119.  
    120.         public void Execute(int i)
    121.         {
    122.             float2 position = positions[i].Value;
    123.             float2 heading = math.normalize(headings[i].Value);
    124.             float2 scale = scales[i].Value;
    125.             float4x4 rotTrans = new float4x4
    126.             {
    127.                 c0 = new float4(heading.y, -heading.x, 0f, 0.0f),
    128.                 c1 = new float4(heading.x, heading.y, 0f, 0f),
    129.                 c2 = new float4(0f, 0f, 1f, 0f),
    130.                 c3 = new float4(position.x, position.y, 0.0f, 1.0f)
    131.             };
    132.  
    133.             matrices[i] = new TransformMatrix
    134.             {
    135.                 Value = math.mul(rotTrans, float4x4.scale(new float3(scale.x, scale.y, 1f)))
    136.             };
    137.         }
    138.     }
    139.  
    140.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    141.     {
    142.         var scaleRotTransToMatrixJob = new ScaleRotTransToMatrix();
    143.         scaleRotTransToMatrixJob.positions = m_ScaleRotTransGroup.positions;
    144.         scaleRotTransToMatrixJob.matrices = m_ScaleRotTransGroup.matrices;
    145.         scaleRotTransToMatrixJob.headings = m_ScaleRotTransGroup.headings;
    146.         scaleRotTransToMatrixJob.scales = m_ScaleRotTransGroup.scales;
    147.  
    148.         return scaleRotTransToMatrixJob.Schedule(m_ScaleRotTransGroup.Length, 64, inputDeps);
    149.     }
    150. }
    151.  

    Please feel free to check the math for creating the matrix for each entity. I tested them and they seemed to be producing the correct result, but I am not familiar with matrices and thus there could be an error somewhere.

    Edit: You can combine all those systems in my code into one, then use JobHandles.CombineDepencies(NativeArray<JobHandle>) to combine the different jobs. You can also try and use changed filters to only update the matrix when one of the Position2D, Heading2D, or Scale2D values has changed.

    Edit2: Ignore the edit above. It looks like you cannot combine the dependencies because all four systems write to the TransformMatrix component. Even though they are guaranteed to operate on different entities, the iterator for the TransformMatrix in each system is the same and thus you cannot have it being used in different jobs at the same time. At least, that is my understanding of it.
     
    Last edited: Aug 21, 2018