Search Unity

  1. If you have experience with import & exporting custom (.unitypackage) packages, please help complete a survey (open until May 15, 2024).
    Dismiss Notice
  2. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice

Resolved Update a lot for meshes fast

Discussion in 'Entity Component System' started by Chmyke, Jun 9, 2022.

  1. Chmyke

    Chmyke

    Joined:
    Aug 1, 2012
    Posts:
    34
    Hello everyone,

    I think I'm going in the wrong direction and I need some little hints or advise since I'm new to ECS and a bit lost...

    In my game I have a lot of flowers witch are Entities, each of theses flowers have their own unique Mesh, and I need to constantly change their respective mesh created by code in order to grow them.

    I thought I can change their RenderMesh in a ForEach... But It's not relly efficient because with the RenderMesh in the ForEach I must use .WithStructuralChanges().WithoutBurst().Run(); In order to make It work correctly.

    What do you advise me to do? In my research I have found some stuffs about Graphics.DrawMesh, witch I'm really not famillar with... Should I look more into this direction?
    Is there a better way to do what I want (update a lot for meshes in ECS)?

    Thanks a lot.
     
  2. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,809
    I would suggest 4 options.

    1. Is to hide/spawn/instantiate entity with desired mesh, rather removing shared components. Probably easiest but not the fastest. Yet creating and destroying 1000s of entities takes fraction of the frame.

    2. Have a mesh which is animated AMD anime it.

    3. Use shader to animate growth. Possibly fastest approach.

    4. Use DrawMeshInstanced / DrawMeshInstancedIndirect instead shared mesh. Then you have full control what mesh and texture you want to render.
     
    Chmyke likes this.
  3. Chmyke

    Chmyke

    Joined:
    Aug 1, 2012
    Posts:
    34
    I will go with for solution 4, I feel more reassured thanks to your advice, It's always scary to to invest time learning new things when we don't know if it's that we really need...
    Thank you Antypodish!
     
  4. Chmyke

    Chmyke

    Joined:
    Aug 1, 2012
    Posts:
    34
    Update:

    I can't really use DrawMeshInstanced, since each one of my flowers is very unique in it shape (there is genetic gameplay mechanics)
    So I will use DrawMesh instead.

    But unfortunately I ran into the same problem than before, I can't make my code work with ScheduleParallel(), like when I used the RenderMesh, need to use WithoutBurst and Run in order to make it works.

    Code (CSharp):
    1. using Unity.Entities;
    2. using UnityEngine;
    3.  
    4. public partial class FlowerSystem : SystemBase
    5. {
    6.     protected override void OnUpdate()
    7.     {
    8.         Entities.ForEach((ref Flower f) => { f.size += 0.01f; }).ScheduleParallel();
    9.  
    10.         Entities.ForEach((in Flower f) =>
    11.                 {
    12.                     Mesh mesh = new Mesh
    13.                     {
    14.                         vertices = new[]
    15.                         {
    16.                             new Vector3(0, 0, 0),
    17.                             new Vector3(1, 0, 0),
    18.                             new Vector3(0, f.size, 0),
    19.                         },
    20.                         triangles = new[]
    21.                         {
    22.                             0, 2, 1
    23.                         }
    24.                     };
    25.  
    26.                     Graphics.DrawMesh(mesh, f.pos, Quaternion.identity, MaterialManager.instance.material, 0);
    27.                 })
    28.                 //.ScheduleParallel();  Don't work :(
    29.                 .WithoutBurst()
    30.                 .Run();
    31.     }
    32. }
    33.  
    The problem here is that mesh is a reference type, and apparently I can't use a reference type with ScheduleParallel.
    Is there anything I can do in order to make it work with ScheduleParallel?

    Is it really impossible to modify a mesh inside a multithreaded Job?
     
    Last edited: Jun 10, 2022
  5. Fribur

    Fribur

    Joined:
    Jan 5, 2019
    Posts:
    141
    Old but might give you some ideas. https://github.com/keijiro/Firefly

    Or check out the new Mesh API: https://docs.unity3d.com/2020.1/Documentation/ScriptReference/Mesh.MeshData.html

    https://github.com/Unity-Technologies/MeshApiExamples

    Fastest and most flexible (no prior knowledge of number of vertices and indices needed) in my experience is modifying vertices and indices as NativeLists in Job and then apply the mesh on the main thread. Pretty annoying but true that you simply cannot set the mesh in a job (but might be coming in the future).
     
    bb8_1 and Chmyke like this.
  6. Chmyke

    Chmyke

    Joined:
    Aug 1, 2012
    Posts:
    34
    "Use a MeshData struct to access, process and create Meshes in the C# Job System."
    I was totally unaware of the new Mesh API. It's seems to be what I need. Thanks a lot Fribur!
     
  7. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,809
    You need to use it outside the job.
    Then pass an array of entities with same type of mesh.
    Basically you need batch entities with same mesh.

    But you run here potentially into major problem with many various meshes.
    DOTS ECS looses its benefits, when fragmenting entities a lot.
    Basically you may end up in a situation of 10k plants, but each one may be literally different (different mesh).
    In such way, to keep amazing speed of DOTS, you need use vertex shader, instead manipulating vertices of actual mesh.

    Have a look this use case, which I did in the past, using DrawMeshInstanced.

    I use here


    Planet has about 165k tiles, which each is an entity. Near halve of them are unique.
    Meaning, nearly 82k unique shaped hex tails. Yes, each hex tails on the sphere are not the same.
    If I use each individual mesh per tail, I would kill performance. Instead I use single hex mesh per tail.
    I do manipulate however vertex shader. In fact I used shader graph here.

    Another my use case of mine, is here (procedural random creatures generator using DOTS)



    Where I actually use two meshes, of which I manipulate vertex shader. One mesh for body, and one for each segment of legs. Of each is an own entity.

    and here



    Same creatures in the forest. Each plant uses two meshes. Trunk and the leafs/flowers.
    Variations are added by a shader.
     
    Chmyke and bb8_1 like this.
  8. Chmyke

    Chmyke

    Joined:
    Aug 1, 2012
    Posts:
    34
    Thank you for taking the time to explaining theses things. I really appreciate. I feel less distraught.

    Before switching to ECS, I was using classic Monobehavior for my flowers, mushrooms and trees. It was great because it's so much more easy to control and tweak with the inspector... I had animation curves and scriptable objects to control everything. So much fun. Now in ECS it's way more difficult. Difficulty doesn't bother me that much, I mean, it's the part of the process to become a better developer, but I have the odd feeling that I will not able to archive the same result than with Monobehavior and even worse: that the performance gain will be not that big...


    Flower.gif


    Mushroom3.gif

    Tree3.gif

    Converting my hex map in ECS was complicated too but interesting... Even a simple selection raycast in ECS is a big deal XD

    It's a game about bee, luckily the performance gain with those are totally fatalistic with ECS. :D

    Bees.gif


    For now I don't know if I must continue to convert everything in ECS... Those flowers, mushrooms and trees will be a great chalenge for sure. I just hope the performance gain will be there...

    I'm not ready yet to accept that I must to use shader graph for the growing. Vertex manipulation worked so well with Monobehavior... I really like manipulating the vertices, it's fun and it allows a lot of possibility. Don't get me wrong, I love shader graph, I mean really, in fact I already use it to paint and animate my flowers, my ECS bee wings animation, etc.... It's just I need maybe more failure attempts to accept to use vertex shader for the growing. I think your solution is very good, and your video demonstrates it clearly, thanks a lot to share it, it's really cool.

    When you say that "DOTS ECS looses its benefits, when fragmenting entities a lot." it scares me bit. I don't really understand because the data structures are the same for all my flowers, it's only their data that change, so they will be a benefits form DOTS, no? It's just If I need to do something in the main thread for all flowers, like changing the mesh It not relevant anymore.

    Thank a lot Antypodish for all your explications and advise, it's great!
     
    thelebaron, apkdev and Antypodish like this.
  9. Fribur

    Fribur

    Joined:
    Jan 5, 2019
    Posts:
    141
    RenderMesh is a “SharedComponent”, which means only 1 per chunk permitted. So each of your flower will consume a 16kB chunk + the unique Mesh somewhere else in memory. So no benefit from processing them via DOTS whatsoever, lots of waisted memory. For that reason Antypodish is correctly suggesting to use same mesh for all flowers and just modify them per instance with some entity (instance) specific data you feed into the shader. I suffer same problem with 1000nds of unique TextMesh Labels, and consider currently to combine them all in 1 mesh every now and then…
     
    Antypodish and Chmyke like this.
  10. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,809
    @Chmyke you got some really cool results there.
    But at current state, the rendering will be probably your major bottleneck. Either you do OOP or DOTS.
    As Fribur mentioned, your issue is using SharedComponent for each individual meshes.
    If that what you are using. If so, you basically loose any benefits of using ECS in your case (because of many unique meshes).

    C# vertex manipulation is similar to shader verts. If you learn how to utilise UVs, sooner than later you will realise power of shader. All that you can do with shader graph. Or if you feel strong, you can script shaders :)
     
    Chmyke likes this.
  11. Chmyke

    Chmyke

    Joined:
    Aug 1, 2012
    Posts:
    34
    I totally ignored that, it's important to know, thanks Fribur!


    With a little hindsight I think I will be able to manage the transition to vertex shader Animation...
    Each of my flowers will be divided in part, like petals, leaves and stem.And each parts will use the same Mesh and be modified by Material Property in order to them to grow.
    Exactly like the fantastic creatures of Antypodish.

    There is probably even more flexibility to use this technique than the vertex manipulation one. I will have a very good control of the initial mesh geometry since I will be able do design it freely in Blender. And I think the growing on Shadergraph will be easier to test en tweak since the update a of a shader don't break the play session.

    Hmmmm I'm starting to see the light... It's very exciting!
     
    Last edited: Jun 11, 2022
    Antypodish likes this.
  12. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,283
    The biggest factor as to whether or not that is viable is whether or not your algorithms require knowing the previous growth positions of the vertices and develop incrementally, or if the whole thing can be represented parametrically. The latter will work with shader graph. The former will require compute shaders or a smart mesh sideload system that plays well with the Hybrid Renderer's chunk structuring. I have a bit of experience with that from developing animation tech, so if you go down that route and want assistance, reach out to me!
     
    Chmyke likes this.
  13. Chmyke

    Chmyke

    Joined:
    Aug 1, 2012
    Posts:
    34
    My algorithms don't need to know the previous positions of the vertices. Everything can be represented parametrically. I made this choice because I think it simplifies a lot the save/load system.

    Thanks a lot for the assistance @DreamingImLatios, I really appreciate, I'm definitely intrigued by this "smart mesh sideload system" even if my algorithms can work with just shadergraph... It's seams to be the solution of my problems when I wanted to do vertex manipulation via code, no? But in the same time it's seams too much complex for my skills...
    Do you think it can solve my previous problem of vertex manipulation via code without too much bottleneck?

    What if my flowers have just a MeshData and their FlowerData? I can manipulate that in a parallel job since it's only value type.
    At the end of each frame in the main thread, I take all MeshDatas that I have updated in a ForEach, merge everthing Into one mesh, and apply It into one unique renderMesh or even a good old MeshRender. It is foolish?
    One problem that I have with that it that I can only have one and unique same material for all flowers, but since I can play with vertex colors and UV it's not that much a big deal.
    What do you think about that? Is viable?
     
  14. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,283
    It would solve it, but unless your parametric functions are huge and heavily rely of transcendental functions, doing things in shader graph is going to be faster.

    The mesh-batching approach works alright if you need to vary the vertex count. I would probably build it in a way where the material was still a shared component so that you could have a few different batches with a few different materials. The approach I would have proposed would have required the vertex counts of your base meshes to be correct, but the variations would be persistent and you could have a decent mix and match of materials.
     
  15. Chmyke

    Chmyke

    Joined:
    Aug 1, 2012
    Posts:
    34
    Update

    Finally, I chose to go with the ShaderGraph solution, and It's working very well. Of course the performance gain is here, but it's really nice to be able to tweak the growing with a shader, and since I use meshes that I created with Blender I have gain a lot of control and flexibility, wonderful.
    I even be able to add some animation curves thanks to the last video of Turbo Makes Games.

    I'm really happy with this solution and will continue to develop it.

    Thanks everyone for the support!
     
    Antypodish likes this.
  16. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,809
    I am glad you found and shared your way to progress. We'll done.