public void spawnTree(Hex hex, float heightSeed) { GameObject newTree = Instantiate(treePrefab); Vector2 treePosition = Random.insideUnitCircle * this.getHexSize(); treePosition += HexMathHelper.hexToWorldCoords(hex.getPosition(), this.getHexSize()); float spawnHeight = TerrainHelper.getHeight(heightSeed, treePosition, hex, this.getHexSize(), elevatedHeightmap, mountainHeightmap); float yScale = Random.Range(0.05f, 0.08f); Vector3 newScale = newTree.transform.localScale; newScale.y = yScale; newTree.transform.localScale = newScale; newTree.transform.position = new Vector3(treePosition.x, treePosition.y, spawnHeight - 0.12f); }
public static List <Vector3> getRiversMesh(List <List <Vector2> > rivers, float riverDensity, float hexSize, float heightSeed, Texture2D mountainHeightmap, Texture2D elevatedHeightmap, Map map) { Debug.Log(rivers.Count); float perlinNoiseX = 15.004f; float perlinNoiseStep = 0.1f; List <Vector3> allRriversPoints = new List <Vector3>(); float riverThickness = riverDensity; List <Vector3> vertices = new List <Vector3>(); List <int> triangles = new List <int>(); List <Color32> colours = new List <Color32>(); foreach (List <Vector2> river in rivers) { Debug.Log(river[0]); Debug.Log(river.Count); List <Vector3> riverShorePoints = new List <Vector3>(); List <Vector3> riverPoints = new List <Vector3>(); for (int i = 0; i < river.Count - 1; i++) { Vector2 firstRiverPoint = getHexRiverPoint(river[i], hexSize, map); Vector2 secondRiverPoint = getHexRiverPoint(river[i + 1], hexSize, map); Vector2 direction = secondRiverPoint - firstRiverPoint; Vector2 normal = new Vector2(-direction.y, direction.x).normalized; int pointsNumber = Mathf.CeilToInt(direction.magnitude / riverDensity); for (int pointIndex = 0; pointIndex < pointsNumber; pointIndex++) { Vector3 derivativeDirection; float t = pointIndex * 1.0f / pointsNumber; Vector2 newPoint = Vector2.Lerp(firstRiverPoint, secondRiverPoint, t); float scaleShiftFactor = pointIndex <= pointsNumber / 2 ? pointIndex * 2.0f / pointsNumber : (pointsNumber - pointIndex) * 2.0f / pointsNumber; newPoint = Vector2.Lerp(firstRiverPoint, secondRiverPoint, t); float shift = Mathf.PerlinNoise(perlinNoiseX, riverPoints.Count * perlinNoiseStep) * 0.4f - 0.2f; newPoint += normal * shift * scaleShiftFactor; if (i != 0 || pointIndex != 0) { if (pointIndex == 0) { float nextPointT = (pointIndex + 1) * 1.0f / pointsNumber; Vector2 nextPoint = Vector2.Lerp(firstRiverPoint, secondRiverPoint, nextPointT); float nextScaleShiftFactor = pointIndex + 1 <= pointsNumber / 2 ? (pointIndex + 1) * 2.0f / pointsNumber : (pointsNumber - pointIndex - 1) * 2.0f / pointsNumber; float nextPointShift = Mathf.PerlinNoise(perlinNoiseX, (riverPoints.Count + 1) * perlinNoiseStep) * 0.4f - 0.2f; nextPoint += normal * nextPointShift * nextScaleShiftFactor; Vector2 previousPoint = riverPoints[riverPoints.Count - 1]; float derivativeT = 0.5f; derivativeDirection = 2f * (1f - derivativeT) * (newPoint - previousPoint) + 2f * derivativeT * (nextPoint - newPoint); newPoint = Vector2.Lerp(Vector2.Lerp(previousPoint, newPoint, 0.5f), Vector2.Lerp(newPoint, nextPoint, 0.5f), 0.5f); } else { Vector2 previousPoint = riverPoints[riverPoints.Count - 1]; derivativeDirection = newPoint - previousPoint; } Vector3 perpendicular = new Vector3(-derivativeDirection.y, derivativeDirection.x).normalized; Vector3 actualNewPoint = new Vector3(newPoint.x, newPoint.y, 0); Vector3 firstShorePoint = actualNewPoint + perpendicular * riverThickness; Hex firstPointHex = map.getHex(HexMathHelper.worldToHexCoords(firstShorePoint, hexSize)); float firstShorePointHeight = TerrainHelper.getHeight(heightSeed, firstShorePoint, firstPointHex, hexSize, elevatedHeightmap, mountainHeightmap); firstShorePoint += new Vector3(0, 0, firstShorePointHeight); Vector3 secondShorePoint = actualNewPoint - perpendicular * riverThickness; Hex secondPointHex = map.getHex(HexMathHelper.worldToHexCoords(secondShorePoint, hexSize)); float secondShorePointHeight = TerrainHelper.getHeight(heightSeed, secondShorePoint, secondPointHex, hexSize, elevatedHeightmap, mountainHeightmap); secondShorePoint += new Vector3(0, 0, secondShorePointHeight); riverShorePoints.Add(firstShorePoint); riverShorePoints.Add(secondShorePoint); } Hex newPointHex = map.getHex(HexMathHelper.worldToHexCoords(newPoint, hexSize)); float newPointHeight = TerrainHelper.getHeight(heightSeed, newPoint, newPointHex, hexSize, elevatedHeightmap, mountainHeightmap); riverPoints.Add(new Vector3(newPoint.x, newPoint.y, newPointHeight)); } } Vector3 veryFirstShorePoint = riverShorePoints[0]; Vector3 verySecondShorePoint = riverShorePoints[1]; Vector3 firstPointShift = new Vector2(riverPoints[0].x, riverPoints[0].y) - new Vector2(riverPoints[1].x, riverPoints[1].y); Vector3 missingFirstPoint = verySecondShorePoint + firstPointShift; float missingFirstPointHeight = TerrainHelper.getHeight(heightSeed, missingFirstPoint, map.getHex(HexMathHelper.worldToHexCoords(missingFirstPoint, hexSize)), hexSize, elevatedHeightmap, mountainHeightmap); missingFirstPoint += new Vector3(0, 0, missingFirstPointHeight); riverShorePoints.Insert(0, missingFirstPoint); Vector3 missingSecondPoint = veryFirstShorePoint + firstPointShift; float missingSecondPointHeight = TerrainHelper.getHeight(heightSeed, missingSecondPoint, map.getHex(HexMathHelper.worldToHexCoords(missingSecondPoint, hexSize)), hexSize, elevatedHeightmap, mountainHeightmap); missingSecondPoint += new Vector3(0, 0, missingSecondPointHeight); riverShorePoints.Insert(0, missingSecondPoint); riverPoints.AddRange(riverShorePoints); //allRriversPoints.AddRange(riverPoints); allRriversPoints.AddRange(riverShorePoints); for (int i = 0, vertextIndex = 0; i <= riverShorePoints.Count - 4; i += 2, vertextIndex += 6) { vertices.Add(riverShorePoints[i + 2]); vertices.Add(riverShorePoints[i + 1]); vertices.Add(riverShorePoints[i]); vertices.Add(riverShorePoints[i + 3]); vertices.Add(riverShorePoints[i + 1]); vertices.Add(riverShorePoints[i + 2]); for (int triangleIndex = vertextIndex; triangleIndex < vertextIndex + 6; triangleIndex++) { triangles.Add(triangleIndex); colours.Add(Color.blue); } } } Mesh mesh = new Mesh(); mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; mesh.name = "Rivers"; mesh.vertices = vertices.ToArray(); mesh.triangles = triangles.ToArray(); mesh.colors32 = colours.ToArray(); mesh.RecalculateNormals(); mesh.RecalculateBounds(); return(allRriversPoints); }
public MapMesh generateTerrain(Map map, List <List <Vector2> > riverPoints, TriangleNet.Mesh mapTriangulation) { MapMesh terrain = new MapMesh(); List <Vector3> landVertices = new List <Vector3>(); List <Vector3> oceanVertices = new List <Vector3>(); List <Vector3> innerWaterVertices = new List <Vector3>(); Dictionary <Vector2, float> mapVerticesHeights = new Dictionary <Vector2, float>(); foreach (Triangle triangle in mapTriangulation.Triangles) { List <MapVertex> mapVertices = triangle.vertices .Select(vertex => vertex is MapVertex ? (MapVertex)vertex : convertToMapVertex(vertex)) .Reverse() .ToList(); List <Vector3> underWaterShifts = new List <Vector3>(new Vector3[3]); List <bool> needsShoreAdjustments = new List <bool>(new bool[3]); if (mapVertices.Any(mapVertice => mapVertice.hex == null)) { for (int i = 0; i < mapVertices.Count; i++) { if (mapVertices[i].hex != null) { needsShoreAdjustments[i] = true; } } } MapVertex shoreMapVertex = mapVertices.FirstOrDefault(mapVertex => mapVertex.hex != null && (mapVertex.hex.biome == null || mapVertex.hex.biome.name != "Fresh lake")); if (shoreMapVertex != null) { Vector2 shoreCenter = HexMathHelper.hexToWorldCoords(new Vector2(shoreMapVertex.hex.x, shoreMapVertex.hex.y), this.hexSize); //if shore triangle push it underwater to create shore slope for (int i = 0; i < mapVertices.Count; i++) { if (mapVertices[i].hex == null) { underWaterShifts[i] = (new Vector2((float)mapVertices[i].x, (float)mapVertices[i].y) - shoreCenter).normalized * 0.3f; underWaterShifts[i] += new Vector3(0, 0, 0.03f); } } } List <Vector3> triangleVertices = new List <Vector3>(); for (int i = 0; i < mapVertices.Count; i++) { float height = TerrainHelper.getHeight(heightSeed, mapVertices[i], this.hexSize, elevatedHeightmap, mountainHeightmap); Vector3 newVertex = mapVertices[i].toVector3() + underWaterShifts[i] + new Vector3(0, 0, height); if (!mapVerticesHeights.ContainsKey(newVertex) && needsShoreAdjustments[i]) { newVertex.z = Random.Range(0.08f, 0.13f); mapVerticesHeights[newVertex] = newVertex.z; } if (mapVertices[i].isRiver && (mapVertices[i].hex == null || !mapVertices[i].hex.hasTag(RiverHelper.FRESH_LAKE_TAG))) { newVertex += TerrainHelper.getRiverHeightAdjustment(newVertex); } triangleVertices.Add(newVertex); } if (mapVertices.All(mapVertex => mapVertex.hex == null)) { oceanVertices.AddRange(triangleVertices); } else if (mapVertices.All(mapVertex => mapVertex.isRiver)) { innerWaterVertices.AddRange(triangleVertices); } else if (mapVertices.All(mapVertex => mapVertex.hex != null && mapVertex.hex.hasTag(RiverHelper.FRESH_LAKE_TAG))) { innerWaterVertices.AddRange(triangleVertices); } else { landVertices.AddRange(triangleVertices); } } //smooth shore for (int i = 0; i < landVertices.Count; i++) { Vector3 vertex = landVertices[i]; if (mapVerticesHeights.ContainsKey(vertex)) { vertex.z = mapVerticesHeights[landVertices[i]]; landVertices[i] = vertex; } } terrain.landMesh = this.createMesh("Land", landVertices); terrain.oceanMesh = this.createMesh("Ocean", oceanVertices); terrain.innerWaterMesh = this.createMesh("Lakes and Rivers", innerWaterVertices); return(terrain); }