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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Bug Compute shader flatten chunk terrain array and make the array 2D once it hits the CPU again

Discussion in 'Shaders' started by Bloxxy213, Apr 14, 2023.

  1. Bloxxy213

    Bloxxy213

    Joined:
    Mar 24, 2023
    Posts:
    11
    Hello! So I'm trying to make terrain using compute shaders instead of CPU, and it works just fine for one single chunk, but whenever I try to use more chunks it gives weird results.

    One chunk:

    CPU:


    upload_2023-4-14_9-22-53.png

    GPU:

    upload_2023-4-14_9-24-12.png

    Multiple chunks (This is where it breaks itself):

    CPU:

    upload_2023-4-14_9-26-27.png

    GPU:

    upload_2023-4-14_9-30-51.png

    I belive this is a issue with how I'm storing the chunks, maybe in the heightPositions array.

    This is the compute shader:

    Code (CSharp):
    1. #include "noiseSimplex.cginc"
    2. #pragma kernel TerrainLevels
    3.  
    4. int seed;
    5. int scale;
    6. int octaves;
    7. int amplitude;
    8. float persistence;
    9.  
    10. RWStructuredBuffer<float> Result;
    11. StructuredBuffer<float> InputRanges;
    12.  
    13. uint indexFromCoord(uint3 id)
    14. {
    15.     return id.x + id.y * 16;
    16. }
    17.  
    18. [numthreads(16, 16, 1)]
    19. void TerrainLevels (uint3 dispatch_id : SV_DispatchThreadID, uint3 group_id : SV_GroupID, uint3 group_thread_id : SV_GroupThreadID)
    20. {
    21.     uint index = indexFromCoord(dispatch_id);
    22.  
    23.     Result[index] = dispatch_id.y + dispatch_id.x;
    24. }
    These are the important parts CPU side:

    Setting up the compute shader:

    Code (CSharp):
    1.         int terrain_kernel = noiseCompute.FindKernel("TerrainLevels");
    2.  
    3.         noiseCompute.SetInt("seed", seed);
    4.         noiseCompute.SetInt("scale", scale);
    5.         noiseCompute.SetInt("octaves", octaves);
    6.         noiseCompute.SetInt("amplitude", amplitude);
    7.         noiseCompute.SetFloat("persistence", persistence);
    8.  
    9.         List<float> formattedInput = new List<float>();
    10.         for (int i = 0; i < positions.Count; i++)
    11.         {
    12.             formattedInput.Add(positions[i].x);
    13.             formattedInput.Add(positions[i].y);
    14.         }
    15.  
    16.         outputHeightBuffer = new ComputeBuffer(positions.Count * chunkSize * chunkSize, sizeof(float));
    17.  
    18.         inputHeightBuffer = new ComputeBuffer(formattedInput.Count, sizeof(float));
    19.         inputHeightBuffer.SetData(formattedInput);
    20.  
    21.         noiseCompute.SetBuffer(terrain_kernel, "Result", outputHeightBuffer);
    22.         noiseCompute.SetBuffer(terrain_kernel, "InputRanges", inputHeightBuffer);
    23.  
    24.         noiseCompute.Dispatch(terrain_kernel, positions.Count, positions.Count, 1);
    25.         terrain_request = AsyncGPUReadback.Request(outputHeightBuffer);
    This is how Im getting the data from the GPU:

    Code (CSharp):
    1.         if (!checkedHeightBuffer && terrain_request.done && !terrain_request.hasError)
    2.         {
    3.             checkedHeightBuffer = true;
    4.             float[] output = new float[heightPositions.Count * 256];
    5.  
    6.             outputHeightBuffer.GetData(output);
    7.             __manipulateChunks(output);
    8.         }
    Code for manipulating the data received from the GPU:

    Code (CSharp):
    1.         for (int chunk_index = 0; chunk_index < heightPositions.Count; chunk_index++)
    2.         {
    3.             Vector2Int chunk_position = heightPositions[chunk_index];
    4.             Chunk chunk = grabChunk(chunk_position);
    5.             int startPosition = chunk_index * 256;
    6.  
    7.             for (int x = 0; x < chunkSize; x++)
    8.             {
    9.                 for (int z = 0; z < chunkSize; z++)
    10.                 {
    11.                     // first for GPU, second for CPU generation
    12.                
    13.                     float terrain_level = 100 + output[startPosition + x + z * 16];
    14.                     //float terrain_level = 100 + chunk_position.x * 16 + chunk_position.y * 16 + x + z;
    15.  
    16.  
    17.                 }
    18.             }
    19.  
    20.             chunk.shouldRender = true;
    21.             setChunk(chunk_position, chunk);
    22.         }
     
    Last edited: Apr 14, 2023
  2. Bloxxy213

    Bloxxy213

    Joined:
    Mar 24, 2023
    Posts:
    11
    I've still found no clue on how to fix this...
     
  3. Bloxxy213

    Bloxxy213

    Joined:
    Mar 24, 2023
    Posts:
    11
    This has been moved to the shader section (By a moderator I guess?), however I feel the issue is more a standard C# issue with flattening and then reading it.
     
  4. Bloxxy213

    Bloxxy213

    Joined:
    Mar 24, 2023
    Posts:
    11
  5. Bloxxy213

    Bloxxy213

    Joined:
    Mar 24, 2023
    Posts:
    11
    It seems like Shader theads are dead. How can I move it to the correct place?
     
  6. burningmime

    burningmime

    Joined:
    Jan 25, 2014
    Posts:
    845
    I can't tell exactly how you have laid out your data, but if it's a grid, then you want to multiply X by the width of the whole grid, and if it's per-chunk, then you'll need to add the chunk offset. Either way, this method is almost certainly not correct.

    Dispatch IDs for that will be from [0...16*positions.Count) in both X and Y dimensions. So if positions.Count is like 10, then you'll have IDs from (0,0) to (159,159) -- a total of 25600 invocations.
     
    Last edited: Apr 17, 2023