Hello.
I've made a paged terrain system here loading terrain heightmaps/splatmaps from TCP/IP (directly with the Sockets class). All is working fine, and my adjacent terrains get loaded and displayed as soon as I get near the center terrain border, so I can keep walking and I won't reach the end of the center terrain before the adjacent one is loaded.
Although it is fine, one thing still annoys me... While the data streaming in another thread (using backgroundworker to load the heightmap and splatmap data and store it, so the main thread can display the terrain (as we have the thread-unsafe unity methods which makes life harder)) is loading correctly and I can move around the map while the data comes in, when the main thread takes over the job of creating the terrain object, my "game" is getting hung until the terrain is indeed created and populated with the streamed data.
I though, then, if I should start using StartCoroutine to do so, and I tried it, without success. It does start and it does continue the flow of my Update method, but still I get a hang while creating the terrain (create object, add heightmap info, add splatmap info, attach the textures that will be used by the splatmap). How can I achieve a seamless terrain creation, without having my app freezing in the meanwhile?
Code where the StartCoroutine is called (in Update loop): (It is compared by 4 as 4 is my state in my 3x3 grid of terrains that tells the loop that this terrain is not visible yet, but background worker already loaded data for it)
if (Global.terrainloading[x, y] == 4)
{
GameObject obj = GameObject.Find("TerrainContainer"+y.ToString()+x.ToString());
StartCoroutine(Global.AssignTerrain(Global.terrainx + (-1 + x), Global.terrainy + (-1 + y), x, y, obj));
}
And this is the AssignTerrain method:
private static IEnumerator AssignTerrain(int x, int y, int tx, int ty, GameObject obj)
{
Debug.Log("Started terrain loading");
obj.AddComponent(typeof(Terrain));
TerrainData terrain = new TerrainData();
Vector3 sz = new Vector3(100, 1000, 100);
terrain.size = sz;
int w2 = 1025;
terrain.heightmapResolution = w2;
float[,] heightmapData = (float[,])heightmaploading[tx,ty];
float[, ,] SplatmapData = (float[,,])splatmaploading[tx, ty];
terrain.SetHeights(0, 0, heightmapData);
// Set up SplatPrototypes with the correct terrain textures (for now 3, 0=grass,1=rock,2=sand)
SplatPrototype[] splatprotos = new SplatPrototype[3];
splatprotos[0] = new SplatPrototype();
splatprotos[0].texture = (Texture2D)Resources.Load("grass", typeof(Texture2D));
splatprotos[0].tileOffset = new Vector2(0, 0);
splatprotos[0].tileSize = new Vector2(15, 15);
splatprotos[1] = new SplatPrototype();
splatprotos[1].texture = (Texture2D)Resources.Load("rock", typeof(Texture2D));
splatprotos[1].tileOffset = new Vector2(0, 0);
splatprotos[1].tileSize = new Vector2(15, 15);
splatprotos[2] = new SplatPrototype();
splatprotos[2].texture = (Texture2D)Resources.Load("seasand", typeof(Texture2D));
splatprotos[2].tileOffset = new Vector2(0, 0);
splatprotos[2].tileSize = new Vector2(15, 15);
terrain.splatPrototypes = splatprotos;
terrain.alphamapResolution = 1025;
terrain.baseMapResolution = 1025;
((TerrainCollider)obj.AddComponent(typeof(TerrainCollider))).terrainData = terrain;
((Terrain)obj.GetComponent(typeof(Terrain))).terrainData = terrain;
((Terrain)obj.GetComponent(typeof(Terrain))).terrainData.SetAlphamaps(0, 0, SplatmapData);
((Terrain)obj.GetComponent(typeof(Terrain))).heightmapPixelError = 10;
Global.terrainloading[tx, ty] = 2;
yield return null;
}