Search Unity

Procedural terrain meshes in DOTS?

Discussion in 'Entity Component System' started by The-Wand3rer, Nov 10, 2020.

  1. The-Wand3rer

    The-Wand3rer

    Joined:
    May 14, 2019
    Posts:
    34
    Hi! I have a simple terrain generation system based on "jobified" monobehaviours. The generation of the terrain (static unique chunks, not voxels, that cannot be modified by the user) is already based on a set of jobs which build the mesh, generate the noise, apply various filters, etc. I was looking into DOTS and I looked at a lot of prior threads. Some of the referenced github examples, however, were implemented with previous version of DOTS and might be no longer relevant.

    Some of these were using very "arcane" implementations (at least to a person not used to DOTS) such as using dynamic / command buffers etc. My naive implementation would consist in creating a TerrainMesh component with NativeArrays for the vertices, indices, UVs, etc. Then in the OnCreate method I would basically run the IJobParallelFor I already implemented in the monobehaviour implementation. Then a RenderMesh component would be used to render the generated unique mesh.

    Would that work? Would I see any benefit over my current MB approach? If not, what should I look into? What would be the best architecture / design pattern to follow that is up to date for DOTS 2020? Again, this would not be for voxels, just meshes based on noise-generated heightmaps.
     
  2. SteveSync

    SteveSync

    Joined:
    Sep 25, 2013
    Posts:
    27
    I've currently got a terrain generation system going using a process like you mention. I have one system that deals with generating the chunks and their visibility. Another system then uses layered noise to generate height data and stores it in a DynamicBuffer. I then have two more systems, one to generate the mesh, and another to generate the mesh colliders.

    I am however dealing with voxel data, so I do a couple more steps in between, but the overall process should be the same. I'm also using a ComputeShader to generate the mesh as I use marching cubes.

    From what I've read, an ECS approach won't be much better than your current way of doing things, since all of your terrain meshes will be different, and as such each terrain chunk will be stored in a different entity chunk. The main advantage of a pure ECS approach is if you can have lots of entities in the same entity chunk, so that they're together in memory (or so I believe. I'm still learning about DOTS). I wrote mine the way I did because I wasn't using jobs in the first place, and my goal is to have as much of my code in the DOTS stack as possible.

    I'd love to share parts of my code if you're interest, as I'm always welcome for feedback and ways I can improve what I've written.
     
  3. TheGabelle

    TheGabelle

    Joined:
    Aug 23, 2013
    Posts:
    242
    I'll be working with terrain soon, but have yet to prototype. A theoretical work around is to store height maps in a texture array, use a unique index per terrain, and a single shared mesh for all terrains. In theory the terrains will be instanced and fill ECS chunks properly. They may be split into separate chunks again because of physics colliders though. Haven't thought of a way around that yet.
     
  4. runner78

    runner78

    Joined:
    Mar 14, 2015
    Posts:
    792
    eugolana likes this.
  5. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    My approach in procedural hex sphere planet generation, using DOTS, in brief is following.

    Create Template hex and pentagon 3D tile mesh.
    Create NativeArrays of of vertices, UV, Normals, vertexColors as persistent.
    Populate arrays using jobs and burst, with relevant calculations, of verts positions.
    Using Graphics.DrawMeshInstanced to render.
    I combine multiple tiles (2k+) per mesh.

    On ECS side:
    Storing height and tile type in entities. Also, reference (starting index) to corresponding verts indices as per array.
    Using Perlin Noises to generate terrain variations.
    Apply heights to entities.
    Update verts and vertexColor arrays in parallel.
    And finally update arrays to actual mesh(es).
    It is important to use Set methods
    Code (CSharp):
    1. newMesh.SetVertices(vertices);
    not assignments
    Code (CSharp):
    1. newMesh.vertices = vertices ;
    otherwise generating GC and is much slower.

    upload_2020-11-12_9-15-49.png

    In this case, whole small planet, is a single mesh

    upload_2020-11-12_9-31-36.png
     
    bb8_1, bigchicken and Haneferd like this.
  6. SteveSync

    SteveSync

    Joined:
    Sep 25, 2013
    Posts:
    27
    I'm currently using the Mesh.MeshData class for updating the meshes which is part of the Mesh API mentioned above. So I can do `Mesh.ApplyAndDisposeWritableMeshData(meshDataArray, meshes);`

    That's actually been really useful in my various jobs.
     
  7. Nyanpas

    Nyanpas

    Joined:
    Dec 29, 2016
    Posts:
    406
    SetVertices() takes NativeArrays which I use for my own generator.
     
  8. bb8_1

    bb8_1

    Joined:
    Jan 20, 2019
    Posts:
    100
    Is it possible(fast enough using mb/jobs/burst or dots ) to create Earth-size planet using marching cubes algorithm - or only part of planet we are closest and the rest of the planet create using classic approach(simple cube we deform to sphere)? When we use cube deformed to sphere it is harder to create things like caves or stone-bridges formations for example and with marching cubes it is a lot easier...
     
  9. MNNoxMortem

    MNNoxMortem

    Joined:
    Sep 11, 2016
    Posts:
    723
    Not sure where I read it first, but thanks to everyone pointing out the new MeshData API - I missed it, and unknowingly waited for it :D
     
    Last edited: Apr 10, 2021