Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Job system for procedural voxel world mesh generation

Discussion in 'C# Job System' started by pherda, Aug 22, 2023.

  1. pherda

    pherda

    Joined:
    Aug 27, 2020
    Posts:
    9
    I am making a (surprise surprise) minecraft-like infinite procedurally generated game that utilizes the Unity Job System for chunk generation. Note: I am only using Jobs, not ECS, chunks are gameobjects.

    My current implementation is as follows:
    - World.Update() gets all chunks within view distance, if it already exists, simply enable it, if it's new, add it to a queue to be created.
    - ChunkManager.Update() loops through each item in queue, creates each chunk object:
    - Chunk's 16x256x16 block array (flattened to a NativeArray<byte>) is populated inside a job. Adjacent chunk arrays are scheduled to populate as well (explained below). Dequeue and add to mesh queue
    - Loops through each item in mesh queue:
    - Chunk's mesh data generation is calculated inside job, uses block array and adjacent chunks' block arrays too. Uses previous job handle as a dependency. Dequeue
    - Chunks' mesh data applied to mesh filter/renderer in coroutine, 'yield return null' until previous job is completed, then runs.

    In order to generate the mesh data, I need access to the blocks from adjacent chunks to decide whether to render the outside faces of a chunk. Because this is being done inside a job, I can't simply access my World object, get an adjacent chunk, and get the needed block, so I am just passing the entire block arrays of the adjacent chunks, along with the current chunk's block array to each mesh data generation job. Is there a better way to access adjacent chunk data without just passing the whole array? I also get occasional InvalidOperationExceptions from writing to adjacent chunks then trying to read from them in the next job even though everything has correct dependencies but that's a whole other issue. I thought about adding 4 more arrays to each chunk which contains the surrounding blocks on each side but that seems like a lot of overhead because it would add an extra 16,384 bytes (16x256x4) to a chunk that already has 65536 (16x256x16) bytes for its block array. Is the overhead worth it or do y'all have better solutions?

    Thanks in advance.
     
  2. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    3,721
    you could have a separate job that determines border face visibility between two chunks and store that data for both chunks (and each side of a chunk). You only need to update that data once when a chunk changes.

    Sorry, my initial reply i only considered „hidden surface removal“.
     
    Last edited: Aug 22, 2023
    pherda likes this.
  3. pherda

    pherda

    Joined:
    Aug 27, 2020
    Posts:
    9
    You mean like input the two block arrays into a job and output a bool array and use that to determine what to render for the outside? Would you keep the results or dispose of it after you generate the mesh?
     
  4. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    3,721
    Yes, and I would keep it as long as both or any visible chunk still references that data. You may even have two copies, each assigned to a specific chunk to not having to bother managing these. You can then simply discard the border data when the chunk goes out of scope, then recreate it when it becomes visible again respectively check the neighbours and take their available data (unsafe memcopy would be fastest to duplicate that array).
     
    pherda likes this.
  5. pherda

    pherda

    Joined:
    Aug 27, 2020
    Posts:
    9
    So if I'm understanding this correctly, the job would basically input an adjacent block array, calculate the index of each block on the connecting face, eg. north array where z = 0 from (0,0,0) to (15,255,0), get whether each block should be rendered as a bool, then paste that data to a bool array?
     
  6. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    3,721
    Basically yes, although you could also use a BitArray to save space by a factor of 8 (bool is a byte).
     
    pherda likes this.
  7. pherda

    pherda

    Joined:
    Aug 27, 2020
    Posts:
    9
    Ah I didn't even know that existed, good to know.

    In the midst of implementing this all and it seems to be working so far so thanks for your help!