Search Unity

Modifying multiple meshes with job system (and/or ECS)

Discussion in 'C# Job System' started by hivemindhermit, Dec 14, 2018.

  1. hivemindhermit

    hivemindhermit

    Joined:
    Dec 13, 2016
    Posts:
    9
    (I posted this in Answers yesterday but realised that I'll probably have more luck here. My apologies if this is bad form!)

    I want to procedurally modify a lot of meshes at runtime, and thought I'd look into doing this with the job system.

    If I weren't using the job system, I would store references to the vertex arrays in some collection, and then loop over each array to modify the vertices therein. So my original thought was to simply do this loop in a job. As I've come to understand, this isn't actually possible, since an array of arrays doesn't count as a blittable type.

    I assume this means I'd have to schedule one job per mesh, perhaps storing them in a collection so I could schedule several jobs per update tick. The vertex arrays will probably be quite small, but there's likely to be a lot of them, and this solution makes me wonder what sort of overhead the actual scheduling and completing of jobs itself might create.

    I've started looking into ECS but am not yet familiar enough with it to see if it offers a solution.

    So... I'm out of my depth here. ^^ Anyone got any advice for an ECS/job system newb?
     
    olix4242 likes this.
  2. hivemindhermit

    hivemindhermit

    Joined:
    Dec 13, 2016
    Posts:
    9
    No one?

    I guess I will simply have to do some tests to see if jobs are worth the trouble of copying the data back to the vertex arrays.
     
  3. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    I've posted how to do this a dozen times (not exaggerating).

    I'd get you a link but I'm in bed about to head to sleep but you can probably find it easy enough if you look at my post history (a little bit back.) Otherwise I'll find it tomorrow when I get up.
     
  4. hivemindhermit

    hivemindhermit

    Joined:
    Dec 13, 2016
    Posts:
    9
    Thanks for the response! I did do a bunch of searching but didn't find anyone discussing the angle of having multiple meshes. I did find one thread where you posted an extension making the actual copying more effective, which I made a note to return to when I get that far :)
     
  5. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,776
    Definitely this forum is better than Answers. So no worry about it.

    There were quite few topic talking about modifying meshes in past.

    Does searching 'Mesh' key word, did not yield the relevant answer?
    https://forum.unity.com/search/37830286/?page=2&q=Mesh&t=post&o=date&c[node]=147

    On page 2 there is topic relevant to Arrays.
    If you haven't yet, I suggest check it out.
    Along with other older pages as well.
     
  6. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,776
    Do you have existing, or generating new meshes?
     
  7. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,776
    hivemindhermit likes this.
  8. iam2bam

    iam2bam

    Joined:
    Mar 9, 2016
    Posts:
    36
    I haven't tried for performance yet but I think you can schedule a whole bunch of jobs and combine all dependencies with JobHandle.CombineDependencies(NativeArray<JobHandle>).

    Theoretically you could have a regular array of NativeArray<float4> (for the vertices) outside the jobs, then run a job for each NativeArray and wait on the combined handle for completion.
     
    hivemindhermit likes this.
  9. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    Ok I'm awake.

    So pretty much I believe the best approach is to make each mesh an entity and store each mesh component (vertices, uvs, normals) etc as their own BufferArray.

    This way you can just use a single job and not worry about combining dependencies.

    I got a few minutes I might put up a demo on exactly what I'm talking about.

    There's no real reason to ever use a ISharedComponentData for this, it just causes huge issues.
     
    hivemindhermit, recursive and iam2bam like this.
  10. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    https://github.com/tertle/MeshDemo

    Here ya go.

    It might look like the meshes are just moving up and down but it's really just manipulating the mesh y vertices with some random dodgy job I threw together.

    Code (CSharp):
    1.     /// <summary>
    2.     ///  Just some random mesh manipulation. Frame dependent, don't turn off sync.
    3.     /// </summary>
    4.     [BurstCompile]
    5.     [RequireComponentTag(typeof(Vertex))]
    6.     private struct ManipulateMeshJob : IJobProcessComponentDataWithEntity<MeshScale>
    7.     {
    8.         [NativeDisableParallelForRestriction]
    9.         public BufferFromEntity<Vertex> Vertices;
    10.  
    11.         public NativeQueue<MeshDirty>.Concurrent MeshDirtyQueue;
    12.  
    13.         /// <inheritdoc />
    14.         public void Execute(Entity entity, int index, ref MeshScale meshScale)
    15.         {
    16.             this.MeshDirtyQueue.Enqueue(new MeshDirty{Entity = entity});
    17.  
    18.             meshScale.Count += 1;
    19.  
    20.             if (meshScale.Count == meshScale.Max)
    21.             {
    22.                 meshScale.Count = -meshScale.Max;
    23.             }
    24.  
    25.             var vertices = this.Vertices[entity].Reinterpret<float3>();
    26.  
    27.             var offset = meshScale.Step;
    28.  
    29.             if (meshScale.Count < 0)
    30.             {
    31.                 offset = -offset;
    32.             }
    33.  
    34.             for (var i = 0; i < vertices.Length; i++)
    35.             {
    36.                 var v = vertices[i];
    37.                 v.y += offset;
    38.                 vertices[i] = v;
    39.             }
    40.         }
    41.     }
    A few notes

    - uses my batch system to create events to notify of mesh changes, this is just how I do things and is completely optionally. Usually I don't manipulate meshes every frame (unlike this example) as they are only occasionally modified hence the choice to use events.
    - uses float3 for uv (instead of float2) because my actual project uses texture2darray which needs the 3rd uv.
    - the random mesh manipulation is frame dependent, i wouldn't turn off sync. just threw together something quick to show mesh manipulations.
    - the actual MeshSystem supports both MeshInstanceRenderer as well as traditional MeshRenderer component if that is what is attached to entity.
    - the block model is structured very strangely for a traditional cube - this is because it's organized in a very particular way for my greedy meshing optimizations for another project. I just copied it in.
     
    Emanx140, iam2bam, Squize and 2 others like this.
  11. hivemindhermit

    hivemindhermit

    Joined:
    Dec 13, 2016
    Posts:
    9
    Thank you! This is very helpful. Given that I haven't had the time to look into ECS yet I can't say I understood all of that, but I'll look into it for sure. :)
     
  12. andywatts

    andywatts

    Joined:
    Sep 19, 2015
    Posts:
    112
    Sorry to necro.
    @tertle, do you remember why you used GetArchetypeChunkComponentType and iterate over chunks?
    I'm thinking Entities.ForEach(Entity e, ref MeshDirty md) might be simpler.
     
  13. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    Well to start with Entities.ForEach didn't exist back then

    That said, not a huge fan of Entities.ForEach - componentsystem version has always been an avoid, jobcomponentsystem version has potential and when polished will be good to use but for now we've found way too many issues with it to be worth using until it's fixed.
     
    Last edited: Dec 18, 2019
    eizenhorn, Antypodish and andywatts like this.