city-generation/Game/Assets/Scripts/Unity/TerrainGeneratorScript.cs

209 lines
6.3 KiB
C#
Raw Normal View History

2015-05-09 15:06:30 +00:00
using System;
2015-03-19 10:34:58 +00:00
using System.Collections;
2015-05-09 15:06:30 +00:00
using System.Linq;
2015-03-19 10:34:58 +00:00
using TransportGame.Generator;
using TransportGame.Model;
using TransportGame.Unity;
2015-05-09 15:06:30 +00:00
using TransportGame.Utils;
using UnityEngine;
2015-03-19 10:34:58 +00:00
public class TerrainGeneratorScript : MonoBehaviour
{
private Map map = null;
2015-03-19 10:34:58 +00:00
public int TerrainWidth = 1024;
public int TerrainHeight = 1024;
public GameObject WaterObject;
2015-05-09 15:06:30 +00:00
public Texture2D[] Textures;
public Material RoadMaterial;
2015-03-19 10:34:58 +00:00
// Use this for initialization
void Start()
{
StartCoroutine(GenerateMap());
}
2015-03-19 10:34:58 +00:00
private void GenerateTerrainThread()
{
CityGenerator generator = new CityGenerator();
map = generator.Generate(TerrainWidth, TerrainHeight);
}
2015-05-20 08:26:46 +00:00
private Mesh GenerateWater()
{
Mesh water = new Mesh();
water.name = "water";
water.vertices = new[] {
new Vector3(0, map.WaterLevel, 0),
new Vector3(0, map.WaterLevel, map.Height),
new Vector3(map.Width, map.WaterLevel, 0),
new Vector3(map.Width, map.WaterLevel, map.Height)
};
water.triangles = new[] { 0, 1, 2, 2, 1, 3 };
water.uv = new[] {
2015-05-29 16:03:08 +00:00
new UnityEngine.Vector2(0, 0),
new UnityEngine.Vector2(0, 1),
new UnityEngine.Vector2(1, 0),
new UnityEngine.Vector2(1, 1)
};
water.RecalculateNormals();
2015-03-19 10:34:58 +00:00
return water;
}
2015-03-19 10:34:58 +00:00
private IEnumerator GenerateMap()
{
2015-05-20 08:26:46 +00:00
// Generate terrain
foreach (var i in Task.RunAsync(GenerateTerrainThread))
yield return i;
2015-03-19 10:34:58 +00:00
// Generate terrain data
TerrainData terrainData = new TerrainData();
terrainData.heightmapResolution = Mathf.Max(map.Height, map.Width) + 1;
terrainData.size = new Vector3(map.Width, map.Biome.Height, map.Height);
terrainData.SetDetailResolution(1024, 8);
2015-05-20 08:26:46 +00:00
terrainData.SetHeights(0, 0, map.Heightmap);
terrainData.name = "Generated Terrain Data";
2015-05-09 15:06:30 +00:00
yield return null;
if (map.Biome.Textures != null)
{
SplatPrototype[] prototypes = new SplatPrototype[map.Biome.Textures.Length];
for (int i = 0; i < map.Biome.Textures.Length; i++)
{
Texture2D texture = Textures.FirstOrDefault(tex => tex != null && tex.name == map.Biome.Textures[i].Source);
if (texture == null)
throw new Exception("Texture " + map.Biome.Textures[i].Source + " not found!");
prototypes[i] = new SplatPrototype();
prototypes[i].texture = texture;
}
terrainData.splatPrototypes = prototypes;
yield return null;
}
2015-03-19 10:34:58 +00:00
// Create terrain object
GameObject terrain = Terrain.CreateTerrainGameObject(terrainData);
terrain.name = "Generated Terrain";
yield return null;
2015-03-19 10:34:58 +00:00
Terrain terrainComp = terrain.GetComponent<Terrain>();
terrainComp.heightmapPixelError = 1;
yield return null;
2015-03-19 10:34:58 +00:00
// Set water
if (WaterObject != null)
{
MeshFilter waterMesh = WaterObject.GetComponent<MeshFilter>();
waterMesh.mesh = GenerateWater();
}
2015-05-09 15:06:30 +00:00
yield return null;
// Set up textures
Logger.Info("Setting up textures...");
foreach (var i in SetupSplatmaps(terrainData))
yield return i;
// Generate road mesh
Logger.Info("Generating roads...");
RoadMeshGenerator meshGenerator = new RoadMeshGenerator();
meshGenerator.RoadMaterial = RoadMaterial;
foreach (object i in meshGenerator.Generate(map))
yield return i;
2015-05-29 16:03:08 +00:00
// -- DEBUG --
foreach (var center in map.PopulationCenters)
Debug.DrawLine(new Vector3(center.Y, 0, center.X), new Vector3(center.Y, map.Biome.Height, center.X), Color.yellow, 100000);
}
2015-03-19 10:34:58 +00:00
private float[,,] GenerateSplatData(int alphaWidth, int alphaHeight, int alphaLayers)
2015-05-09 15:06:30 +00:00
{
float[, ,] splatData = new float[alphaWidth, alphaHeight, alphaLayers];
Expression[] expressions = new Expression[alphaLayers];
2015-05-09 15:06:30 +00:00
for (int y = 0; y < alphaHeight; y++)
for (int x = 0; x < alphaWidth; x++)
2015-05-09 15:06:30 +00:00
{
float y_01 = (float)y / (float)alphaHeight;
float x_01 = (float)x / (float)alphaWidth;
2015-05-09 15:06:30 +00:00
int ix = Mathf.RoundToInt(x_01 * TerrainWidth);
int iy = Mathf.RoundToInt(y_01 * TerrainHeight);
// Get height
2015-05-20 08:26:46 +00:00
float height = map.GetHeight(ix, iy);
2015-05-09 15:06:30 +00:00
// Get steepness
2015-05-21 08:49:04 +00:00
float steepness = map.GetSteepness(ix, iy);
2015-05-20 08:26:46 +00:00
// Go through each texture layer
float[] weights = new float[alphaLayers];
2015-05-09 15:06:30 +00:00
float sum = 0;
for (int t = 0; t < alphaLayers; t++)
2015-05-09 15:06:30 +00:00
{
// Set up expression
if (expressions[t] == null)
{
expressions[t] = new Expression(map.Biome.Textures[t].Expression);
expressions[t].ParseExpression();
}
expressions[t].Variables["height"] = height;
expressions[t].Variables["steepness"] = steepness;
expressions[t].Variables["maxHeight"] = map.Biome.Height;
2015-05-09 15:06:30 +00:00
expressions[t].Variables["waterLevel"] = map.WaterLevel - 1f;
// Obtain weight
weights[t] = expressions[t].Evaluate();
sum += weights[t];
}
// Normalize and copy weights
for (int t = 0; t < alphaLayers; t++)
2015-05-09 15:06:30 +00:00
{
splatData[x, y, t] = weights[t] / sum;
}
}
return splatData;
}
private IEnumerable SetupSplatmaps(TerrainData terrainData)
{
float[, ,] splatData = null;
int alphaW = terrainData.alphamapWidth;
int alphaH = terrainData.alphamapHeight;
int alphaL = terrainData.alphamapLayers;
foreach (var i in Task.RunAsync(() => splatData = GenerateSplatData(alphaW, alphaH, alphaL)))
yield return i;
2015-05-09 15:06:30 +00:00
terrainData.SetAlphamaps(0, 0, splatData);
}
// Update is called once per frame
void Update()
{
}
2015-05-29 16:03:08 +00:00
void OnGUI()
{
Event e = Event.current;
if (e.type == EventType.KeyDown)
{
if (e.keyCode == KeyCode.Home)
{
Logger.Warning("Writing to file...");
Logger.DumpMap(map, "map.map");
Logger.Warning("Wrote map to file.");
}
}
}
2015-03-19 10:34:58 +00:00
}