public static void Generate <T>(BlockContainer blocks, Func <int[], int[], int[], int, bool, VoxelFace, bool, IEnumerable <T> > createQuad,
                                        out T[] vertices, out int[] indices, bool cw = false) where T : IVertexType
        {
            try
            {
                var verts = new List <T>();
                var inds  = new List <int>();

                int[] size = { blocks.SizeX(), blocks.SizeY(), blocks.SizeZ() };
                // loop over the three directions; x -> 0, y -> 1, z -> 2
                for (var direction = 0; direction < 3; direction++)
                {
                    // u and v are the other two directions
                    var u = (direction + 1) % 3;
                    var v = (direction + 2) % 3;

                    // pos holds the current position in the grid
                    var pos = new int[3];
                    // 1 for the current direction and 0 for others, unit vector of the axis we're handling
                    var nextPos = new int[3];
                    // contains the rendering data for each face in the current layers, a layer being a slice of the grid; Note that this is linearized
                    var backFaces  = new VoxelFace[blocks.GetBlockContainerSize(u) * blocks.GetBlockContainerSize(v)];
                    var frontFaces = new VoxelFace[blocks.GetBlockContainerSize(u) * blocks.GetBlockContainerSize(v)];

                    nextPos[direction] = 1;

                    // outer loop goes through all layers
                    // we start at -1 because we check for faces *between* blocks and have to get the outer faces too
                    for (pos[direction] = -1; pos[direction] < blocks.GetBlockContainerSize(direction); pos[direction]++)
                    {
                        var noBack  = true;
                        var noFront = true;
                        // Get all faces that need to be rendered in the current layer (front and back seperately)
                        for (pos[v] = 0; pos[v] < size[v]; pos[v]++)
                        {
                            for (pos[u] = 0; pos[u] < size[u]; pos[u]++)
                            {
                                // if this block is visible and the one behind it is not we need to render the backface of the current block
                                // if this one is not visible but the one behind it is, we need to render the frontface of the 'behind' block
                                var index   = pos[v] * size[u] + pos[u];
                                var current = pos[direction] >= 0 && !blocks[(byte)pos[0], (byte)pos[1], (byte)pos[2]].IsEmpty();
                                var behind  = pos[direction] + 1 < blocks.GetBlockContainerSize(direction) &&
                                              !blocks[(byte)(pos[0] + nextPos[0]), (byte)(pos[1] + nextPos[1]), (byte)(pos[2] + nextPos[2])].IsEmpty();

                                if (current && !behind)
                                {
                                    backFaces[index] = new VoxelFace(blocks[(byte)pos[0], (byte)pos[1], (byte)pos[2]]);
                                    noBack           = false;
                                }
                                else if (!current && behind)
                                {
                                    frontFaces[index] = new VoxelFace(blocks[(byte)(pos[0] + nextPos[0]), (byte)(pos[1] + nextPos[1]), (byte)(pos[2] + nextPos[2])]);
                                    noFront           = false;
                                }
                            }
                        }

                        // Then process both layers to build quads
                        if (!noFront)
                        {
                            ProcessLayer(frontFaces, createQuad, verts, inds, pos[direction] + 1, direction, size, cw, false);
                        }
                        if (!noBack)
                        {
                            ProcessLayer(backFaces, createQuad, verts, inds, pos[direction] + 1, direction, size, !cw, true);
                        }
                    }
                }

                vertices = verts.ToArray();
                indices  = inds.ToArray();
            }
            catch (Exception e)
            {
                throw new Exception("Generate GreedyMesh failed!\r\n " + e.ToString());
            }
        }
        private IEnumerable <VertexWithIndexNormal> CreateQuad(int[] p, int[] du, int[] dv,
                                                               int normal, bool normalPos, VoxelFace voxelFace, bool backFace)
        {
            // 法线垂直于宽高面
            var norm = DirectionToFace(normal, normalPos);

            return(new[]
            {
                new VertexWithIndexNormal((byte)p[0], (byte)p[1], (byte)p[2], voxelFace.Index, norm),
                new VertexWithIndexNormal((byte)(p[0] + du[0]), (byte)(p[1] + du[1]), (byte)(p[2] + du[2]), voxelFace.Index, norm),
                new VertexWithIndexNormal((byte)(p[0] + du[0] + dv[0]), (byte)(p[1] + du[1] + dv[1]), (byte)(p[2] + du[2] + dv[2]), voxelFace.Index, norm),
                new VertexWithIndexNormal((byte)(p[0] + dv[0]), (byte)(p[1] + dv[1]), (byte)(p[2] + dv[2]), voxelFace.Index, norm),
            });
        }