Esempio n. 1
0
    public override bool Calculate()
    {
        VoxelBlock <T> block = input.GetValue <VoxelBlock <T> >();

        if (block == null || block.Layers == null)
        {
            return(false);
        }

        CalculationSetup(block);
        bool success = true;

        for (int i = 0; i < block.Layers.Count(); i++)
        {
            if (!CalculateLayer(block.Layers[i], i - block.Overlap))
            {
                success = false;
                break;
            }
        }
        CalculationTeardown();

        output.SetValue(block);

        return(success);
    }
Esempio n. 2
0
        protected void apply(Application app, VoxelBlock block, Index pos)
        {
            Index cornerChild = pos.getChild();

            for (byte c = 0; c < VoxelBlock.CHILD_COUNT; ++c)
            {
                // TODO: use min and max to reduce number of values considered
                Index  childPos = cornerChild.getNeighbor(c);
                Action action   = checkMutation(app, childPos);
                if (!action.modify)
                {
                    continue;
                }
                Action maskAction = checkMasks(app.tree, childPos);
                if (!maskAction.modify)
                {
                    continue;
                }
                if (childPos.depth < app.tree.maxDetail && (maskAction.doTraverse || action.doTraverse))
                {
                    apply(app, block.expand(childPos.xLocal, childPos.yLocal, childPos.zLocal), childPos);
                }
                else
                {
                    block.children[childPos.xLocal, childPos.yLocal, childPos.zLocal] =
                        mutate(app, childPos, action, block.children[childPos.xLocal, childPos.yLocal, childPos.zLocal].toVoxel());
                }
                if (childPos.depth == app.tree.maxDetail - VoxelRenderer.VOXEL_COUNT_POWER && (action.modify))
                {
                    block.updateAll(childPos.x, childPos.y, childPos.z, childPos.depth, app.tree, true);
                }
            }
        }
Esempio n. 3
0
 protected override void CalculationSetup(VoxelBlock <Voxel> block)
 {
     width  = block.Width;
     height = block.Height;
     length = block.Length;
     offset = block.Offset;
 }
Esempio n. 4
0
    public override bool Calculate()
    {
        VoxelBlock <T> block = new VoxelBlock <T>();

        block.Offset = Offset;
        output.SetValue(InitBlock(block));
        return(true);
    }
Esempio n. 5
0
        public List <VoxelBlock> findPath(VoxelBlock start, VoxelBlock goal)
        {
            var closedset = new HashSet <VoxelBlock>();
            var openset   = new HashSet <VoxelBlock>();

            openset.Add(start);
            var came_from = new Dictionary <VoxelBlock, VoxelBlock>();

            var g_score = new Dictionary <VoxelBlock, float>();
            var f_score = new Dictionary <VoxelBlock, float>();

            //came_from := the empty map    // The map of navigated nodes.

            g_score[start] = 0;    // Cost from start along best known path.
            // Estimated total cost from start to goal through y.
            f_score[start] = g_score[start] + heuristic_cost_estimate(start, goal);

            int numIts = 100;

            while (openset.Count > 0)
            {
                numIts--;
                if (numIts < 0)
                {
                    return(null);
                }
                //openset.Sort((a, b) => f_score[a] < f_score[b] ? -1 : f_score[a] > f_score[b] ? 1 : 0);
                var current = openset.OrderBy(o => f_score[o]).First(); // the node in openset having the lowest f_score[] value
                if (current.Equals(goal))
                {
                    return(reconstruct_path(came_from, goal));
                }

                openset.Remove(current); //remove current from openset
                closedset.Add(current);  //add current to closedset

                foreach (var neighbor in connected_nodes(current))
                {
                    //TW.Graphics.LineManager3D.AddCenteredBox(neighbor.Position + MathHelper.One*0.5f,0.5f, new Color4(0,0,1));
                    if (closedset.Contains(neighbor))
                    {
                        continue;
                    }
                    var tentative_g_score = g_score[current] + dist_between(current, neighbor);
                    if (!openset.Contains(neighbor) || tentative_g_score <= g_score[neighbor])
                    {
                        came_from[neighbor] = current;
                        g_score[neighbor]   = tentative_g_score;
                        f_score[neighbor]   = g_score[neighbor] + heuristic_cost_estimate(neighbor, goal);
                        if (!openset.Contains(neighbor))
                        {
                            openset.Add(neighbor);
                        }
                    }
                }
            }
            return(null);
        }
Esempio n. 6
0
    public override bool Calculate()
    {
        if (!block1Connection.connected() || !block2Connection.connected())
        {
            return(false);
        }
        VoxelBlock <Voxel> block1 = block1Connection.GetValue <VoxelBlock <Voxel> >();
        VoxelBlock <Voxel> block2 = block2Connection.GetValue <VoxelBlock <Voxel> >();

        int overlap = block1.Overlap;
        int width   = block1.Width;
        int height  = block1.Height;
        int length  = block1.Length;

        for (int y = 0; y < height + 2 * overlap; y++)
        {
            VoxelLayer <Voxel> l1 = block1.Layers[y];
            VoxelLayer <Voxel> l2 = block2.Layers[y];
            for (int x = 0; x < width + 2 * overlap; x++)
            {
                for (int z = 0; z < length + 2 * overlap; z++)
                {
                    var v1 = l1.Layer[x, z];
                    var v2 = l2.Layer[x, z];
                    switch (mode)
                    {
                    case CombiningMode.Average:
                        v1.Data = (v1.Data + v2.Data) / 2;
                        break;

                    case CombiningMode.Add:
                        v1.Data = v1.Data + v2.Data;
                        break;

                    case CombiningMode.Subtract:
                        v1.Data = v1.Data - v2.Data;
                        break;

                    case CombiningMode.Divide:
                        if (v2.Data != 0)
                        {
                            v1.Data = v1.Data / v2.Data;
                        }
                        break;

                    case CombiningMode.Multiply:
                        v1.Data = v1.Data * v2.Data;
                        break;
                    }
                }
            }
        }
        outputConnection.SetValue(block1);

        return(true);
    }
Esempio n. 7
0
    public void ReInit(VoxelBlock <Voxel> block)
    {
        int overlap     = block.Overlap;
        int blockHeight = block.Height + 2 * overlap;
        int blockWidth  = block.Width + 2 * overlap;
        int blockLength = block.Length + 2 * overlap;

        if (initHeight == blockHeight && initWidth == blockWidth && initLength == blockLength)
        {
            // we are already set up to process blocks of this size
            return;
        }

        Debug.LogFormat("reinit block ({0}, {1}, {2}) => ({3}, {4}, {5})", initWidth, initHeight, initLength, blockWidth, blockHeight, blockLength);

        initWidth  = blockWidth;
        initHeight = blockHeight;
        initLength = blockLength;

        float[] dummyVoxels = new float[blockHeight * blockWidth * blockLength];
        addPadding(ref dummyVoxels, ref blockWidth, ref blockHeight, ref blockLength);
        numBlocks = new Vector3Int((blockWidth - 1) / blockSize.x, (blockHeight - 1) / blockSize.y, (blockLength - 1) / blockSize.z);

        if (voxelBuffer != null)
        {
            voxelBuffer.Dispose();
        }
        voxelBuffer = new ComputeBuffer(dummyVoxels.Length, sizeof(float));
        if (minMaxBuffer != null)
        {
            minMaxBuffer.Dispose();
        }
        minMaxBuffer = new ComputeBuffer(numBlocks.x * numBlocks.y * numBlocks.z, 2 * sizeof(float));
        if (compactedBlkArray != null)
        {
            compactedBlkArray.Dispose();
        }
        compactedBlkArray = new ComputeBuffer(numBlocks.x * numBlocks.y * numBlocks.z, sizeof(int));

        PMBShader.SetBuffer(minMaxKernelIndex, "voxelBuffer", voxelBuffer);
        PMBShader.SetBuffer(minMaxKernelIndex, "minMaxBuffer", minMaxBuffer);
        PMBShader.SetInts("size", new int[] { blockWidth, blockHeight, blockLength });
        PMBShader.SetInts("numBlocks", new int[] { numBlocks.x, numBlocks.y, numBlocks.z });

        PMBShader.SetBuffer(compactActiveBlocksKernelIndex, "activeBlkNum", activeBlkNum);
        PMBShader.SetBuffer(compactActiveBlocksKernelIndex, "minMaxBuffer", minMaxBuffer);
        PMBShader.SetBuffer(compactActiveBlocksKernelIndex, "compactedBlkArray", compactedBlkArray);

        PMBShader.SetBuffer(generateTrianglesKernelIndex, "marchingCubesEdgeTable", marchingCubesEdgeTableBuffer);
        PMBShader.SetBuffer(generateTrianglesKernelIndex, "globalVertexOffset", globalVertexOffset);
        PMBShader.SetBuffer(generateTrianglesKernelIndex, "voxelBuffer", voxelBuffer);
        PMBShader.SetBuffer(generateTrianglesKernelIndex, "compactedBlkArray", compactedBlkArray);
    }
Esempio n. 8
0
        private float heuristic_cost_estimate(VoxelBlock start, VoxelBlock goal)
        {
            var   a    = terrain.GetPositionOf(start);
            var   b    = terrain.GetPositionOf(goal);
            float dist = 0;

            for (int i = 0; i < 3; i++)
            {
                dist += (float)Math.Abs(a[i] - b[i]);
            }
            return(dist);
        }
Esempio n. 9
0
        private IEnumerable <VoxelBlock> connected_nodes(VoxelBlock current)
        {
            bool inAir = !getBelow(current).Filled;

            // give neighbours with soil under
            foreach (var n in neighbor_nodes(current).Where(n => !n.Filled))
            {
                if (n.RelativePosition.Y != current.RelativePosition.Y)
                {
                    continue; // no vertical movement
                }
                VoxelBlock it        = n;
                int        fallDepth = 3; //TODO fix staying in air when once in air
                if (inAir)
                {
                    fallDepth = 1;
                }
                for (int i = 0; i < fallDepth; i++)
                {
                    it = getBelow(it);
                    if (it != null && it.Filled)
                    {
                        if (n.Filled)
                        {
                            throw new InvalidOperationException();
                        }
                        yield return(n);
                    }
                }
            }

            if (!inAir)
            {
                var up = getUp(current);
                if (up != null && !up.Filled)
                {
                    if (up.Filled)
                    {
                        throw new InvalidOperationException();
                    }
                    yield return(up);
                }
            }
            else
            {
                if (getBelow(current).Filled)
                {
                    throw new InvalidOperationException();
                }
                yield return(getBelow(current));
            }
        }
Esempio n. 10
0
 public VoxelBlock(VoxelBlock <T> b)
 {
     if (b == null)
     {
         return;
     }
     this.Offset = b.Offset;
     if (b.Layers != null)
     {
         this.layers = new VoxelLayer <T> [b.layers.Count()];
         for (int i = 0; i < b.layers.Count(); i++)
         {
             this.layers[i] = new VoxelLayer <T>(b.layers[i]);
         }
     }
     this.Overlap = b.Overlap;
 }
Esempio n. 11
0
    public override bool Calculate()
    {
        VoxelBlock <T> block = input.GetValue <VoxelBlock <T> >();

        if (block == null || block.Layers == null)
        {
            return(false);
        }

        CalculationSetup(block);
        bool success = block.Layers.AsParallel().Select((layer, i) => CalculateLayer(layer, i)).All(x => x);

        CalculationTeardown();

        output.SetValue(block);

        return(success);
    }
Esempio n. 12
0
        private IEnumerable <VoxelBlock> neighbor_nodes(VoxelBlock current)
        {
            for (int i = 0; i < 3; i++)
            {
                var axis = new Point3();
                axis[i] = 1;

                var n1 = terrain.GetVoxelAt(terrain.GetPositionOf(current) + axis);
                var n2 = terrain.GetVoxelAt(terrain.GetPositionOf(current) - axis);

                if (n1 != null)
                {
                    yield return(n1);
                }
                if (n2 != null)
                {
                    yield return(n2);
                }
            }
        }
    VoxelBlock <Voxel> InitBlock(Vector3Int size)
    {
        VoxelBlock <Voxel> block = new VoxelBlock <Voxel>();

        VoxelLayer <Voxel>[] layers = new VoxelLayer <Voxel> [size.y];
        for (int y = 0; y < size.y; y++)
        {
            Voxel[,] voxelLayer = new Voxel[size.x, size.z];
            for (int x = 0; x < size.x; x++)
            {
                for (int z = 0; z < size.z; z++)
                {
                    voxelLayer[x, z] = new Voxel();
                }
            }
            layers[y] = new VoxelLayer <Voxel>(voxelLayer);
        }
        block.Layers = layers;
        return(block);
    }
Esempio n. 14
0
		protected void apply(Application app, VoxelBlock block, Index pos) {
			Index cornerChild = pos.getChild();
			for(byte c = 0; c<VoxelBlock.CHILD_COUNT; ++c) {
				// TODO: use min and max to reduce number of values considered
				Index childPos = cornerChild.getNeighbor(c);
				Action action = checkMutation(app, childPos);
				if (!action.modify)
					continue;
				Action maskAction = checkMasks(app.tree, childPos);
				if (!maskAction.modify)
					continue;
				if (childPos.depth < app.tree.maxDetail && (maskAction.doTraverse || action.doTraverse))
					apply(app, block.expand(childPos.xLocal, childPos.yLocal, childPos.zLocal), childPos);
				else
					block.children[childPos.xLocal, childPos.yLocal, childPos.zLocal] =
						mutate(app, childPos, action, block.children[childPos.xLocal, childPos.yLocal, childPos.zLocal].toVoxel());
				if (childPos.depth == app.tree.maxDetail - VoxelRenderer.VOXEL_COUNT_POWER && (action.modify))
					block.updateAll(childPos.x, childPos.y, childPos.z, childPos.depth, app.tree, true);
			}
		}
Esempio n. 15
0
    protected override VoxelBlock <Voxel> InitBlock(VoxelBlock <Voxel> block)
    {
        int size = 64;

        VoxelLayer <Voxel>[] layers = new VoxelLayer <Voxel> [64];
        for (int y = 0; y < size; y++)
        {
            Voxel[,] voxelLayer = new Voxel[size, size];
            for (int x = 0; x < size; x++)
            {
                for (int z = 0; z < size; z++)
                {
                    voxelLayer[x, z] = new Voxel();
                    if (y < size / 2)
                    {
                        voxelLayer[x, z].Data = 1.0f;
                    }
                }
            }
            layers[y] = new VoxelLayer <Voxel>(voxelLayer);
        }
        block.Layers = layers;
        return(block);
    }
Esempio n. 16
0
 public void Weld( VoxelBlock block2 ,   int dir2 ,   int p1 ,   int p2  )
 {
     if (block2!=null && block2.faces[dir2]!=null) Weld( block2.faces[dir2], p1, p2, true);
 }
Esempio n. 17
0
 protected virtual void CalculationSetup(VoxelBlock <T> block)
 {
 }
Esempio n. 18
0
 //same as above, but works only when no p1 (for cross-block)
 public void Weld( VoxelBlock block2 ,   int dir2 ,   int p1 ,   int p2 ,   bool check  )
 {
     if (verts[p1]==null && block2!=null && block2.faces[dir2]!=null && block2.faces[dir2].verts[p2]==null)
         Weld( block2.faces[dir2], p1, p2, true);
 }
Esempio n. 19
0
        public List <VoxelBlock> reconstruct_path(Dictionary <VoxelBlock, VoxelBlock> came_from, VoxelBlock current_node)
        {
            var ret = new List <VoxelBlock>();

            for (int i = 0; i < 200; i++)
            {
                ret.Add(current_node);
                if (!came_from.ContainsKey(current_node))
                {
                    break;
                }
                current_node = came_from[current_node];
            }

            return(ret);
            //if came_from[current_node] in set
            //    p := reconstruct_path(came_from, came_from[current_node])
            //    return (p + current_node)
            //else

            //    return current_node
        }
Esempio n. 20
0
 //welding three poins (side) using mid-point number
 public void Weld( VoxelBlock block2 ,   int dir2 ,     int pA1 ,   int pA2 ,   int pA3 ,     int pB1 ,   int pB2 ,   int pB3  )
 {
     if (verts[pA2]==null && block2!=null && block2.faces[dir2]!=null && block2.faces[dir2].verts[pB2]==null)
     {
         VoxelFace fB = block2.faces[dir2];
         Weld(fB, pA1, pB1); Weld(fB, pA2, pB2); Weld(fB, pA3, pB3);
     }
 }
Esempio n. 21
0
 private VoxelBlock getUp(VoxelBlock block)
 {
     return(terrain.GetVoxelAt(terrain.GetPositionOf(block) + MathHelper.Up));
 }
Esempio n. 22
0
        public void CalculateTerrain()
        {
            terrainProgress = Progress.threadStarted;
            //bool isMainThread = System.Threading.Thread.CurrentThread.ManagedThreadId == Voxel.mainThreadId;
            //bool isMainThread = false;

            int x=0; int y=0; int z=0; //int nx=0; int ny=0; int nz=0;
            int dir = 0; int v=0; int f=0; int i = 0;
            VoxelBlock block; VoxelFace face; VoxelVert vert;// VoxelFace nface;
            //Vector3 pos;

            System.Collections.Generic.List<VoxelFace> faces = new System.Collections.Generic.List<VoxelFace>();

            #region Calculating top and bottom points
            int topPoint = land.data.GetTopPoint(offsetX, offsetZ, offsetX+size, offsetZ+size)+1;
            int bottomPoint = Mathf.Max(0, land.data.GetBottomPoint(offsetX, offsetZ, offsetX+size, offsetZ+size)-2);
            int shortHeight = topPoint - bottomPoint;

            //emergency exit if chunk contains no blocks
            if (topPoint<=1) { visibleFaces.Clear(); terrainProgress = Progress.calculated; return; }
            #endregion

            bool[] existMatrix = new bool[size*size*shortHeight];
            land.data.GetExistMatrix (existMatrix,  offsetX, bottomPoint, offsetZ,  offsetX+size, topPoint, offsetZ+size);

            VoxelBlock[] blocks = new VoxelBlock[size*shortHeight*size];

            #region Creating all faces

            //for (y=bottomPoint; y<topPoint; y++)
            for (y=0; y<shortHeight; y++)
                for (x=0; x<size; x++)
                    for (z=0; z<size; z++)
                {
                    i = z*shortHeight*size + y*size + x;

                    //if exists
                    //if (land.data.GetExist(x+offsetX,y,z+offsetZ))
                    if (existMatrix[z*size*shortHeight + y*size + x])
                        for (dir = 0; dir<6; dir++)
                    {
                        //if has face at this side
                        if (x+VoxelFace.dirToPosX[dir] >= 0 && x+VoxelFace.dirToPosX[dir] < size &&  //cap sides here
                            y+VoxelFace.dirToPosY[dir] >= 0 && y+VoxelFace.dirToPosY[dir] < shortHeight &&
                            z+VoxelFace.dirToPosZ[dir] >= 0 && z+VoxelFace.dirToPosZ[dir] < size &&
                            !existMatrix[ (z+VoxelFace.dirToPosZ[dir])*size*shortHeight + (y+VoxelFace.dirToPosY[dir])*size + x+VoxelFace.dirToPosX[dir] ])
                        {
                            if (blocks[i]==null)
                            {
                                blocks[i] = new VoxelBlock(x,y+bottomPoint,z);

                                if (x<land.overlap || x>=size-land.overlap ||
                                    z<land.overlap || z>=size-land.overlap ||
                                    y == 0)
                                        blocks[i].visible = false;
                                else blocks[i].visible = true;

                                byte typeNum = land.data.GetBlock(x+offsetX, y+bottomPoint, z+offsetZ);
                                if (typeNum < land.types.Length) blocks[i].type = land.types[typeNum];
                                else blocks[i].type = land.types[0];

                                blocks[i].chunk = this;
                            }

                            face = new VoxelFace();
                            faces.Add(face);

                            blocks[i].faces[dir] = face;

                            face.block = blocks[i];
                            face.dir = (byte)dir;

                            //setting face type, and adding it to used types array
                            //face.type = (byte)land.data.GetBlock(x+offsetX, y+bottomPoint, z+offsetZ);
                            //if (!usedTypes.Contains(face.type)) usedTypes.Add(face.type);

                            face.visible = face.block.type.filled; //land.data.exist[face.block.type]; //land.types[face.block.type].visible;

                            //setting coords
                            for (v=0;v<9;v++)
                            {
                                //pos = VoxelVert.posTable[ dir*9 + v ] + new Vector3(x,y,z);
                                //face.coords[v] = 1000000 + pos.x*20000 + pos.y*200 + pos.z*2;
                            }
                        }
                    }
                }
            #endregion

            #region Welding internal, Welding neig

            int maxSize = size-1;
            int maxHeight = shortHeight-1;

            for (y=0; y<shortHeight; y++)
                for (x=0; x<size; x++)
                    for (z=0; z<size; z++)
            {
                    int stepz = shortHeight*size;
                    i = z*stepz + y*size + x;

                    if (blocks[i]!=null) for (dir = 0; dir<6; dir++)
                    {
                        block = blocks[i];
                        face = block.faces[dir];
                        if (face==null) continue;

                        //weld this block
                        switch (dir)
                        {
                        case 0: face.Weld( block, 5,  0,1,2, 2,1,0); face.Weld( block, 2,  2,3,4, 2,1,0);
                            face.Weld( block, 4,  4,5,6, 2,1,0); face.Weld( block, 3,  6,7,0, 2,1,0);

                            if (x>0) face.Weld( blocks[i-1], 0,  6,7,0, 4,3,2);
                            if (z>0) face.Weld( blocks[i-stepz], 0,  4,5,6, 2,1,0);

                            break;

                        case 1: face.Weld( block, 5,  0,1,2, 6,5,4); face.Weld( block, 3,  2,3,4, 6,5,4);
                            face.Weld( block, 4,  4,5,6, 6,5,4); face.Weld( block, 2,  6,7,0, 6,5,4);

                            if (x>0) face.Weld( blocks[i-1], 1,  2,3,4, 0,7,6);
                            if (z>0) face.Weld( blocks[i-stepz], 1,  4,5,6, 2,1,0);

                            break;

                        case 2: face.Weld( block, 0,  0,1,2, 4,3,2); face.Weld( block, 5,  2,3,4, 0,7,6);
                            face.Weld( block, 1,  4,5,6, 0,7,6); face.Weld( block, 4,  6,7,0, 4,3,2);

                            if (y>0) face.Weld( blocks[i-size], 2,  4,5,6, 2,1,0);
                            if (z>0) face.Weld( blocks[i-stepz], 2,  6,7,0, 4,3,2);

                            break;

                        case 3: face.Weld( block, 0,  0,1,2, 0,7,6); face.Weld( block, 4,  2,3,4, 0,7,6);
                            face.Weld( block, 1,  4,5,6, 4,3,2); face.Weld( block, 5,  6,7,0, 4,3,2);

                            if (y>0) face.Weld( blocks[i-size], 3,  4,5,6, 2,1,0);
                            if (z>0) face.Weld( blocks[i-stepz], 3,  2,3,4, 0,7,6);

                            break;

                        case 4: face.Weld( block, 0,  0,1,2, 6,5,4); face.Weld( block, 2,  2,3,4, 0,7,6);
                            face.Weld( block, 1,  4,5,6, 6,5,4); face.Weld( block, 3,  6,7,0, 4,3,2);

                            if (y>0) face.Weld( blocks[i-size], 4,  4,5,6, 2,1,0);
                            if (x>0) face.Weld( blocks[i-1], 4,  6,7,0, 4,3,2);

                            break;

                        case 5: face.Weld( block, 0,  0,1,2, 2,1,0); face.Weld( block, 3,  2,3,4, 0,7,6);
                            face.Weld( block, 1,  4,5,6, 2,1,0); face.Weld( block, 2,  6,7,0, 4,3,2);

                            if (y>0) face.Weld( blocks[i-size], 5,  4,5,6, 2,1,0);
                            if (x>0) face.Weld( blocks[i-1], 5,  2,3,4, 0,7,6);

                            break;
                        }
                    }
            }
            #endregion

            #region Cross-welding

            for (y=0; y<shortHeight; y++)
                for (x=0; x<size; x++)
                    for (z=0; z<size; z++)
            {
                    int stepz = shortHeight*size;
                    i = z*stepz + y*size + x;
                    int j = i;

                    if (blocks[i]!=null) for (dir = 0; dir<6; dir++)
                    {
                        face = blocks[i].faces[dir];
                        if (face==null) continue;

                        //weld cross block
                        if (dir==0 && y<maxHeight)
                        {
                            j = i+size;
                            if (x>0) face.Weld( blocks[j-1], 2,  6,7,0, 6,5,4); 		//x-1,y+1,z
                            if (z>0) face.Weld( blocks[j-stepz], 5,  4,5,6, 6,5,4); 	//x,y+1,z-1
                            if (x<maxSize) face.Weld( blocks[j+1], 3,  2,3,4, 6,5,4); 	//x+1,y+1,z
                            if (z<maxSize) face.Weld( blocks[j+stepz], 4,  0,1,2, 6,5,4); 	//x,y+1,z+1
                        }

                        else if (dir==1 && y>0)
                        {
                            j = i-size;
                            if (x>0) face.Weld( blocks[j-1], 2,  2,3,4, 2,1,0);		//x-1,y-1,z
                            if (z>0) face.Weld( blocks[j-stepz], 5,  4,5,6, 2,1,0);		//x,y-1,z-1
                            if (x<maxSize) face.Weld( blocks[j+1], 3,  6,7,0, 2,1,0);		//x+1,y-1,z
                            if (z<maxSize) face.Weld( blocks[j+stepz], 4,  0,1,2, 2,1,0);		//x,y-1,z+1
                        }

                        else if (dir==2 && x<maxSize)
                        {
                            j = i+1;
                            if (y>0) face.Weld( blocks[j-size], 0,  4,5,6, 0,7,6);		//x+1,y-1,z
                            if (z>0) face.Weld( blocks[j-stepz], 5,  6,7,0, 4,3,2);		//x+1,y,z-1
                            if (y<maxHeight) face.Weld( blocks[j+size], 1,  0,1,2, 4,3,2);//x+1,y+1,z
                            if (z<maxSize) face.Weld( blocks[j+stepz], 4,  2,3,4, 0,7,6);		//x+1,y,z+1
                        }

                        else if (dir==3 && x>0)
                        {
                            j = i-1;
                            if (y>0) face.Weld( blocks[j-size], 0,  4,5,6, 4,3,2);		//x-1,y-1,z
                            if (z>0) face.Weld( blocks[j-stepz], 5,  2,3,4, 0,7,6);		//x-1,y,z-1
                            if (y<maxHeight) face.Weld( blocks[j+size], 1,  0,1,2, 0,7,6);//x-1,y+1,z
                            if (z<maxSize) face.Weld( blocks[j+stepz], 4,  6,7,0, 4,3,2);		//x-1,y,z+1
                        }

                        else if (dir==4 && z>0)
                        {
                            j = i-stepz;
                            if (y>0) face.Weld( blocks[j-size], 0,  4,5,6, 2,1,0);		//x,y-1,z-1
                            if (x>0) face.Weld( blocks[j-1], 2,  6,7,0, 4,3,2);		//x-1,y,z-1
                            if (y<maxHeight) face.Weld( blocks[j+size], 1,  0,1,2, 2,1,0);//x,y+1,z-1
                            if (x<maxSize) face.Weld( blocks[j+1], 3,  2,3,4, 0,7,6);		//x+1,y,z-1
                        }

                        else if (dir==5 && z<maxSize)
                        {
                            j = i+stepz;
                            if (y>0) face.Weld( blocks[j-size], 0,  4,5,6, 6,5,4);		//x,y-1,z+1
                            if (x>0) face.Weld( blocks[j-1], 2,  2,3,4, 0,7,6);		//x-1,y,z+1
                            if (y<maxHeight) face.Weld( blocks[j+size], 1,  0,1,2, 6,5,4);//x,y+1,z+1
                            if (x<maxSize) face.Weld( blocks[j+1], 3,  6,7,0, 4,3,2);		//x+1,y,z+1
                        }

                        for (v=0;v<9;v++)
                        {
                            vert = face.verts[v];

                            //setting new vert
                            if (vert==null)
                            {
                                vert = new VoxelVert();
                                face.verts[v] = vert;
                            }

                            vert.pos = VoxelVert.posTable[ dir*9 + v ] + new Vector3(x,y,z);

                            vert.AddFace(face);
                        }

                        //face.LinkVerts();
                    }
            }
            #endregion

            #region Linking (adding verts neigs)
            for (f=0;f<faces.Count;f++) faces[f].LinkVerts();
            #endregion

            #region Lifting on BottomPoint
            for (f=0;f<faces.Count;f++)
            {
                face = faces[f];
                for (v=0;v<9;v++)
                    if (!face.verts[v].processed)
                {
                    face.verts[v].pos += new Vector3(0,bottomPoint,0);
                    face.verts[v].processed = true;
                }
            }

            for (f=0;f<faces.Count;f++) //clearing
                for (v=0;v<9;v++)
                    faces[f].verts[v].processed = false;
            #endregion

            #region Relaxing

            //setting vert relax
            for (f=0;f<faces.Count;f++)
            {

                for (v=0;v<9;v++)
                {
                    faces[f].verts[v].relax += faces[f].block.type.smooth;
                    faces[f].verts[v].relaxCount += 1;
                }
            }

            for (f=0;f<faces.Count;f++)
                for (v=0;v<9;v++)
                    if (faces[f].verts[v].relaxCount != 0)
            {
                faces[f].verts[v].relax = faces[f].verts[v].relax / faces[f].verts[v].relaxCount;
                faces[f].verts[v].relaxCount = 0;
            }

            //averaging corners
            for (f=0;f<faces.Count;f++)
            {
                face = faces[f];

                if (!face.verts[0].processed) { face.verts[0].pos += face.verts[0].GetRelax()*2; face.verts[0].processed=true; }
                if (!face.verts[2].processed) { face.verts[2].pos += face.verts[2].GetRelax()*2; face.verts[2].processed=true; }
                if (!face.verts[4].processed) { face.verts[4].pos += face.verts[4].GetRelax()*2; face.verts[4].processed=true; }
                if (!face.verts[6].processed) { face.verts[6].pos += face.verts[6].GetRelax()*2; face.verts[6].processed=true; }
            }

            //averaging mid verts
            for (f=0;f<faces.Count;f++)
            {
                face = faces[f];

                face.verts[1].pos = (face.verts[0].pos + face.verts[2].pos) * 0.5f;
                face.verts[3].pos = (face.verts[2].pos + face.verts[4].pos) * 0.5f;
                face.verts[5].pos = (face.verts[4].pos + face.verts[6].pos) * 0.5f;
                face.verts[7].pos = (face.verts[6].pos + face.verts[0].pos) * 0.5f;

                face.verts[8].pos = (face.verts[0].pos + face.verts[2].pos + face.verts[4].pos + face.verts[6].pos) * 0.25f;

                //returning processed flags
                face.verts[0].processed = false;
                face.verts[2].processed = false;
                face.verts[4].processed = false;
                face.verts[6].processed = false;
            }

            //seconary relax
            for (f=0;f<faces.Count;f++)
            {
                face = faces[f];

                for (v=0;v<9;v++)
                    if (!face.verts[v].processed)
                {
                    face.verts[v].relaxed = face.verts[v].GetRelax();
                    face.verts[v].processed = true;
                }
            }

            for (f=0;f<faces.Count;f++)
                for (v=0;v<9;v++)
                    faces[f].verts[v].processed = false;

            for (f=0;f<faces.Count;f++)
            {
                face = faces[f];

                for (v=0;v<9;v++)
                    if (!face.verts[v].processed)
                {
                    face.verts[v].pos += face.verts[v].relaxed;
                    face.verts[v].processed = true;
                }
            }
            #endregion

            #region Setting normals
            for (f=0;f<faces.Count;f++)
            {
                face = faces[f];

                face.verts[0].normal += Vector3.Cross(face.verts[1].pos-face.verts[0].pos, face.verts[7].pos-face.verts[0].pos).normalized;
                face.verts[2].normal += Vector3.Cross(face.verts[3].pos-face.verts[2].pos, face.verts[1].pos-face.verts[2].pos).normalized;
                face.verts[4].normal += Vector3.Cross(face.verts[5].pos-face.verts[4].pos, face.verts[3].pos-face.verts[4].pos).normalized;
                face.verts[6].normal += Vector3.Cross(face.verts[7].pos-face.verts[6].pos, face.verts[5].pos-face.verts[6].pos).normalized;

                face.verts[1].normal += Vector3.Cross(face.verts[8].pos-face.verts[1].pos, face.verts[0].pos-face.verts[1].pos).normalized +
                    Vector3.Cross(face.verts[2].pos-face.verts[1].pos, face.verts[8].pos-face.verts[1].pos).normalized;
                face.verts[3].normal += Vector3.Cross(face.verts[8].pos-face.verts[3].pos, face.verts[2].pos-face.verts[3].pos).normalized +
                    Vector3.Cross(face.verts[4].pos-face.verts[3].pos, face.verts[8].pos-face.verts[3].pos).normalized;
                face.verts[5].normal += Vector3.Cross(face.verts[8].pos-face.verts[5].pos, face.verts[4].pos-face.verts[5].pos).normalized +
                    Vector3.Cross(face.verts[6].pos-face.verts[5].pos, face.verts[8].pos-face.verts[5].pos).normalized;
                face.verts[7].normal += Vector3.Cross(face.verts[8].pos-face.verts[7].pos, face.verts[6].pos-face.verts[7].pos).normalized +
                    Vector3.Cross(face.verts[0].pos-face.verts[7].pos, face.verts[8].pos-face.verts[7].pos).normalized;

                face.verts[8].normal = Vector3.Cross(face.verts[1].pos-face.verts[5].pos, face.verts[3].pos-face.verts[7].pos).normalized;
            }

            if (land.normalsRandom > 0.01f)
            {
                for (x=0; x<size; x++)
                    for (z=0; z<size; z++)
                        for (y=0; y<shortHeight; y++)
                    {
                        i = z*shortHeight*size + y*size + x;

                        if (blocks[i]==null) continue;
                        if (!blocks[i].visible) continue;

                        Vector3 normalRandom = new Vector3(Random.value-0.5f, Random.value-0.5f, Random.value-0.5f)*1;

                        for (f=0;f<6;f++) if (blocks[i].faces[f]!=null && blocks[i].faces[f].visible)
                            for (v=0;v<9;v++) blocks[i].faces[f].verts[v].normal += normalRandom;
                    }
            }
            #endregion

            #region Set visible faces
            //visibleFaces.Clear();
            visibleFaces = new System.Collections.Generic.List<VoxelFace>();
            for (x=0; x<size; x++)
                for (z=0; z<size; z++)
                    for (y=0; y<shortHeight; y++)
                {
                    i = z*shortHeight*size + y*size + x;

                    if (blocks[i]==null) continue;
                    if (!blocks[i].visible) continue;
                    for (f=0;f<6;f++) if (blocks[i].faces[f]!=null && blocks[i].faces[f].visible)
                        visibleFaces.Add(blocks[i].faces[f]);
                }
            #endregion

            #region Set collider hierarchy
            boundsMin = new Vector2(offsetX + land.overlap, offsetZ + land.overlap);
            boundsMax = new Vector2(offsetX - land.overlap*2 + size, offsetZ - land.overlap*2 + size);
            boundsCenter = (boundsMin+boundsMax) / 2f;

            faceHolders = new FaceHolder[16];
            int facesPerHolder = Mathf.CeilToInt((size-land.overlap*2) / 4f);
            for (x=0; x<4; x++)
                for (z=0; z<4; z++)
            {
                faceHolders[z*4+x] = new FaceHolder();
                faceHolders[z*4+x].faces = new List<VoxelFace>();
                faceHolders[z*4+x].min = new Vector2(boundsMin.x + facesPerHolder*x, boundsMin.y + facesPerHolder*z);
                faceHolders[z*4+x].center = faceHolders[z*4+x].min + new Vector2(facesPerHolder/2f, facesPerHolder/2f);

                if (x==3) faceHolders[z*4+x].max = new Vector2(boundsMax.x, boundsMin.y + facesPerHolder*(z+1));
                else if (z==3) if (x==3) faceHolders[z*4+x].max = new Vector2(boundsMin.x + facesPerHolder*(x+1), boundsMax.y);
                else faceHolders[z*4+x].max = new Vector2(boundsMin.x + facesPerHolder*(x+1), boundsMin.y + facesPerHolder*(z+1));
            }

            for (f=0; f<visibleFaces.Count; f++)
            {
                face = visibleFaces[f];
                x = face.block.x / facesPerHolder;
                z = face.block.z / facesPerHolder;
                faceHolders[z*4+x].faces.Add(face);
            }
            #endregion

            terrainProgress = Progress.calculated;
        }
Esempio n. 23
0
 private float dist_between(VoxelBlock current, VoxelBlock neighbor)
 {
     return(1);
 }
Esempio n. 24
0
 protected abstract VoxelBlock <T> InitBlock(VoxelBlock <T> block);
Esempio n. 25
0
 protected override void CalculationSetup(VoxelBlock <Voxel> block)
 {
     dInput  = inputUpperBound - inputLowerBound;
     dOutput = outputUpperBound - outputLowerBound;
 }
Esempio n. 26
0
 private VoxelBlock getBelow(VoxelBlock block)
 {
     return(terrain.GetVoxelAt(terrain.GetPositionOf(block) + MathHelper.Down));
 }
    public IEnumerator <object> genericTest(Tests type, string name, int cpuLimit, int pmbLimit, Func <Vector3Int, int, int, int, float> voxelGenerator)
    {
        int CPU_LIMIT = cpuLimit;
        int PMB_LIMIT = pmbLimit;

        UnityEngine.Debug.Log("Starting Test " + name);
        perfData[(int)type] = new PerfData
        {
            testName = name,
            sizes    = new TestSize[testSizes.Length],
        };

        int limitCounter = 0;

        for (int i = 0; i < testSizes.Length; i++)
        {
            Vector3Int size = (Vector3Int)testSizes[i];
            UnityEngine.Debug.Log("size: " + size);
            perfData[(int)type].sizes[i] = new TestSize
            {
                sizeName     = string.Format("({0}, {1}, {2})", size.x, size.y, size.z),
                cpuTime      = new int[ROUNDS],
                pmbTime      = new int[ROUNDS],
                cpuTriangles = 0,
                pmbTriangles = 0,
            };


            float[] voxel;

            string path = Path.Combine(performanceDataDir, string.Format("{0}{1}.dat", name, perfData[(int)type].sizes[i].sizeName));
            if (File.Exists(path))
            {
                UnityEngine.Debug.Log("loading voxelData from file:");
                Stream          voxelStream  = File.OpenRead(path);
                BinaryFormatter deserializer = new BinaryFormatter();
                voxel = (float[])deserializer.Deserialize(voxelStream);
                voxelStream.Close();
            }
            else
            {
                UnityEngine.Debug.Log("recreating voxelData:");
                voxel = new float[size.x * size.y * size.z];
                for (int x = 0; x < size.x; x++)
                {
                    for (int y = 0; y < size.y; y++)
                    {
                        for (int z = 0; z < size.z; z++)
                        {
                            voxel[z * size.x * size.y + y * size.x + x] = voxelGenerator(size, x, y, z);
                        }
                    }
                }
                Stream          SaveFileStream = File.Create(path);
                BinaryFormatter serializer     = new BinaryFormatter();
                serializer.Serialize(SaveFileStream, voxel);
                SaveFileStream.Close();
            }

            UnityEngine.Debug.Log("executing Test:");

            for (int round = 0; round < ROUNDS; round++)
            {
                Stopwatch watch = Stopwatch.StartNew();

                if (limitCounter < CPU_LIMIT)
                {
                    List <Vector3> verts   = new List <Vector3>();
                    List <int>     indices = new List <int>();
                    List <Vector3> normals = new List <Vector3>();
                    marching.Generate(voxel, size.x, size.y, size.z, verts, indices, normals);

                    watch.Stop();

                    UnityEngine.Debug.LogFormat("\tCPU took {0}ms", watch.ElapsedMilliseconds);
                    perfData[(int)type].sizes[i].cpuTime[round] = (int)watch.ElapsedMilliseconds;
                    perfData[(int)type].sizes[i].cpuTriangles   = indices.Count / 3;
                }
                else
                {
                    UnityEngine.Debug.Log("\tCPU skipped");
                    perfData[(int)type].sizes[i].cpuTime[round] = -1;
                }

                if (limitCounter < PMB_LIMIT)
                {
                    VoxelBlock <Voxel> block = InitBlock(size);
                    UnityEngine.Debug.Log(voxel.Length + " " + voxel[0] + " " + voxel[1] + " " + voxel[2] + " " + voxel[3] + " " + voxel[4] + " " + voxel[5] + " " + voxel[6] + " " + voxel[7]);
                    helper.scheduleOnMainThread(() =>
                    {
                        watch = Stopwatch.StartNew();
                        pmb.ReInit(block);
                        RenderBuffers buffers = pmb.calculate(voxel, size.x, size.y, size.z, 0.5f);

                        int[] args = new int[4];
                        buffers.argsBuffer.GetData(args);
                        watch.Stop();

                        UnityEngine.Debug.LogFormat("\tPMB took {0}ms", watch.ElapsedMilliseconds);
                        perfData[(int)type].sizes[i].pmbTime[round] = (int)watch.ElapsedMilliseconds;
                        perfData[(int)type].sizes[i].pmbTriangles   = args[0] / 3;

                        buffers.vertexBuffer.Dispose();
                        buffers.indexBuffer.Dispose();
                        buffers.normalBuffer.Dispose();
                        buffers.argsBuffer.Dispose();

                        UnityEngine.Debug.Log("PMB triags inside thread: " + perfData[(int)type].sizes[i].pmbTriangles);
                    }).wait();
                    UnityEngine.Debug.Log("PMB triags after thread: " + perfData[(int)type].sizes[i].pmbTriangles);
                }
                else
                {
                    UnityEngine.Debug.Log("\tPMB skipped");
                    perfData[(int)type].sizes[i].pmbTime[round] = -1;
                    watch.Stop();
                }

                yield return(null);
            }
            limitCounter++;
        }
    }
Esempio n. 28
0
    public override bool Calculate()
    {
        VoxelBlock <T> block = input.GetValue <VoxelBlock <T> >();

        if (block == null || block.Layers == null)
        {
            return(false);
        }

        CalculationSetup(block);

        Vector3Int voxelCount = block.VoxelCount;

        bool success = true;

        for (int x = 0; x < voxelCount.x && success; x++)
        {
            for (int z = 0; z < voxelCount.z; z++)
            {
                float height;

                if (!CalculateHeight(out height, x - block.Overlap, z - block.Overlap))
                {
                    success = false;
                    break;
                }

                for (int y = -block.Overlap; y < voxelCount.y - block.Overlap; y++)
                {
                    float voxelHeight = y / (float)block.Height;

                    if (height > voxelHeight)
                    {
                        float nextVoxelHeight = (y + 1) / (float)block.Height;
                        if (height >= nextVoxelHeight)
                        {
                            block[x - block.Overlap, y, z - block.Overlap].Data = 1.0f;
                        }
                        else
                        {
                            block[x - block.Overlap, y, z - block.Overlap].Data = (height - voxelHeight) * (float)block.Height;
                        }
                    }
                    else
                    {
                        block[x - block.Overlap, y, z - block.Overlap].Data = 0.0f;
                    }
                }
            }
        }

        if (!success)
        {
            CalculationTeardown();
            return(false);
        }

        CalculationTeardown();
        output.SetValue(block);

        return(true);
    }
Esempio n. 29
0
    public override bool Calculate()
    {
        Meshes = new List <GameObject>();
        VoxelBlock <Voxel> block = input.GetValue <VoxelBlock <Voxel> >();

        Marching marching = null;

        if (mode == MarchingMode.Tetrahedron)
        {
            marching = new MarchingTertrahedron();
        }
        else
        {
            marching = new MarchingCubes();
        }

        //Surface is the value that represents the surface of mesh
        //For example the perlin noise has a range of -1 to 1 so the mid point is where we want the surface to cut through.
        //The target value does not have to be the mid point it can be any value with in the range.
        //
        //This should be accesible by an input
        marching.Surface = 0.5f;

        //The size of voxel array.
        int width  = block.Width;
        int height = block.Height;
        int length = block.Length;

        float[] voxels = new float[width * height * length];

        for (int y = 0; y < height; y++)
        {
            Voxel[,] voxelLayer = block.Layers[y].Layer;
            for (int x = 0; x < width; x++)
            {
                for (int z = 0; z < length; z++)
                {
                    int idx = x + y * width + z * width * height;
                    voxels[idx] = voxelLayer[x, z].GetValue();
                }
            }
        }

        List <Vector3> verts   = new List <Vector3>();
        List <int>     indices = new List <int>();

        //The mesh produced is not optimal. There is one vert for each index.
        //Would need to weld vertices for better quality mesh.
        marching.Generate(voxels, width, height, length, verts, indices);

        int generatedVerts   = verts.Count;
        int generatedIndices = indices.Count;

        weldVertices(verts, indices);
        Debug.Log("Vertex Welding: " + generatedVerts + "=>" + verts.Count);
        Debug.Log("Vertex Welding indices: " + generatedIndices + "=>" + indices.Count);
        Debug.LogError("Out of Bounds: " + indices.Find(i => i >= verts.Count));

        //A mesh in unity can only be made up of 65000 verts.
        //Need to split the verts between multiple meshes.

        int maxVertsPerMesh = 30000;   //must be divisible by 3, ie 3 verts == 1 triangle
        int numMeshes       = verts.Count / maxVertsPerMesh + 1;

        for (int i = 0; i < numMeshes; i++)
        {
            List <Vector3> splitVerts   = new List <Vector3>();
            List <int>     splitIndices = new List <int>();

            for (int j = 0; j < maxVertsPerMesh; j++)
            {
                int idx = i * maxVertsPerMesh + j;

                if (idx < verts.Count)
                {
                    splitVerts.Add(verts[idx]);
                    splitIndices.Add(j);
                }
            }

            if (splitVerts.Count == 0)
            {
                continue;
            }
            splitVerts   = verts;
            splitIndices = indices;

            Mesh mesh = new Mesh();
            mesh.SetVertices(splitVerts);
            mesh.SetTriangles(splitIndices, 0);
            mesh.RecalculateBounds();
            mesh.RecalculateNormals();

            GameObject go = new GameObject("Mesh");
            // go.transform.parent = transform;
            go.AddComponent <MeshFilter>();
            go.AddComponent <MeshRenderer>();
            // go.GetComponent<Renderer>().material = m_material;
            go.GetComponent <MeshFilter>().mesh = mesh;
            go.transform.localPosition          = new Vector3(-width / 2, -height / 2, -length / 2);
            go.transform.localScale             = new Vector3(1.0f, 1.0f, 1.0f);

            Meshes.Add(go);
        }
        VertexDisplay.RenderNewMeshes(Meshes);
        return(true);
    }
Esempio n. 30
0
    public override bool Calculate()
    {
        bool isPMB = false;

        if (!input.connected())
        {
            return(false);
        }
        VoxelBlock <Voxel> block = input.GetValue <VoxelBlock <Voxel> >();

        if (surfaceConnection.connected())
        {
            surface = surfaceConnection.GetValue <float>();
        }

        Marching marching = null;

        switch (mode)
        {
        case VerteGenerationMode.Tetrahedron:
            marching = new MarchingTertrahedron();
            break;

        case VerteGenerationMode.Cubes:
            marching = new MarchingCubes();
            break;

        case VerteGenerationMode.Voxel:
            marching = new VoxelGeneration();
            break;

        case VerteGenerationMode.PMB:
            isPMB = true;
            break;
        }

        //The size of voxel array.
        Vector3Int count  = block.VoxelCount;
        int        width  = count.x;
        int        height = count.y;
        int        length = count.z;

        float[] voxels = new float[width * height * length];

        for (int y = 0; y < height; y++)
        {
            Voxel[,] voxelLayer = block.Layers[y].Layer;
            for (int x = 0; x < width; x++)
            {
                for (int z = 0; z < length; z++)
                {
                    int idx = x + y * width + z * width * height;
                    voxels[idx] = voxelLayer[x, z].GetValue();
                }
            }
        }

        if (isPMB)
        {
            var pmbTask = MainThreadHelper.instance().scheduleOnMainThread(() =>
            {
                pmb.ReInit(block);
                Stopwatch pmbWatch = Stopwatch.StartNew();
                buffers            = pmb.calculate(voxels, width, height, length, surface);
                pmbWatch.Stop();
                UnityEngine.Debug.LogFormat("PMB took {0}ms\n\t{1} voxels\n\t{2} triangles", pmbWatch.ElapsedMilliseconds, voxels.Count(), buffers.indexBuffer.count / 3);
            });

            pmbTask.wait();

            if (!pmbTask.completed)
            {
                return(false);
            }

            Block = block;
            return(true);
        }

        //Surface is the value that represents the surface of mesh
        //For example the perlin noise has a range of -1 to 1 so the mid point is where we want the surface to cut through.
        //The target value does not have to be the mid point it can be any value with in the range.
        //
        //This should be accesible by an input
        marching.Surface = surface;

        List <Vector3> verts   = new List <Vector3>();
        List <int>     indices = new List <int>();
        List <Vector3> normals = new List <Vector3>();

        Stopwatch sw = Stopwatch.StartNew();

        marching.Generate(voxels, width, height, length, verts, indices, normals);

        sw.Stop();

        UnityEngine.Debug.LogFormat("Marching took {0}ms\n\t{1} vertices; {2} triangles", sw.ElapsedMilliseconds, verts.Count(), indices.Count() / 3);

        sw.Restart();
        weldVertices(verts, indices, normals);
        sw.Stop();

        UnityEngine.Debug.LogFormat("Vertex welding took {0}ms\n\t {1} vertices left", sw.ElapsedMilliseconds, verts.Count());

        var task = MainThreadHelper.instance().scheduleOnMainThread(() =>
        {
            buffers = new RenderBuffers {
                vertexBuffer = new ComputeBuffer(verts.Count, sizeof(float) * 3),
                indexBuffer  = new ComputeBuffer(indices.Count, sizeof(int)),
                normalBuffer = new ComputeBuffer(normals.Count, sizeof(float) * 3),
                argsBuffer   = new ComputeBuffer(4, sizeof(int), ComputeBufferType.IndirectArguments),
            };

            buffers.vertexBuffer.SetData(verts);
            buffers.indexBuffer.SetData(indices);
            buffers.normalBuffer.SetData(normals);
            buffers.argsBuffer.SetData(new int[] { indices.Count, 1, 0, 0 });
        });

        task.wait();

        if (!task.completed)
        {
            return(false);
        }

        Block = block;

        return(true);
    }