166 lines
5.0 KiB
C#
166 lines
5.0 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Linq;
|
|
using TransportGame.Generator;
|
|
using TransportGame.Model;
|
|
using TransportGame.Utils;
|
|
using UnityEngine;
|
|
|
|
public class TerrainGeneratorScript : MonoBehaviour
|
|
{
|
|
private Map map = null;
|
|
|
|
public int TerrainWidth = 1024;
|
|
public int TerrainHeight = 1024;
|
|
public GameObject WaterObject;
|
|
public Texture2D[] Textures;
|
|
|
|
// Use this for initialization
|
|
void Start()
|
|
{
|
|
StartCoroutine(GenerateMap());
|
|
}
|
|
|
|
private void GenerateTerrainThread()
|
|
{
|
|
CityGenerator generator = new CityGenerator();
|
|
map = generator.Generate(TerrainWidth, TerrainHeight);
|
|
}
|
|
|
|
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[] {
|
|
new Vector2(0, 0),
|
|
new Vector2(0, 1),
|
|
new Vector2(1, 0),
|
|
new Vector2(1, 1)
|
|
};
|
|
water.RecalculateNormals();
|
|
|
|
return water;
|
|
}
|
|
|
|
private IEnumerator GenerateMap()
|
|
{
|
|
// Generate terrain
|
|
foreach (var i in Task.RunAsync(GenerateTerrainThread))
|
|
yield return i;
|
|
|
|
// 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);
|
|
terrainData.SetHeights(0, 0, map.Heightmap);
|
|
terrainData.name = "Generated Terrain Data";
|
|
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;
|
|
}
|
|
|
|
// Create terrain object
|
|
GameObject terrain = Terrain.CreateTerrainGameObject(terrainData);
|
|
terrain.name = "Generated Terrain";
|
|
yield return null;
|
|
|
|
Terrain terrainComp = terrain.GetComponent<Terrain>();
|
|
terrainComp.heightmapPixelError = 1;
|
|
yield return null;
|
|
|
|
// Set water
|
|
if (WaterObject != null)
|
|
{
|
|
MeshFilter waterMesh = WaterObject.GetComponent<MeshFilter>();
|
|
waterMesh.mesh = GenerateWater();
|
|
}
|
|
yield return null;
|
|
|
|
// Set up textures
|
|
SetupSplatmaps(terrainData);
|
|
}
|
|
|
|
private void SetupSplatmaps(TerrainData terrainData)
|
|
{
|
|
float[, ,] splatData = new float[terrainData.alphamapWidth, terrainData.alphamapHeight, terrainData.alphamapLayers];
|
|
Expression[] expressions = new Expression[terrainData.alphamapLayers];
|
|
|
|
for (int y = 0; y < terrainData.alphamapHeight; y++)
|
|
for (int x = 0; x < terrainData.alphamapWidth; x++)
|
|
{
|
|
float y_01 = (float)y / (float)terrainData.alphamapHeight;
|
|
float x_01 = (float)x / (float)terrainData.alphamapWidth;
|
|
|
|
int ix = Mathf.RoundToInt(x_01 * TerrainWidth);
|
|
int iy = Mathf.RoundToInt(y_01 * TerrainHeight);
|
|
|
|
// Get height
|
|
float height = map.GetHeight(ix, iy);
|
|
|
|
// Get steepness
|
|
float steepness = map.GetSteepness(ix, iy);
|
|
|
|
// Go through each texture layer
|
|
float[] weights = new float[terrainData.alphamapLayers];
|
|
float sum = 0;
|
|
|
|
for (int t = 0; t < terrainData.alphamapLayers; t++)
|
|
{
|
|
// 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"] = terrainData.size.y;
|
|
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 < terrainData.alphamapLayers; t++)
|
|
{
|
|
splatData[x, y, t] = weights[t] / sum;
|
|
}
|
|
}
|
|
|
|
terrainData.SetAlphamaps(0, 0, splatData);
|
|
}
|
|
|
|
// Update is called once per frame
|
|
void Update()
|
|
{
|
|
}
|
|
}
|