public void SmoothBlocks() { // *This is not completely deterministic - the order in which chunks are processed could impact the final terrain in some cases if (this.composition != Composition.MIX) { return; } // Remove unwanted blocks from surface for (int x = 0; x < World.chunkSize; x++) { for (int z = 0; z < World.chunkSize; z++) { int y = column.heightMap[x, z] - (int)this.position.y; if (y > World.chunkSize - 1 || y < 0) { continue; } Blocks.Types type = blockTypes[x, y, z]; if (Blocks.smoothSurface[(int)type]) { blockBytes[x, y, z] = GetBitMask(new Vector3(x, y, z)); //, true, type); Shapes.RemoveBlocks(this, x, y, z); } } } // Assign shapes to smooth terrain for (int x = 0; x < World.chunkSize; x++) { for (int z = 0; z < World.chunkSize; z++) { int height = column.heightMap[x, z] - (int)this.position.y; Shapes.Types previousShape = 0; int previousY = 0; for (int y = height; y > height - 2; y--) { if (y > World.chunkSize - 1 || y < 0) { continue; } Blocks.Types type = blockTypes[x, y, z]; Vector3 blockPosition = new Vector3(x, y, z); if (Blocks.smoothSurface[(int)type]) { blockBytes[x, y, z] = GetBitMask(blockPosition); Shapes.SetSlopes(this, x, y, z); } // Avoid overhangs on steep slopes - does not handle iterating between two chunks if (previousShape == Shapes.Types.CORNEROUT && (blockShapes[x, y, z] == Shapes.Types.CORNEROUT || blockShapes[x, y, z] == Shapes.Types.WEDGE)) { blockShapes[x, y + 1, z] = Shapes.Types.CORNEROUT2; blockShapes[x, y, z] = Shapes.Types.CUBE; } else if (previousShape == Shapes.Types.WEDGE) { blockShapes[x, y, z] = Shapes.Types.CUBE; } previousShape = blockShapes[x, y, z]; previousY = y; } } } }
public void Draw(bool redraw = false) { //bool debugging = false; if (status == Status.DRAWN && !redraw || composition == Composition.EMPTY) { return; } Vector3[] offsets = Util.CubeFaceDirections(); int solidAdjacentChunkCount = 0; for (int i = 0; i < 6; i++) { Vector3 adjacentPosition = this.position + (offsets[i] * World.chunkSize); //World.debug.OutlineChunk(adjacentPosition, Color.green, sizeDivision: 3.5f); Chunk adjacentChunk = World.chunks[adjacentPosition]; if (adjacentChunk.composition == Chunk.Composition.SOLID) { solidAdjacentChunkCount++; } if (solidAdjacentChunkCount == 6) { return; } } world.chunksDrawn++; World.debug.Output("Chunks drawn", world.chunksDrawn.ToString()); List <Vector3> verts = new List <Vector3>(); List <Vector3> norms = new List <Vector3>(); List <int> tris = new List <int>(); List <Vector2> UVs = new List <Vector2>(); List <Color> cols = new List <Color>(); // Vertex count for offsetting triangle indices int vertexCount = 0; int exposedBlockCount = 0; // Generate mesh data for (int x = 0; x < World.chunkSize; x++) { for (int z = 0; z < World.chunkSize; z++) { for (int y = 0; y < World.chunkSize; y++) { // Check block type, skip drawing if air Blocks.Types type = blockTypes[x, y, z]; if (type == Blocks.Types.AIR) { continue; } if (composition == Composition.SOLID && (Util.InChunk(x, 1) && Util.InChunk(y, 1) && Util.InChunk(z, 1))) { continue; } Vector3 blockPosition = new Vector3(x, y, z); Shapes.Types shape = blockShapes[x, y, z]; // Check if adjacent blocks are exposed bool[] exposedFaces = new bool[6]; bool blockExposed = false; for (int e = 0; e < 6; e++) { exposedFaces[e] = FaceExposed(offsets[e], blockPosition); if (exposedFaces[e] && !blockExposed) { blockExposed = true; } } if (blockExposed) { exposedBlockCount++; } // Block is not visible so nothing to draw if (!blockExposed && blockBytes[x, y, z] == 0) { continue; } // Check block shapes and generate mesh data int localVertCount = 0; localVertCount = shapes[(int)blockShapes[x, y, z]].Draw(verts, norms, tris, UVs, blockPosition, blockYRotation[x, y, z], exposedFaces, vertexCount, (int)type); // Keep count of vertices to offset triangles vertexCount += localVertCount; Color color = (Color)Blocks.colors[(int)blockTypes[x, y, z]]; /*if(column.POIWalls != null && column.POIWalls[x,z] == 1) color = Color.black; * else if(column.POIWalls != null && column.POIWalls[x,z] == 2) color = Color.red; * else if(column.POIWalls != null && column.POIWalls[x,z] == 3) color = Color.green; * /*else if(column.POIHeightGradient != null) * { * float colVal = ((float)column.POIHeightGradient[x,z])/10; * if(colVal == 0) colVal = 0.05f; * color = new Color(colVal,colVal,colVal); * }*/ cols.AddRange(Enumerable.Repeat(color, localVertCount)); } } } CreateMesh(verts, norms, tris, UVs, cols); status = Status.DRAWN; }
// Change type of block at voxel and reload chunk(s) public bool ChangeBlock(Vector3 voxel, Blocks.Types type, Shapes.Types shape = Shapes.Types.CUBE) { // Find owner chunk Chunk chunk; if (!chunks.TryGetValue(VoxelOwner(voxel), out chunk)) { Debug.Log("can't find chunk at " + VoxelOwner(voxel)); return(false); } Column columnTopology = columns[new Vector3(chunk.position.x, 0, chunk.position.z)]; // Check highest/lowest blocks in column if (type == Blocks.Types.AIR) { if (voxel.y < columnTopology.lowestPoint) { columnTopology.lowestPoint = (int)voxel.y; } if (chunk.composition == Chunk.Composition.SOLID) { chunk.composition = Chunk.Composition.MIX; } } else { if (voxel.y > columnTopology.highestPoint) { columnTopology.highestPoint = (int)voxel.y; } if (chunk.composition == Chunk.Composition.EMPTY) { chunk.composition = Chunk.Composition.MIX; } } // Change block type Vector3 local = voxel - chunk.position; chunk.blockTypes[(int)local.x, (int)local.y, (int)local.z] = type; chunk.blockShapes[(int)local.x, (int)local.y, (int)local.z] = shape; List <Vector3> adjacent = new List <Vector3>(); // If the block is at edge(s) get it's adjacent chunk(s) if (local.x == 0) { adjacent.Add((new Vector3(chunk.position.x - chunkSize, chunk.position.y, chunk.position.z))); } if (local.x == chunkSize - 1) { adjacent.Add((new Vector3(chunk.position.x + chunkSize, chunk.position.y, chunk.position.z))); } if (local.y == 0) { adjacent.Add((new Vector3(chunk.position.x, chunk.position.y - chunkSize, chunk.position.z))); } if (local.y == chunkSize - 1) { adjacent.Add((new Vector3(chunk.position.x, chunk.position.y + chunkSize, chunk.position.z))); } if (local.z == 0) { adjacent.Add((new Vector3(chunk.position.x, chunk.position.y, chunk.position.z - chunkSize))); } if (local.z == chunkSize - 1) { adjacent.Add((new Vector3(chunk.position.x, chunk.position.y, chunk.position.z + chunkSize))); } if (local.x == 0 && local.z == 0) { adjacent.Add((new Vector3(chunk.position.x - chunkSize, chunk.position.y, chunk.position.z - chunkSize))); } if (local.x == chunkSize - 1 && local.z == chunkSize - 1) { adjacent.Add((new Vector3(chunk.position.x + chunkSize, chunk.position.y, chunk.position.z + chunkSize))); } if (local.x == 0 && local.z == chunkSize - 1) { adjacent.Add((new Vector3(chunk.position.x - chunkSize, chunk.position.y, chunk.position.z + chunkSize))); } if (local.x == chunkSize - 1 && local.z == 0) { adjacent.Add((new Vector3(chunk.position.x + chunkSize, chunk.position.y, chunk.position.z - chunkSize))); } // Update adjacent foreach (Vector3 chunkPosition in adjacent) { Chunk updateChunk = World.chunks[chunkPosition]; UpdateChunk(chunkPosition); } // Update target UpdateChunk(chunk.position); return(true); }