public GeneratedChunk(Chunk chunk, ThreeDimensionalBlockArray blocks, Vector3[] vertices, Vector2[] uvs, int[] triangles) { this.chunk = chunk; this.blocks = blocks; this.vertices = vertices; this.uvs = uvs; this.triangles = triangles; }
void GenerateMeshThreaded(ThreeDimensionalBlockArray Blocks, Chunk chunk) { var refreshed = GenerateMesh(Blocks, chunk); refreshed.ApplyBlocks = false; generatedChunks.Enqueue(refreshed); }
int GetHeight(ThreeDimensionalBlockArray Blocks, int x, int z) { for (int y = (int)size.y - 1; y >= 0; y--) { if (Blocks[x, y, z].BlockID != BlockType.Air) { return(y); } } return(0); }
bool BlockExists(int x, int y, int z, BlockFace blockFace, ThreeDimensionalBlockArray currentBlocks, ThreeDimensionalBlockArray neighourBlocks) { if (neighourBlocks != null) { //Debug.Log("Neighbour is not null"); // if at the edge of the array, we need to check neighbours if (x == 0 || x >= ((int)Chunk.ChunkSize.x - 1) || z == 0 || z >= ((int)Chunk.ChunkSize.z - 1)) { switch (blockFace) { case BlockFace.Top: case BlockFace.Bottom: break; case BlockFace.Left: if (x != 0) { break; } return(neighourBlocks.BlockExists((int)Chunk.ChunkSize.x, y, z)); case BlockFace.Right: if (x != (int)Chunk.ChunkSize.x - 1) { break; } return(neighourBlocks.BlockExists(0, y, z)); case BlockFace.Forward: if (z != (int)Chunk.ChunkSize.z - 1) { break; } return(neighourBlocks.BlockExists(x, y, 0)); case BlockFace.Back: if (z != 0) { break; } return(neighourBlocks.BlockExists(x, y, (int)Chunk.ChunkSize.z - 1)); } } } return(currentBlocks.BlockExists(x, y, z, blockFace)); }
void FillArea(ThreeDimensionalBlockArray Blocks, int xStart, int yStart, int zStart, int xEnd, int yEnd, int zEnd, BlockType blockType) { for (int y = yStart; y <= yEnd; y++) { for (int x = xStart; x <= xEnd; x++) { for (int z = zStart; z <= zEnd; z++) { if (Blocks.ElementExists(x, y, z)) { Block block = Blocks.Get(x, y, z); if (block.BlockID == BlockType.Air) { block.BlockID = blockType; } } } } } }
void GenerateTree(ThreeDimensionalBlockArray Blocks, Vector3 pos, TreeType treeType, System.Random random) { //System.Random random = new System.Random(); int yStart = (int)pos.y + 1; int yEnd = yStart + random.Next(3, 7); int y = yStart; for (; y < yEnd; y++) { Blocks[(int)pos.x, y, (int)pos.z].BlockID = BlockType.OakLog; } Blocks[(int)pos.x, y, (int)pos.z].BlockID = BlockType.OakLeaf; // one leaf forward, back, left and right from the top leaf Vector3 current = new Vector3(pos.x, y, pos.z); Vector3 forward, back, left, right; forward = current + Vector3.forward; back = current + Vector3.back; left = current + Vector3.left; right = current + Vector3.right; if (Blocks.ElementExists(forward)) { if (Blocks.Get(forward).BlockID == BlockType.Air) { Blocks.Get(forward).BlockID = BlockType.OakLeaf; } } if (Blocks.ElementExists(back)) { if (Blocks.Get(back).BlockID == BlockType.Air) { Blocks.Get(back).BlockID = BlockType.OakLeaf; } } if (Blocks.ElementExists(left)) { if (Blocks.Get(left).BlockID == BlockType.Air) { Blocks.Get(left).BlockID = BlockType.OakLeaf; } } if (Blocks.ElementExists(right)) { if (Blocks.Get(right).BlockID == BlockType.Air) { Blocks.Get(right).BlockID = BlockType.OakLeaf; } } // one layer down, an entire ring current = new Vector3(pos.x, y - 1, pos.z); // 3x1x3 ring FillArea(Blocks, (int)current.x - 1, (int)current.y, (int)current.z - 1, (int)current.x + 1, (int)current.y, (int)current.z + 1, BlockType.OakLeaf); // 5x2x5 ring FillArea(Blocks, (int)current.x - 2, (int)current.y - 2, (int)current.z - 2, (int)current.x + 2, (int)current.y - 1, (int)current.z + 2, BlockType.OakLeaf); }
GeneratedChunk GenerateMesh(ThreeDimensionalBlockArray Blocks, Chunk chunk) { List <Vector3> vertices = new List <Vector3>(); List <Vector2> uvs = new List <Vector2>(); List <int> triangles = new List <int>(); int VerticesIndex; float blockSize = 1; ThreeDimensionalBlockArray leftBlocks, rightBlocks, backBlocks, frontBlocks; leftBlocks = rightBlocks = backBlocks = frontBlocks = null; ChunkIndex chunkIndex = chunk.ChunkIndex; ChunkIndex leftIndex, rightIndex, backIndex, frontIndex; leftIndex = new ChunkIndex(chunkIndex.ChunkX - 1, chunkIndex.ChunkZ); rightIndex = new ChunkIndex(chunkIndex.ChunkX + 1, chunkIndex.ChunkZ); backIndex = new ChunkIndex(chunkIndex.ChunkX, chunkIndex.ChunkZ - 1); frontIndex = new ChunkIndex(chunkIndex.ChunkX, chunkIndex.ChunkZ + 1); lock (Chunk.WorldChunks) { if (Chunk.WorldChunks.TryGetValue(leftIndex, out Chunk left)) { leftBlocks = left.ChunkBlocks; } if (Chunk.WorldChunks.TryGetValue(rightIndex, out Chunk right)) { rightBlocks = right.ChunkBlocks; } if (Chunk.WorldChunks.TryGetValue(backIndex, out Chunk back)) { backBlocks = back.ChunkBlocks; } if (Chunk.WorldChunks.TryGetValue(frontIndex, out Chunk front)) { frontBlocks = front.ChunkBlocks; } } for (int y = 0; y < size.y; y++) { for (int x = 0; x < size.x; x++) { for (int z = 0; z < size.z; z++) { if (Blocks[x, y, z].BlockID != BlockType.Air) { BlockType blockType = Blocks[x, y, z].BlockID; BlockFaceDirection direction = BlockFaceDirection.Side; if (!BlockExists(x, y, z, BlockFace.Top, Blocks, null)) { direction = BlockFaceDirection.Top; VerticesIndex = vertices.Count; vertices.Add(new Vector3(x, y + blockSize, z)); vertices.Add(new Vector3(x, y + blockSize, z + blockSize)); vertices.Add(new Vector3(x + blockSize, y + blockSize, z + blockSize)); vertices.Add(new Vector3(x + blockSize, y + blockSize, z)); UpdateChunkUV(blockType, direction); } if (!BlockExists(x, y, z, BlockFace.Bottom, Blocks, null)) { if (y == 0) { continue; } direction = BlockFaceDirection.Bottom; VerticesIndex = vertices.Count; vertices.Add(new Vector3(x, y, z)); vertices.Add(new Vector3(x + blockSize, y, z)); vertices.Add(new Vector3(x + blockSize, y, z + blockSize)); vertices.Add(new Vector3(x, y, z + blockSize)); UpdateChunkUV(blockType, direction); } if (!BlockExists(x, y, z, BlockFace.Left, Blocks, leftBlocks)) { direction = BlockFaceDirection.Side; VerticesIndex = vertices.Count; vertices.Add(new Vector3(x, y, z + blockSize)); vertices.Add(new Vector3(x, y + blockSize, z + blockSize)); vertices.Add(new Vector3(x, y + blockSize, z)); vertices.Add(new Vector3(x, y, z)); UpdateChunkUV(blockType, direction); } if (!BlockExists(x, y, z, BlockFace.Right, Blocks, rightBlocks)) { direction = BlockFaceDirection.Side; VerticesIndex = vertices.Count; vertices.Add(new Vector3(x + blockSize, y, z)); vertices.Add(new Vector3(x + blockSize, y + blockSize, z)); vertices.Add(new Vector3(x + blockSize, y + blockSize, z + blockSize)); vertices.Add(new Vector3(x + blockSize, y, z + blockSize)); UpdateChunkUV(blockType, direction); } if (!BlockExists(x, y, z, BlockFace.Back, Blocks, backBlocks)) { direction = BlockFaceDirection.Side; VerticesIndex = vertices.Count; vertices.Add(new Vector3(x, y, z)); vertices.Add(new Vector3(x, y + blockSize, z)); vertices.Add(new Vector3(x + blockSize, y + blockSize, z)); vertices.Add(new Vector3(x + blockSize, y, z)); UpdateChunkUV(blockType, direction); } if (!BlockExists(x, y, z, BlockFace.Forward, Blocks, frontBlocks)) { direction = BlockFaceDirection.Side; VerticesIndex = vertices.Count; vertices.Add(new Vector3(x + blockSize, y, z + blockSize)); vertices.Add(new Vector3(x + blockSize, y + blockSize, z + blockSize)); vertices.Add(new Vector3(x, y + blockSize, z + blockSize)); vertices.Add(new Vector3(x, y, z + blockSize)); UpdateChunkUV(blockType, direction); } } } } } return(new GeneratedChunk(chunk, Blocks, vertices.ToArray(), uvs.ToArray(), triangles.ToArray())); void UpdateChunkUV(BlockType blockType, BlockFaceDirection direction) { triangles.Add(VerticesIndex); triangles.Add(VerticesIndex + 1); triangles.Add(VerticesIndex + 2); triangles.Add(VerticesIndex + 2); triangles.Add(VerticesIndex + 3); triangles.Add(VerticesIndex); Vector2 textureInterval = TextureManager.TextureInterval; int textureIndex = 0; switch (direction) { case BlockFaceDirection.Top: textureIndex = TextureManager.TextureMap[blockType].TopIndex; break; case BlockFaceDirection.Side: textureIndex = TextureManager.TextureMap[blockType].SideIndex; break; case BlockFaceDirection.Bottom: textureIndex = TextureManager.TextureMap[blockType].BottomIndex; break; } Vector2 textureId = new Vector2(textureInterval.x * (textureIndex % TextureManager.AtlasSize.x), textureInterval.y * Mathf.FloorToInt(textureIndex / TextureManager.AtlasSize.y)); uvs.Add(new Vector2(textureId.x + textureInterval.x, textureId.y - textureInterval.y)); uvs.Add(new Vector2(textureId.x + textureInterval.x, textureId.y)); uvs.Add(new Vector2(textureId.x, textureId.y)); uvs.Add(new Vector2(textureId.x, textureId.y - textureInterval.y)); } }
/// <summary> /// General method that returns a completed chunk /// </summary> /// <returns>The chunk.</returns> /// <param name="chunk">Chunk.</param> /// <param name="chunkIndex">Chunk index.</param> /// <param name="noiseSettings">Noise settings.</param> GeneratedChunk GenerateChunk(Chunk chunk, ChunkIndex chunkIndex, NoiseSettings noiseSettings, bool perlin) { // Create our blocks. This is not the mesh ThreeDimensionalBlockArray Blocks = new ThreeDimensionalBlockArray((int)size.x, (int)size.y, (int)size.z); // Heightmap float[,] noiseMap = null; if (perlin) { noiseMap = NoiseGenerator.Generate2D(chunkIndex.ChunkX, chunkIndex.ChunkZ, (int)size.x, (int)size.z, noiseSettings.Octaves, noiseSettings.Amplitude, noiseSettings.Smoothness, noiseSettings.GroundHeight, noiseSettings.Roughness); } else { noiseMap = NoiseGenerator.Generate2DSimplex(chunkIndex.ChunkX, chunkIndex.ChunkZ, (int)size.x, (int)size.z, noiseSettings.Octaves, noiseSettings.Amplitude, noiseSettings.Smoothness, noiseSettings.GroundHeight, noiseSettings.Roughness); } List <Vector3> trees = new List <Vector3>(); // can't use unity due to threading System.Random random = new System.Random(); for (int x = 0; x < size.x; x++) { for (int z = 0; z < size.z; z++) { int h = Mathf.RoundToInt(noiseMap[x, z]); for (int y = 0; y < size.y; y++) { BlockType blockType = BlockType.Air; if (y < h) { // Top block if (y + 1 == h) { // TODO: Get top block blockType = BlockType.Grass; if (random.Next(0, 100 - noiseSettings.TreeFrequency) == 5) { trees.Add(new Vector3(x, y, z)); } //if ((0, noiseSettings.TreeFrequency + 1) == 5) //{ // trees.Add(new Vector3(x, y, z)); //} } // Dirt else if (y + 1 > h - 3) { blockType = BlockType.Dirt; } // Below else { blockType = BlockType.Stone; } } Blocks[x, y, z] = new Block(x, y, z, blockType); } } } //foreach (Vector3 pos in trees) //{ // GenerateTree(pos, TreeType.Oak); //} return(GenerateMesh(Blocks, chunk)); }
GeneratedChunk GenerateNew(Chunk chunk, ChunkIndex chunkIndex, NoiseSettings noiseSettings) { System.Random random = new System.Random(); ThreeDimensionalBlockArray Blocks = new ThreeDimensionalBlockArray((int)size.x, (int)size.y, (int)size.z); noiseSettings.SetWeights(); // Loop through all blocks and get solid or air value for (int x = 0; x < size.x; x++) { for (int y = 0; y < size.y; y++) { for (int z = 0; z < size.z; z++) { if (y == 0 || y == 1 || y == 2) { Blocks[x, y, z] = new Block(x, y, z, BlockType.Stone); continue; } float groundNoise = 0; float caveNoise1 = 0; float caveNoise2 = 0; caveNoise1 = NoiseGenerator.GetPixelRidged(chunkIndex, x, y, z, noiseSettings.CaveOne); groundNoise = NoiseGenerator.GetPixel(chunk.ChunkIndex, x, y, z, noiseSettings); caveNoise2 = NoiseGenerator.GetPixelRidged(chunkIndex, x, y, z, noiseSettings.CaveTwo); float groundSolid = 1; int caveOpen1 = -1; int caveOpen2 = -1; groundSolid = OneMinusOne(groundNoise, ChunkYGradient[y]); caveOpen1 = OneZero(caveNoise1, ChunkYGradient[y]); caveOpen2 = OneZero(caveNoise2, ChunkYGradient[y]); bool isSolid; float finalOpen = groundSolid * Flip(caveOpen1 * caveOpen2); isSolid = finalOpen >= 1; //isSolid = caveOpen1 >= 1; Blocks[x, y, z] = new Block(x, y, z, isSolid ? BlockType.Grass : BlockType.Air); } } } // Loop through all blocks and get grass, dirt or stone value for (int x = 0; x < size.x; x++) { for (int z = 0; z < size.z; z++) { float topBlockHeight = -1; // the height we first found a block at for (int y = (int)size.y - 1; y >= 0; y--) { // if we found the first solid block and are not below ground if (Blocks[x, y, z].BlockID != BlockType.Air) { if (topBlockHeight < 0) { topBlockHeight = y; } if (y < topBlockHeight && y >= topBlockHeight - 3) { Blocks[x, y, z].BlockID = BlockType.Dirt; } else if (y < topBlockHeight) { Blocks[x, y, z].BlockID = BlockType.Stone; } } } } } //List<Vector3> trees = new List<Vector3>(); //// Loop through 4x4 grids and place trees //for (int x = 0; x < size.x; x += 4) //{ // for (int z = 0; z < size.z; z += 4) // { // // to get delta height we index the array diagonally and min max the heights // // there's no point going through each block // int one, two, three, four; // one = GetHeight(Blocks, x, z); // two = GetHeight(Blocks, x + 1, z + 1); // three = GetHeight(Blocks, x + 2, z + 2); // four = GetHeight(Blocks, x + 3, z + 3); // int min = int.MaxValue; // int max = int.MinValue; // if (one > max) // one = max; // if (two > max) // two = max; // if (three > max) // three = max; // if (four > max) // four = max; // if (one < min) // one = min; // if (two < min) // two = min; // if (three < min) // three = min; // if (four < min) // four = min; // int delta = max - min; // if (delta < 5) // only do trees if the ground is relatively flat // { // if (random.Next(0, 100 - noiseSettings.TreeFrequency) == 5) // { // trees.Add(new Vector3(x, one, z)); // } // } // } //} //foreach (Vector3 vector in trees) //{ // GenerateTree(Blocks, vector, TreeType.Oak, random); //} return(GenerateMesh(Blocks, chunk)); }
/// <summary> /// Sets the blocks of this chunk /// </summary> /// <param name="blocks">Blocks.</param> public void ApplyBlocks(ThreeDimensionalBlockArray blocks) { ChunkBlocks = blocks; }