Procedural Terrain generation and weird sudden changes

EDIT: Seems to be fixed now, not sure but it was probably something to do with rounding errors in the terrain stitcher…

Hey so I’ve for nearly 2 weeks now been very puzzled about a possible bug in unity’s terrain class. I’ve been debugging all of my own clases over the past 2 weeks and literally went through huge 2D arrays looking up values to check if everything is okay which it seem to be.

This bug seems to happen everytime a new "chunk is created/generated but the first 25 initialchunks generated is perfect (as seen below) but the next 5 added causes very weird behaviors, and not only generates completely weird, but also changes previously generated chunks WITHOUT having any reference to them or their terrain script.

So I was wondering if anyone else had ever had similar issues happen to them when working with PCG and unity’s own terrain, and how I can fix this?

I’m on unity 4.5.4 atm.

This is my result after generation the first 25 initial chunks:

The result after generation 5 new chunks besides the hills (Note that the camera have NOT been moved, and how the hills is suddenly appearing without any sort of script calls).

Edit: So I increased the initial load distance which gave me a correct looking, however after the first line of new chunks, everything went up in smoke again…

  • Jackie

The only things I notice is you have 25 chunks in all the 2 images, but the last 5 chunks have different names.
Have you overwritten the last 5 intentionally?

different names? All is named “Chunk[x;y]” where x and y is coordinates relative to the the chunk(s) size eg: (position.x / chunksize) I should not over write them as I completely delete all old and unused chunks and initialize new ones each time the play move within a threshold.

Up

Hard to tell without code, but can be your problem is due to reaching the end of the virtual terrain you extract chunks from and the end can’t be seamlessly tied to the start.

The virtual terrain, (assuming you talking the noise generator) is limited to be between int.minvalue and int.maxvalue, each chunk only increase/decrease the area by 1 about the code, the only 2 script that is active doing generation is these, don’t mind the mess from the debugging…

Chunkloader:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class ChunkLoader : MonoBehaviour
{
    public static ChunkLoader chunkloader;
    int LoadDistance = 9;
    int Center { get { return (LoadDistance - 1) / 2; } }
    int ChunkSize;
    public List<List<GameObject>> Chunks = new List<List<GameObject>>();

    Terrain lt;
    Terrain rt;
    Terrain tt;
    Terrain bt;

    [SerializeField]
    GameObject Player;

    public ChunkLoader()
    {
        chunkloader = this;
      
    }

    // Use this for initialization
    void Start ()
    {
        ChunkSize = DataBaseHandler.ChunkSize;
        for (int i = 0; i < LoadDistance; i++)
        {
            List<GameObject> lgo = new List<GameObject>();
            for (int j = 0; j < LoadDistance; j++)
            {
                GameObject go = new GameObject();
                go.AddComponent<Chunk>();
                go.transform.position = new Vector3(((((LoadDistance - 1) / 2) - LoadDistance) + j + 1) * ChunkSize, 0, (((LoadDistance - 1) / 2 - LoadDistance) + i + 1) * ChunkSize);
                go.name = "Chunk" + "[" + (j - Center) + ";" + (i - Center) + "]";
                lgo.Add(go);
                go.GetComponent<Chunk>().Generate();
            }
            Chunks.Add(lgo);
        }
        for (int i = 0; i < LoadDistance; i++)
        {
            for (int j = 0; j < LoadDistance; j++)
            {
                if (i != 0)
                {
                    bt = Chunks[i - 1][j].GetComponent<Terrain>();
                    TerrainStitcher.stitch(bt, Chunks[i][j].GetComponent<Terrain>(), 16, 0);
                }
                if (i != LoadDistance - 1)
                {
                    tt = Chunks[i + 1][j].GetComponent<Terrain>();
                    TerrainStitcher.stitch(tt, Chunks[i][j].GetComponent<Terrain>(), 16, 0);
                }
                if (j != 0)
                {
                    lt = Chunks[i][j - 1].GetComponent<Terrain>();
                    TerrainStitcher.stitch(lt, Chunks[i][j].GetComponent<Terrain>(), 16, 0);
                }
                if (j != LoadDistance - 1)
                {
                    rt = Chunks[i][j + 1].GetComponent<Terrain>();
                    TerrainStitcher.stitch(rt, Chunks[i][j].GetComponent<Terrain>(), 16, 0);
                }

                Chunks[i][j].GetComponent<Terrain>().SetNeighbors(lt, tt, rt, bt);
                Chunks[i][j].GetComponent<Terrain>().Flush();
                bt = null;
                tt = null;
                lt = null;
                rt = null;
            }
        }

    }

    // Update is called once per frame
    void Update()
    {
        if (Player.transform.position.z < Chunks[Center - 1][Center].transform.position.z + (ChunkSize / 2))
        {
            AddColumnBack();
            DeleteColumnFront();
        }
        if (Player.transform.position.z > Chunks[Center + 1][Center].transform.position.z + (ChunkSize / 2))
        {
            AddColumnFront();
            DeleteColumnBack();
        }
        if (Player.transform.position.x < Chunks[Center][Center - 1].transform.position.x + (ChunkSize / 2))
        {
            AddRowBack();
            DeleteRowFront();
        }
        if (Player.transform.position.x > Chunks[Center][Center + 1].transform.position.x + (ChunkSize / 2))
        {
            AddRowFront();
            DeleteRowBack();
        }
    }

    void AddColumnFront()
    {
        Vector3 vec = Chunks[Chunks.Count - 1][Center].transform.position;
        List<GameObject> lgo = new List<GameObject>();
        int c = -(Center * ChunkSize);
        for (int i = 0; i < Chunks.Count; i++)
        {
            GameObject go = new GameObject();
            go.transform.position = new Vector3(vec.x + c, 0, vec.z + ChunkSize);
            go.AddComponent<Chunk>();
            go.name = "Chunk" + "[" + go.transform.position.x / ChunkSize + ";" + go.transform.position.z / ChunkSize + "]";
            lgo.Add(go);
            go.GetComponent<Chunk>().Generate();
            c += ChunkSize;
        }

        Chunks.Add(lgo);

        for (int i = 0; i < Chunks.Count - 1; i++)
        {

            if (i == 0)
            {
                TerrainTools.StitchTerrains(Chunks[Chunks.Count - 1][i].GetComponent<Terrain>(), Chunks[Chunks.Count - 1][i + 1].GetComponent<Terrain>(), 16, 0);
                TerrainTools.StitchTerrains(Chunks[Chunks.Count - 1][i].GetComponent<Terrain>(), Chunks[Chunks.Count - 2][i].GetComponent<Terrain>(), 16, 0);

                Chunks[Chunks.Count - 1][i].GetComponent<Terrain>().SetNeighbors(null, null, Chunks[Chunks.Count - 1][i + 1].GetComponent<Terrain>(), Chunks[Chunks.Count - 2][i].GetComponent<Terrain>());
                Chunks[Chunks.Count - 1][i].GetComponent<Terrain>().Flush();
                Chunks[Chunks.Count - 2][i].GetComponent<Terrain>().SetNeighbors(null, Chunks[Chunks.Count - 1][i].GetComponent<Terrain>(), Chunks[Chunks.Count - 2][i + 1].GetComponent<Terrain>(), Chunks[Chunks.Count - 3][i].GetComponent<Terrain>());
                Chunks[Chunks.Count - 2][i].GetComponent<Terrain>().Flush();
            }
            else if (i == Chunks.Count - 2)
            {
                TerrainTools.StitchTerrains(Chunks[Chunks.Count - 1][i].GetComponent<Terrain>(), Chunks[Chunks.Count - 1][i - 1].GetComponent<Terrain>(), 16, 0);
                TerrainTools.StitchTerrains(Chunks[Chunks.Count - 1][i].GetComponent<Terrain>(), Chunks[Chunks.Count - 2][i].GetComponent<Terrain>(), 16, 0);

                Chunks[Chunks.Count - 1][i].GetComponent<Terrain>().SetNeighbors(Chunks[Chunks.Count - 1][i - 1].GetComponent<Terrain>(), null, null, Chunks[Chunks.Count - 2][i].GetComponent<Terrain>());
                Chunks[Chunks.Count - 1][i].GetComponent<Terrain>().Flush();
                Chunks[Chunks.Count - 2][i].GetComponent<Terrain>().SetNeighbors(Chunks[Chunks.Count - 2][i - 1].GetComponent<Terrain>(), Chunks[Chunks.Count - 1][i].GetComponent<Terrain>(), null, Chunks[Chunks.Count - 3][i].GetComponent<Terrain>());
                Chunks[Chunks.Count - 2][i].GetComponent<Terrain>().Flush();
            }
            else
            {
                TerrainTools.StitchTerrains(Chunks[Chunks.Count - 1][i].GetComponent<Terrain>(), Chunks[Chunks.Count - 1][i - 1].GetComponent<Terrain>(), 16, 0);
                TerrainTools.StitchTerrains(Chunks[Chunks.Count - 1][i].GetComponent<Terrain>(), Chunks[Chunks.Count - 1][i + 1].GetComponent<Terrain>(), 16, 0);
                TerrainTools.StitchTerrains(Chunks[Chunks.Count - 1][i].GetComponent<Terrain>(), Chunks[Chunks.Count - 2][i].GetComponent<Terrain>(), 16, 0);

                Chunks[Chunks.Count - 1][i].GetComponent<Terrain>().SetNeighbors(Chunks[Chunks.Count - 1][i - 1].GetComponent<Terrain>(), null, Chunks[Chunks.Count - 1][i + 1].GetComponent<Terrain>(), Chunks[Chunks.Count - 2][i].GetComponent<Terrain>());
                Chunks[Chunks.Count - 1][i].GetComponent<Terrain>().Flush();
                Chunks[Chunks.Count - 2][i].GetComponent<Terrain>().SetNeighbors(Chunks[Chunks.Count - 2][i - 1].GetComponent<Terrain>(), Chunks[Chunks.Count - 1][i].GetComponent<Terrain>(), Chunks[Chunks.Count - 2][i + 1].GetComponent<Terrain>(), Chunks[Chunks.Count - 3][i].GetComponent<Terrain>());
                Chunks[Chunks.Count - 2][i].GetComponent<Terrain>().Flush();
            }
        }
    }

    void AddColumnBack()
    {
        Vector3 vec = Chunks[0][Center].transform.position;
        List<GameObject> lgo = new List<GameObject>();
        int c = -(Center * ChunkSize);
        for (int i = 0; i < Chunks.Count; i++)
        {
            GameObject go = new GameObject();
            go.transform.position = new Vector3(vec.x + c, 0, vec.z - ChunkSize);
            go.AddComponent<Chunk>();
            go.name = "Chunk" + "[" + go.transform.position.x / ChunkSize + ";" + go.transform.position.z / ChunkSize + "]";
            lgo.Add(go);
            go.GetComponent<Chunk>().Generate();
            c += ChunkSize;
        }
        Chunks.Insert(0, lgo);

        for (int i = 0; i < Chunks.Count - 1; i++)
        {
            if (i == 0)
            {
                TerrainTools.StitchTerrains(Chunks[0][i].GetComponent<Terrain>(), Chunks[0][i + 1].GetComponent<Terrain>(), 16, 0);
                TerrainTools.StitchTerrains(Chunks[0][i].GetComponent<Terrain>(), Chunks[1][i].GetComponent<Terrain>(), 16, 0);

                Chunks[0][i].GetComponent<Terrain>().SetNeighbors(null, Chunks[1][i].GetComponent<Terrain>(), Chunks[0][i + 1].GetComponent<Terrain>(), null);
                Chunks[0][i].GetComponent<Terrain>().Flush();
                Chunks[1][i].GetComponent<Terrain>().SetNeighbors(null, Chunks[2][i].GetComponent<Terrain>(), Chunks[1][i + 1].GetComponent<Terrain>(), Chunks[0][i].GetComponent<Terrain>());
                Chunks[1][i].GetComponent<Terrain>().Flush();
            }
            else if (i == Chunks.Count - 2)
            {
                TerrainTools.StitchTerrains(Chunks[0][i].GetComponent<Terrain>(), Chunks[0][i - 1].GetComponent<Terrain>(), 16, 0);
                TerrainTools.StitchTerrains(Chunks[0][i].GetComponent<Terrain>(), Chunks[1][i].GetComponent<Terrain>(), 16, 0);

                Chunks[0][i].GetComponent<Terrain>().SetNeighbors(Chunks[0][i - 1].GetComponent<Terrain>(), Chunks[1][i].GetComponent<Terrain>(), null, null);
                Chunks[0][i].GetComponent<Terrain>().Flush();
                Chunks[1][i].GetComponent<Terrain>().SetNeighbors(Chunks[1][i - 1].GetComponent<Terrain>(), Chunks[2][i].GetComponent<Terrain>(), null, Chunks[0][i].GetComponent<Terrain>());
                Chunks[1][i].GetComponent<Terrain>().Flush();
            }
            else
            {
                TerrainTools.StitchTerrains(Chunks[0][i].GetComponent<Terrain>(), Chunks[0][i - 1].GetComponent<Terrain>(), 16, 0);
                TerrainTools.StitchTerrains(Chunks[0][i].GetComponent<Terrain>(), Chunks[0][i + 1].GetComponent<Terrain>(), 16, 0);
                TerrainTools.StitchTerrains(Chunks[0][i].GetComponent<Terrain>(), Chunks[1][i].GetComponent<Terrain>(), 16, 0);

                Chunks[0][i].GetComponent<Terrain>().SetNeighbors(Chunks[0][i - 1].GetComponent<Terrain>(), Chunks[1][i].GetComponent<Terrain>(), Chunks[0][i + 1].GetComponent<Terrain>(), null);
                Chunks[0][i].GetComponent<Terrain>().Flush();
                Chunks[1][i].GetComponent<Terrain>().SetNeighbors(Chunks[1][i - 1].GetComponent<Terrain>(), Chunks[2][i].GetComponent<Terrain>(), Chunks[1][i + 1].GetComponent<Terrain>(), Chunks[0][i].GetComponent<Terrain>());
                Chunks[1][i].GetComponent<Terrain>().Flush();
            }
        }
    }

    void AddRowFront()
    {
        Vector3 vec = Chunks[Center][Chunks[1].Count - 1].transform.position;
        int c = -(Center * ChunkSize);
        foreach (List<GameObject> lgo in Chunks)
        {
            GameObject go = new GameObject();
            go.transform.position = new Vector3(vec.x + ChunkSize, 0, vec.z + c);
            go.AddComponent<Chunk>();
            go.name = "Chunk" + "[" + go.transform.position.x / ChunkSize + ";" + go.transform.position.z / ChunkSize + "]";
            go.GetComponent<Chunk>().Generate();
            lgo.Add(go);
            c += ChunkSize;
        }


        for (int i = 0; i < Chunks.Count; i++)
        {
            if (i == 0)
            {
                TerrainTools.StitchTerrains(Chunks[i][Chunks.Count].GetComponent<Terrain>(), Chunks[i][Chunks.Count - 1].GetComponent<Terrain>(), 16, 0);
                TerrainTools.StitchTerrains(Chunks[i][Chunks.Count].GetComponent<Terrain>(), Chunks[i + 1][Chunks.Count].GetComponent<Terrain>(), 16, 0);

                Chunks[i][Chunks.Count].GetComponent<Terrain>().SetNeighbors(Chunks[i][Chunks.Count - 1].GetComponent<Terrain>(), Chunks[i + 1][Chunks.Count].GetComponent<Terrain>(), null, null);
                Chunks[i][Chunks.Count].GetComponent<Terrain>().Flush();
                Chunks[i][Chunks.Count - 1].GetComponent<Terrain>().SetNeighbors(Chunks[i][Chunks.Count - 2].GetComponent<Terrain>(), Chunks[i + 1][Chunks.Count - 1].GetComponent<Terrain>(), Chunks[i][Chunks.Count].GetComponent<Terrain>(), null);
                Chunks[i][Chunks.Count - 1].GetComponent<Terrain>().Flush();
            }
            else if (i == Chunks.Count - 1)
            {
                TerrainTools.StitchTerrains(Chunks[i][Chunks.Count].GetComponent<Terrain>(), Chunks[i][Chunks.Count - 1].GetComponent<Terrain>(), 16, 0);
                TerrainTools.StitchTerrains(Chunks[i][Chunks.Count].GetComponent<Terrain>(), Chunks[i - 1][Chunks.Count].GetComponent<Terrain>(), 16, 0);

                Chunks[i][Chunks.Count].GetComponent<Terrain>().SetNeighbors(Chunks[i][Chunks.Count - 1].GetComponent<Terrain>(), null, null, Chunks[i - 1][Chunks.Count].GetComponent<Terrain>());
                Chunks[i][Chunks.Count].GetComponent<Terrain>().Flush();
                Chunks[i][Chunks.Count - 1].GetComponent<Terrain>().SetNeighbors(Chunks[i][Chunks.Count - 2].GetComponent<Terrain>(), null, Chunks[i][Chunks.Count].GetComponent<Terrain>(), Chunks[i - 1][Chunks.Count - 1].GetComponent<Terrain>());
                Chunks[i][Chunks.Count - 1].GetComponent<Terrain>().Flush();
            }
            else
            {
                TerrainTools.StitchTerrains(Chunks[i][Chunks.Count].GetComponent<Terrain>(), Chunks[i][Chunks.Count - 1].GetComponent<Terrain>(), 16, 0);
                TerrainTools.StitchTerrains(Chunks[i][Chunks.Count].GetComponent<Terrain>(), Chunks[i - 1][Chunks.Count].GetComponent<Terrain>(), 16, 0);
                TerrainTools.StitchTerrains(Chunks[i][Chunks.Count].GetComponent<Terrain>(), Chunks[i + 1][Chunks.Count].GetComponent<Terrain>(), 16, 0);

                Chunks[i][Chunks.Count].GetComponent<Terrain>().SetNeighbors(Chunks[i][Chunks.Count - 1].GetComponent<Terrain>(), Chunks[i + 1][Chunks.Count].GetComponent<Terrain>(), null, Chunks[i - 1][Chunks.Count].GetComponent<Terrain>());
                Chunks[i][Chunks.Count].GetComponent<Terrain>().Flush();
                Chunks[i][Chunks.Count - 1].GetComponent<Terrain>().SetNeighbors(Chunks[i][Chunks.Count - 2].GetComponent<Terrain>(), Chunks[i + 1][Chunks.Count - 1].GetComponent<Terrain>(), Chunks[i][Chunks.Count].GetComponent<Terrain>(), Chunks[i - 1][Chunks.Count - 1].GetComponent<Terrain>());
                Chunks[i][Chunks.Count - 1].GetComponent<Terrain>().Flush();
            }
        }
    }

    void AddRowBack()
    {
        Vector3 vec = Chunks[Center][0].transform.position;
        int c = -(Center * ChunkSize);
        foreach (List<GameObject> lgo in Chunks)
        {
            GameObject go = new GameObject();
            go.transform.position = new Vector3(vec.x - ChunkSize, 0, vec.z + c);
            go.AddComponent<Chunk>();
            go.name = "Chunk" + "[" + go.transform.position.x / ChunkSize + ";" + go.transform.position.z / ChunkSize + "]";
            go.GetComponent<Chunk>().Generate();
            lgo.Insert(0, go);
            c += ChunkSize;
        }


        for (int i = 0; i < Chunks.Count; i++)
        {
            if (i == 0)
            {
                TerrainTools.StitchTerrains(Chunks[i][0].GetComponent<Terrain>(), Chunks[i][1].GetComponent<Terrain>(), 16, 0);
                TerrainTools.StitchTerrains(Chunks[i][0].GetComponent<Terrain>(), Chunks[i + 1][0].GetComponent<Terrain>(), 16, 0);

                Chunks[i][0].GetComponent<Terrain>().SetNeighbors(null, Chunks[i + 1][0].GetComponent<Terrain>(), Chunks[i][1].GetComponent<Terrain>(), null);
                Chunks[i][0].GetComponent<Terrain>().Flush();
                Chunks[i][1].GetComponent<Terrain>().SetNeighbors(Chunks[i][0].GetComponent<Terrain>(), Chunks[i + 1][1].GetComponent<Terrain>(), Chunks[i][2].GetComponent<Terrain>(), null);
                Chunks[i][1].GetComponent<Terrain>().Flush();
            }
            else if (i == Chunks.Count - 1)
            {
                TerrainTools.StitchTerrains(Chunks[i][0].GetComponent<Terrain>(), Chunks[i][1].GetComponent<Terrain>(), 16, 0);
                TerrainTools.StitchTerrains(Chunks[i][0].GetComponent<Terrain>(), Chunks[i - 1][0].GetComponent<Terrain>(), 16, 0);

                Chunks[i][0].GetComponent<Terrain>().SetNeighbors(null, null, Chunks[i][1].GetComponent<Terrain>(), Chunks[i - 1][0].GetComponent<Terrain>());
                Chunks[i][0].GetComponent<Terrain>().Flush();
                Chunks[i][1].GetComponent<Terrain>().SetNeighbors(Chunks[i][0].GetComponent<Terrain>(), null, Chunks[i][2].GetComponent<Terrain>(), Chunks[i - 1][1].GetComponent<Terrain>());
                Chunks[i][1].GetComponent<Terrain>().Flush();
            }
            else
            {
                TerrainTools.StitchTerrains(Chunks[i][0].GetComponent<Terrain>(), Chunks[i][1].GetComponent<Terrain>(), 16, 0);
                TerrainTools.StitchTerrains(Chunks[i][0].GetComponent<Terrain>(), Chunks[i - 1][0].GetComponent<Terrain>(), 16, 0);
                TerrainTools.StitchTerrains(Chunks[i][0].GetComponent<Terrain>(), Chunks[i + 1][0].GetComponent<Terrain>(), 16, 0);

                Chunks[i][0].GetComponent<Terrain>().SetNeighbors(null, Chunks[i + 1][0].GetComponent<Terrain>(), Chunks[i][1].GetComponent<Terrain>(), Chunks[i - 1][0].GetComponent<Terrain>());
                Chunks[i][0].GetComponent<Terrain>().Flush();
                Chunks[i][1].GetComponent<Terrain>().SetNeighbors(Chunks[i][0].GetComponent<Terrain>(), Chunks[i + 1][1].GetComponent<Terrain>(), Chunks[i][2].GetComponent<Terrain>(), Chunks[i - 1][1].GetComponent<Terrain>());
                Chunks[i][1].GetComponent<Terrain>().Flush();
            }
        }
    }

    void DeleteColumnFront()
    {
        for (int i = 0; i < Chunks[Chunks.Count - 1].Count; i++)
        {
            if (i == 0)
            {
                Chunks[Chunks.Count - 2][i].GetComponent<Terrain>().SetNeighbors(null, null, Chunks[Chunks.Count - 2][i + 1].GetComponent<Terrain>(), Chunks[Chunks.Count - 3][i].GetComponent<Terrain>());
            }
            else if (i == Chunks[0].Count - 1)
            {
                Chunks[Chunks.Count - 2][i].GetComponent<Terrain>().SetNeighbors(Chunks[Chunks.Count - 2][i - 1].GetComponent<Terrain>(), null, null, Chunks[Chunks.Count - 3][i].GetComponent<Terrain>());
            }
            else
            {
                Chunks[Chunks.Count - 2][i].GetComponent<Terrain>().SetNeighbors(Chunks[Chunks.Count - 2][i - 1].GetComponent<Terrain>(), null, Chunks[Chunks.Count - 2][i + 1].GetComponent<Terrain>(), Chunks[Chunks.Count - 3][i].GetComponent<Terrain>());
            }
            Chunks[Chunks.Count - 2][i].GetComponent<Terrain>().Flush();
            GameObject.Destroy(Chunks[Chunks.Count - 1][i]);
        }
        Chunks.RemoveAt(Chunks.Count - 1);
    }

    void DeleteColumnBack()
    {
        for (int i = 0; i < Chunks[0].Count; i++)
        {
            if (i == 0)
            {
                Chunks[1][i].GetComponent<Terrain>().SetNeighbors(null, Chunks[2][i].GetComponent<Terrain>(), Chunks[1][i + 1].GetComponent<Terrain>(), null);
            }
            else if (i == Chunks[0].Count - 1)
            {
                Chunks[1][i].GetComponent<Terrain>().SetNeighbors(Chunks[1][i - 1].GetComponent<Terrain>(), Chunks[2][i].GetComponent<Terrain>(), null, null);
            }
            else
            {
                Chunks[1][i].GetComponent<Terrain>().SetNeighbors(Chunks[1][i - 1].GetComponent<Terrain>(), Chunks[2][i].GetComponent<Terrain>(), Chunks[1][i + 1].GetComponent<Terrain>(), null);
            }
            Chunks[1][i].GetComponent<Terrain>().Flush();
            GameObject.Destroy(Chunks[0][i]);
        }
        Chunks.RemoveAt(0);
    }

    void DeleteRowFront()
    {
        for (int i = 0; i < Chunks.Count; i++)
        {
            if (i == 0)
            {
                Chunks[i][Chunks.Count - 1].GetComponent<Terrain>().SetNeighbors(Chunks[i][Chunks.Count - 2].GetComponent<Terrain>(), Chunks[i + 1][Chunks.Count - 1].GetComponent<Terrain>(), null, null);
            }
            else if (i == Chunks.Count - 1)
            {

                Chunks[i][Chunks.Count - 1].GetComponent<Terrain>().SetNeighbors(Chunks[i][Chunks.Count - 2].GetComponent<Terrain>(), null, null, Chunks[i - 1][Chunks.Count - 1].GetComponent<Terrain>());
            }
            else
            {
                Chunks[i][Chunks.Count - 1].GetComponent<Terrain>().SetNeighbors(Chunks[i][Chunks.Count - 2].GetComponent<Terrain>(), Chunks[i + 1][Chunks.Count - 1].GetComponent<Terrain>(), null, Chunks[i - 1][Chunks.Count - 1].GetComponent<Terrain>());
            }
            Chunks[i][Chunks.Count - 1].GetComponent<Terrain>().Flush();
        }
        for (int i = 0; i < Chunks.Count; i++)
        {
            GameObject.Destroy(Chunks[i][Chunks.Count]);
            Chunks[i].RemoveAt(Chunks.Count);
        }
    }

    void DeleteRowBack()
    {
        for (int i = 0; i < Chunks.Count; i++)
        {
            if (i == 0)
            {
                Chunks[i][1].GetComponent<Terrain>().SetNeighbors(null, Chunks[i + 1][1].GetComponent<Terrain>(), Chunks[i][2].GetComponent<Terrain>(), null);
            }
            else if (i == Chunks.Count - 1)
            {
                Chunks[i][1].GetComponent<Terrain>().SetNeighbors(null, null, Chunks[i][2].GetComponent<Terrain>(), Chunks[i - 1][1].GetComponent<Terrain>());
            }
            else
            {
                Chunks[i][1].GetComponent<Terrain>().SetNeighbors(null, Chunks[i + 1][1].GetComponent<Terrain>(), Chunks[i][2].GetComponent<Terrain>(), Chunks[i - 1][1].GetComponent<Terrain>());
            }
            Chunks[i][1].GetComponent<Terrain>().Flush();
          
        }
        for (int i = 0; i < Chunks.Count; i++)
        {
            GameObject.Destroy(Chunks[i][0]);
            Chunks[i].RemoveAt(0);
        }
    }

    public Chunk GetChunkAtPlayer()
    {
        return GameObject.Find("Chunk[" + ((int)(Player.transform.position.x / ChunkSize)).ToString() + ";" + ((int)(Player.transform.position.z / ChunkSize)).ToString() + "]").GetComponent<Chunk>();
    }

    public Chunk GetChunkAtWorldLocation(float x, float y)
    {
        return GameObject.Find("Chunk[" + ((int)(x / ChunkSize)).ToString() + ";" + ((int)(y / ChunkSize)).ToString() + "]").GetComponent<Chunk>();
    }

    public Chunk GetChunkAtChunkLocation(int x, int y)
    {
        return GameObject.Find("Chunk[" + (x).ToString() + ";" + (y).ToString() + "]").GetComponent<Chunk>();
    }
}

Chunk:

using UnityEngine;
using System;
using System.Collections.Generic;
using System.Linq;
using LibNoise;
using LibNoise.Operator;
using LibNoise.Generator;

public class Chunk : MonoBehaviour
{
    Vector2[,] WindDirection;
    float[,] RainShadow;
    float[,] Temperature;
    float[,] Humidity;
    int MaxWindSpeed = 50;
    Texture2D rain1;
    Texture2D rain2;
    NoiseHelper noisehelper;
    List<BiomeTypes> availblebiomes = new List<BiomeTypes>();

    float xOffset
    {
        get
        {
            return this.transform.position.x / ThisTerain.terrainData.size.x;
        }
    }

    float yOffset
    {
        get
        {
            return this.transform.position.z / ThisTerain.terrainData.size.x;
        }
    }

    Terrain ThisTerain
    {
        get
        {
            return this.gameObject.GetComponent<Terrain>();
        }
    }

    public void Generate()
    {
        SetupTerainData();
        noisehelper = new NoiseHelper(xOffset, yOffset);
        BiomeTypes[,] Biomes = GenerateBiomes();
        noisehelper.SetBiomes(Biomes);
        noisehelper.SetBounds(new Rect(yOffset, yOffset + 1, xOffset, xOffset + 1));
        GenerateHeightmap(Biomes);
        GenerateAlphamap(Biomes);
        ThisTerain.Flush();
    }

    void SetupTerainData()
    {
        Terrain terrrain = this.gameObject.AddComponent<Terrain>();
        terrrain.terrainData = new TerrainData();
        terrrain.terrainData.heightmapResolution = DataBaseHandler.HeighMapSize;
        terrrain.terrainData.size = new Vector3(DataBaseHandler.ChunkSize, DataBaseHandler.ChunkSize * 2, DataBaseHandler.ChunkSize);
        TerrainCollider terrraincollider = this.gameObject.AddComponent<TerrainCollider>();
        terrraincollider.terrainData = terrrain.terrainData;
        terrrain.terrainData.alphamapResolution = DataBaseHandler.BiomeMapSize;
        terrrain.terrainData.splatPrototypes = DataBaseHandler.DataBase.SplatsPrototypes;
    }

    void GenerateHeightmap(BiomeTypes[,] biomes)
    {
        int resolution = ThisTerain.terrainData.heightmapResolution;
        float[,] hmap = new float[resolution, resolution];
        List <LibNoise.ModuleBase> modules = new List<ModuleBase>();
        for (int i = 0; i < availblebiomes.Count; i++)
        {
            if (!modules.Contains(Biome.FindBiome(availblebiomes[i]).Generate(noisehelper)))
            {
                modules.Add(Biome.FindBiome(availblebiomes[i]).Generate(noisehelper));
            }
        }
      
        for (int i = 1; i < modules.Count; i++)
        {
            if (modules[i] != null)
            {
                modules[i][0] = modules[i - 1];
            }
        }
        rain1 = new Texture2D(128, 128);
        Noise2D heightMap = new Noise2D(resolution, resolution, modules[0]);
        heightMap.GeneratePlanar(yOffset, yOffset + 1, xOffset, xOffset + 1);

        for (int y = 0; y < resolution; y++)
        {
            for (int x = 0; x < resolution; x++)
            {
                hmap[x, y] = (((heightMap[x, y]) * 0.5f) + 0.5f);// (float)((FlatNoiseMap[x, y] * 0.5f) + 0.5f);
            }
        }

        ThisTerain.terrainData.SetHeights(0, 0, hmap);
    }

    BiomeTypes[,] GenerateBiomes()
    {
        BiomeTypes[,] biomes = new BiomeTypes[ThisTerain.terrainData.alphamapResolution, ThisTerain.terrainData.alphamapResolution];

        int resolution = ThisTerain.terrainData.alphamapResolution;

        Noise2D heightMap = new Noise2D(resolution, resolution, new Perlin(0.125, 2, 0.5, 10, 0, QualityMode.High));
        heightMap.GeneratePlanar(yOffset, yOffset + 1, xOffset, xOffset + 1);

        Noise2D rainfall = new Noise2D(resolution, resolution, new Perlin(0.125, 2, 0.5, 10, 4560, QualityMode.High));
        rainfall.GeneratePlanar(yOffset, yOffset + 1, xOffset, xOffset + 1);

        Noise2D WindMap = new Noise2D((resolution + (MaxWindSpeed * 2)), (resolution + (MaxWindSpeed * 2)), new Perlin(0.125, 2, 0.5, 10, 0, QualityMode.High));
        WindMap.GeneratePlanar(yOffset - ((double)MaxWindSpeed / (double)resolution), (yOffset + 1) + ((double)MaxWindSpeed / (double)resolution), xOffset - ((double)MaxWindSpeed / (double)resolution), (xOffset + 1) + ((double)MaxWindSpeed / (double)resolution));

        Noise2D RainCalcMap = new Noise2D((resolution + (MaxWindSpeed * 2)), (resolution + (MaxWindSpeed * 2)), new Perlin(0.125, 2, 0.5, 10, 0, QualityMode.High));
        RainCalcMap.GeneratePlanar(xOffset - ((double)MaxWindSpeed / (double)resolution), (xOffset + 1) + ((double)MaxWindSpeed / (double)resolution), yOffset - ((double)MaxWindSpeed / (double)resolution), (yOffset + 1) + ((double)MaxWindSpeed / (double)resolution));


        RainShadow = new float[ThisTerain.terrainData.alphamapResolution, ThisTerain.terrainData.alphamapResolution];
        Temperature = new float[ThisTerain.terrainData.alphamapResolution, ThisTerain.terrainData.alphamapResolution];
        Humidity = new float[ThisTerain.terrainData.alphamapResolution, ThisTerain.terrainData.alphamapResolution];

        WindDirection = new Vector2[(resolution + (MaxWindSpeed * 2)), (resolution + (MaxWindSpeed * 2))];
        for (int i = 0; i < resolution + (MaxWindSpeed * 2); i++)
        {
            for (int j = 0; j < resolution + (MaxWindSpeed * 2); j++)
            {
                float val = ((((CosGradient((i - 50) + (yOffset * (float)(resolution)), (float)(resolution), 0.125f) * 0.5f) + 0.5f) + (((WindMap[i,j]) * 0.5f) + 0.5f) / 2) * 12.0f);
                if (val >= 0 && val < 2)
                {
                    if (val >= 1)
                    {
                        WindDirection[i, j] = new Vector2(-1.0f, (val - 2.0f));
                    }
                    else
                    {
                        WindDirection[i, j] = new Vector2(val * -1.0f, -1.0f);
                    }
                }
                else if (val >= 2 && val < 4)
                {
                    if (val >= 3)
                    {
                        WindDirection[i, j] = new Vector2((4.0f - val), 1.0f);
                    }
                    else
                    {
                        WindDirection[i, j] = new Vector2(1.0f, val - 2.0f);
                    }
                }
                else if (val >= 4 && val < 6)
                {
                    if (val >= 5)
                    {
                        WindDirection[i, j] = new Vector2(-1.0f, (val - 6.0f));
                    }
                    else
                    {
                        WindDirection[i, j] = new Vector2((val - 4.0f) * -1.0f, -1.0f);
                    }
                }
                else if (val >= 6 && val < 8)
                {
                    if (val >= 7)
                    {
                        WindDirection[i, j] = new Vector2(val - 8.0f, 1.0f);
                    }
                    else
                    {
                        WindDirection[i, j] = new Vector2(-1.0f, (val - 6.0f));
                    }
                }
                else if (val >= 8 && val < 10)
                {
                    if (val >= 9)
                    {
                        WindDirection[i, j] = new Vector2(1.0f, (10.0f - val) * -1.0f);
                    }
                    else
                    {
                        WindDirection[i, j] = new Vector2((val - 8.0f), -1.0f);
                    }
                }
                else if (val >= 10 && val <= 12)
                {
                    if (val >= 11)
                    {
                        WindDirection[i, j] = new Vector2((val - 12.0f), 1.0f);
                    }
                    else
                    {
                        WindDirection[i, j] = new Vector2(-1.0f, (val - 10.0f));
                    }
                }
            }
        }
        for (int i = -MaxWindSpeed; i < RainCalcMap.Width - MaxWindSpeed; i++)
        {
            for (int j = -MaxWindSpeed; j < RainCalcMap.Height - MaxWindSpeed; j++)
            {
                if (RainCalcMap[i + MaxWindSpeed, j + MaxWindSpeed] <= 0.5f)
                {
                    Bresenham(i, i + (int)(WindDirection[j + MaxWindSpeed, i + MaxWindSpeed].x * MaxWindSpeed), j, j + (int)(WindDirection[j + MaxWindSpeed, i + MaxWindSpeed].y * MaxWindSpeed));
                }
            }
        }
        //TODO: Remove the rain1 and rain2 textures from the game!
      
        //Smoothen(ref RainShadow);
        for (int i = 0; i < ThisTerain.terrainData.alphamapResolution; i++)
        {
            for (int j = 0; j < ThisTerain.terrainData.alphamapResolution; j++)
            {
                try
                {
                    Temperature[i, j] = -50.0f + (((((heightMap[i, j] * 0.5f) + 0.5f) + (CosGradient(i + (yOffset * (float)(resolution)), (float)(resolution), 0.25f) * 0.5f) + 0.5f) / 2.0f) * 100.0f);
                    //Humidity[i, j] = ((((CosGradient(i + (yOffset * (float)(resolution)), (float)(resolution), 0.25f) * 0.5f) + 0.5f)) * 100.0f) * (((rainfall[i, j] * 0.5f) + 0.5f));
                    Humidity[i, j] = ((((rainfall[i, j] * 0.5f) + 0.5f)) * 100.0f);// *(((((heightMap[i, j] * 0.75f) + 0.5f) + (CosGradient(i + (yOffset * (float)(resolution)), (float)(resolution), 0.5f) * 0.25f) + 0.5f) / 2.0f));
                    //Old Biome Selector
                    //biomes[i, j] = DataBaseHandler.DataBase.BiomeDiagram[Mathf.RoundToInt((((heightMap[i, j] * 0.5f) + 0.5f) + (CosGradient(i + (yOffset * (float)(resolution)), (float)(resolution), 0.5f) * 0.5f) + 0.5f) / 2), Mathf.RoundToInt((RainShadow[i, j] + ((rainfall[i, j] * 0.5f) + 0.5f) / 2) * 2)];
                    biomes[i, j] = Biome.DecideBiome(Temperature[i, j], Humidity[i, j]);
                    if (!availblebiomes.Contains(biomes[i, j]))
                    {
                        availblebiomes.Add(biomes[i, j]);
                    }
                }
                catch(Exception ex)
                {
                }
            }
        }
      

        return biomes;
    }

    void Bresenham(int x0, int x1, int y0, int y1)
    {
        //TODO: Add smooth Value curves - ie  the value getting smaller and smaller per point it's getting away from the original one.
        int sx = 0;
        int sy = 0;
        int dx = Mathf.Abs(x1 - x0);
        int dy = Mathf.Abs(y1 - y0);
        if (x0 < x1) { sx = 1; } else { sx = -1; }
        if (y0 < y1) { sy = 1; } else { sy = -1; }
        int err = dx - dy;

        bool loop = true;
        while (loop)
        {
            if ((y0 >= 0 && y0 < RainShadow.GetLength(1)) && (x0 >= 0 && x0 < RainShadow.GetLength(0)))
            {
                RainShadow[y0, x0] += 0.000004f;
            }
            if ((x0 == x1) && (y0 == y1)) loop = false;
            int e2 = 2 * err;
            if (e2 > -dy)
            {
                err = err - dy;
                x0 = x0 + sx;
            }
            if (e2 < dx)
            {
                err = err + dx;
                y0 = y0 + sy;
            }
        }
    }

    //TODO Find a Better smooth algorithm.
    public void Smoothen(ref float[,] Heights)
    {
        int i, j, u, v;
        int size = Heights.GetLength(0);
        float total;

        for (i = 1; i < size - 1; ++i)
        {
            for (j = 1; j < size - 1; ++j)
            {
                total = 0.0f;

                for (u = -1; u <= 1; u++)
                {
                    for (v = -1; v <= 1; v++)
                    {
                        total += Heights[i + u, j + v];
                    }
                }

                Heights[i, j] = total / 9.0f;
            }
        }
    }

    float CosGradient(float f, float res, float frequency)
    {
        return ((Mathf.Cos((f / res) * Mathf.PI * frequency)));
    }

    void GenerateAlphamap(BiomeTypes[,] Biomes)
    {
        int resolution = ThisTerain.terrainData.alphamapHeight;
      
        float[, ,] amap = new float[ThisTerain.terrainData.alphamapResolution, ThisTerain.terrainData.alphamapResolution, ThisTerain.terrainData.splatPrototypes.Length];

        for (int hX = 0; hX < ThisTerain.terrainData.alphamapResolution; hX++)
        {
            for (int hY = 0; hY < ThisTerain.terrainData.alphamapResolution; hY++)
            {
                amap[hX, hY, Biome.FindTexture(Biomes[hX, hY])] = 1;
            }
        }
        ThisTerain.terrainData.SetAlphamaps(0, 0, amap);
    }

    void OnGUI()
    {
        //if (this.gameObject.name == "Chunk[0;-2]")
        //{
        GUI.DrawTexture(new Rect((Screen.width / 4) + (128 * xOffset), (Screen.height / 2) - (128 * yOffset), (128), (128)), rain1);
            //GUI.DrawTexture(new Rect(128 + 10, 0, 128, 128 + 50), rain2);
        //}
    }
}