void Start()
        {
            //Allows this camera to draw mesh procedurally.
            PostRenderEvent.AddEvent(Camera.main, DrawMesh);

            //There are 8 threads run per group so N must be divisible by 8.
            if (N % 8 != 0)
            {
                throw new System.ArgumentException("N must be divisible be 8");
            }

            //Holds the voxel values, generated from perlin noise.
            m_noiseBuffer = new ComputeBuffer(N * N * N, sizeof(float));

            //Holds the normals of the voxels.
            m_normalsBuffer                   = new RenderTexture(N, N, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear);
            m_normalsBuffer.dimension         = TextureDimension.Tex3D;
            m_normalsBuffer.enableRandomWrite = true;
            m_normalsBuffer.useMipMap         = false;
            m_normalsBuffer.volumeDepth       = N;
            m_normalsBuffer.Create();

            //Holds the verts generated by the marching cubes.
            m_meshBuffer = new ComputeBuffer(SIZE, sizeof(float) * 7);

            //These two buffers are just some settings needed by the marching cubes.
            m_cubeEdgeFlags = new ComputeBuffer(256, sizeof(int));
            m_cubeEdgeFlags.SetData(MarchingCubesTables.CubeEdgeFlags);
            m_triangleConnectionTable = new ComputeBuffer(256 * 16, sizeof(int));
            m_triangleConnectionTable.SetData(MarchingCubesTables.TriangleConnectionTable);

            //Make the perlin noise, make sure to load resources to match shader used.
            perlin = new GPUPerlinNoise(m_seed);
            perlin.LoadResourcesFor4DNoise();
        }
        void OnDestroy()
        {
            //MUST release buffers.
            m_noiseBuffer.Release();
            m_meshBuffer.Release();
            m_cubeEdgeFlags.Release();
            m_triangleConnectionTable.Release();
            m_normalsBuffer.Release();

            PostRenderEvent.RemoveEvent(Camera.main, DrawMesh);
        }
        public static void RemoveEvent(Camera camera, CameraEventHandler onPostRenderEvent)
        {
            if (camera == null)
            {
                return;
            }

            PostRenderEvent e = camera.GetComponent <PostRenderEvent>();

            if (e != null)
            {
                e.OnEvent -= onPostRenderEvent;
            }
        }
        void Start()
        {
            //Allows this camera to draw mesh procedurally.
            PostRenderEvent.AddEvent(Camera.main, DrawMesh);

            //There are 8 threads run per group so N must be divisible by 8.
            if (N % 8 != 0)
            {
                throw new System.ArgumentException("N must be divisible be 8");
            }

            //Holds the voxel values, generated from perlin noise.
            m_noiseBuffer = new ComputeBuffer(N * N * N, sizeof(float));

            //Holds the normals of the voxels.
            m_normalsBuffer                   = new RenderTexture(N, N, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear);
            m_normalsBuffer.dimension         = TextureDimension.Tex3D;
            m_normalsBuffer.enableRandomWrite = true;
            m_normalsBuffer.useMipMap         = false;
            m_normalsBuffer.volumeDepth       = N;
            m_normalsBuffer.Create();

            //Holds the verts generated by the marching cubes.
            m_meshBuffer = new ComputeBuffer(SIZE, sizeof(float) * 7);

            //Clear the mesh verts to -1. See the TriangleConnectionTable.
            //Only verts that get generated will then have a value of 1.
            //Only required if reading back the mesh.
            //Could also use the ClearMesh compute shader provided.
            float[] val = new float[SIZE * 7];
            for (int i = 0; i < SIZE * 7; i++)
            {
                val[i] = -1.0f;
            }

            m_meshBuffer.SetData(val);

            //These two buffers are just some settings needed by the marching cubes.
            m_cubeEdgeFlags = new ComputeBuffer(256, sizeof(int));
            m_cubeEdgeFlags.SetData(MarchingCubesTables.CubeEdgeFlags);
            m_triangleConnectionTable = new ComputeBuffer(256 * 16, sizeof(int));
            m_triangleConnectionTable.SetData(MarchingCubesTables.TriangleConnectionTable);

            //Make the perlin noise, make sure to load resources to match shader used.
            perlin = new GPUPerlinNoise(m_seed);
            perlin.LoadResourcesFor3DNoise();

            //Make the voxels.
            m_perlinNoise.SetInt("_Width", N);
            m_perlinNoise.SetInt("_Height", N);
            m_perlinNoise.SetFloat("_Frequency", 0.02f);
            m_perlinNoise.SetFloat("_Lacunarity", 2.0f);
            m_perlinNoise.SetFloat("_Gain", 0.5f);
            m_perlinNoise.SetTexture(0, "_PermTable2D", perlin.PermutationTable2D);
            m_perlinNoise.SetTexture(0, "_Gradient3D", perlin.Gradient3D);
            m_perlinNoise.SetBuffer(0, "_Result", m_noiseBuffer);

            m_perlinNoise.Dispatch(0, N / 8, N / 8, N / 8);

            //Make the voxel normals.
            m_normals.SetInt("_Width", N);
            m_normals.SetInt("_Height", N);
            m_normals.SetBuffer(0, "_Noise", m_noiseBuffer);
            m_normals.SetTexture(0, "_Result", m_normalsBuffer);

            m_normals.Dispatch(0, N / 8, N / 8, N / 8);

            //Make the mesh verts
            m_marchingCubes.SetInt("_Width", N);
            m_marchingCubes.SetInt("_Height", N);
            m_marchingCubes.SetInt("_Depth", N);
            m_marchingCubes.SetInt("_Border", 1);
            m_marchingCubes.SetFloat("_Target", 0.0f);
            m_marchingCubes.SetBuffer(0, "_Voxels", m_noiseBuffer);
            m_marchingCubes.SetTexture(0, "_Normals", m_normalsBuffer);
            m_marchingCubes.SetBuffer(0, "_Buffer", m_meshBuffer);
            m_marchingCubes.SetBuffer(0, "_CubeEdgeFlags", m_cubeEdgeFlags);
            m_marchingCubes.SetBuffer(0, "_TriangleConnectionTable", m_triangleConnectionTable);

            m_marchingCubes.Dispatch(0, N / 8, N / 8, N / 8);

            //Reads back the mesh data from the GPU and turns it into a standard unity mesh.
            //ReadBackMesh(m_meshBuffer);
        }