Using Appendbuffers in unity for terrain generation

Posted by Wardy on Game Development See other posts from Game Development or by Wardy
Published on 2014-02-10T11:48:26Z Indexed on 2014/06/11 3:49 UTC
Read the original article Hit count: 259

Filed under:
|
|
|

Like many others I figured I would try and make the most of the monster processing power of the GPU but I'm having trouble getting the basics in place.

CPU code:

using UnityEngine;
using System.Collections;

public class Test : MonoBehaviour
{
   public ComputeShader Generator;
   public MeshTopology Topology;

   void OnEnable()
   {
      var computedMeshPoints = ComputeMesh();
      CreateMeshFrom(computedMeshPoints);
   }

   private Vector3[] ComputeMesh()
   {
      var size = (32*32) * 4; // 4 points added for each x,z pos
      var buffer = new ComputeBuffer(size, 12, ComputeBufferType.Append);
      Generator.SetBuffer(0, "vertexBuffer", buffer);
      Generator.Dispatch(0, 1, 1, 1);
      var results = new Vector3[size];
      buffer.GetData(results);
      buffer.Dispose();
      return results;
   }

   private void CreateMeshFrom(Vector3[] generatedPoints)
   {
      var filter = GetComponent<MeshFilter>();
      var renderer = GetComponent<MeshRenderer>();

      if (generatedPoints.Length > 0)
      {
         var mesh = new Mesh { vertices = generatedPoints };
         var colors = new Color[generatedPoints.Length];
         var indices = new int[generatedPoints.Length];

         //TODO: build this different based on topology of the mesh being generated
         for (int i = 0; i < indices.Length; i++)
         {
            indices[i] = i;
            colors[i] = Color.blue;
         }

         mesh.SetIndices(indices, Topology, 0);
         mesh.colors = colors;

         mesh.RecalculateNormals();
         mesh.Optimize();
         mesh.RecalculateBounds();
         filter.sharedMesh = mesh;
      }
      else
      {
         filter.sharedMesh = null;
      }
   }
}

GPU code:

#pragma kernel Generate

AppendStructuredBuffer<float3> vertexBuffer : register(u0);

void genVertsAt(uint2 xzPos)
{
   //TODO: put some height generation code here.
   //      could even run marching cubes / dual contouring code.

   float3 corner1 = float3( xzPos[0], 0, xzPos[1] );
   float3 corner2 = float3( xzPos[0] + 1, 0, xzPos[1] );
   float3 corner3 = float3( xzPos[0], 0, xzPos[1] + 1);
   float3 corner4 = float3( xzPos[0] + 1, 0, xzPos[1] + 1 );

   vertexBuffer.Append(corner1);
   vertexBuffer.Append(corner2);
   vertexBuffer.Append(corner3);
   vertexBuffer.Append(corner4);
}

[numthreads(32, 1, 32)]
void Generate (uint3 threadId : SV_GroupThreadID, uint3 groupId : SV_GroupID)
{
   uint2 currentXZ = unint2( groupId.x * 32 + threadId.x, groupId.z * 32 + threadId.z);
   genVertsAt(currentXZ);
}

Can anyone explain why when I call "buffer.GetData(results);" on the CPU after the compute dispatch call my buffer is full of Vector3(0,0,0), I'm not expecting any y values yet but I would expect a bunch of thread indexes in the x,z values for the Vector3 array.

I'm not getting any errors in any of this code which suggests it's correct syntax-wise but maybe the issue is a logical bug.

Also: Yes, I know I'm generating 4,000 Vector3's and then basically round tripping them. However, the purpose of this code is purely to learn how round tripping works between CPU and GPU in Unity.

© Game Development or respective owner

Related posts about unity

Related posts about shaders