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), }); }