public static void generateTerrain(Boolean treesEnabled, Boolean grassEnabled) { ImportAndGenerate.treesEnabled = treesEnabled; ImportAndGenerate.grassEnabled = grassEnabled; int length = (int)((xmax - xmin) * scaleLength); int width = (int)((ymax - ymin) * scaleWidth); float x = xmin - (xmax - xmin) / 2 - xmin; float y = ymin - (ymax - ymin) / 2 - ymin; float height = (length < 250 || width < 250) ? 30 : 80; numPlants = (int)(length * width / 20); if (numPlants < 100) { numPlants = 500; } Texture2D FlatTexture = AssetDatabase.LoadAssetAtPath <Texture2D>(PathConstants.pathGrassTexture2D); Texture2D SteepTexture = AssetDatabase.LoadAssetAtPath <Texture2D>(PathConstants.pathRockTexture2D); terrainData = new TerrainData(); terrainData.heightmapResolution = 256; terrainData.alphamapResolution = 256; var heightmap = new float[terrainData.heightmapResolution, terrainData.heightmapResolution]; System.Random rand = new System.Random(); for (var zRes = 0; zRes < terrainData.heightmapResolution; zRes++) { for (var xRes = 0; xRes < terrainData.heightmapResolution; xRes++) { // Reduce factor float distX = 0; float distY = 0; float marginStart = 20; float marginEnd = 50; float reduceFactor = 0; float constHeight = 0.5f; if (Math.Abs(terrainData.heightmapResolution - xRes) < xRes) { distX = Math.Abs(terrainData.heightmapResolution - xRes); } else { distX = xRes; } if (Math.Abs(terrainData.heightmapResolution - zRes) < zRes) { distY = Math.Abs(terrainData.heightmapResolution - zRes); } else { distY = zRes; } if (distX > marginStart && distY > marginStart && distX <= marginEnd && distY <= marginEnd) { reduceFactor = 1 - (float)(((distX - marginStart) + (distY - marginStart)) / (2 * (marginEnd - marginStart))); heightmap[zRes, xRes] = reduceFactor * constHeight; } else if (distY > marginStart && distY <= marginEnd && distX > marginEnd) { reduceFactor = 1 - ((distY - marginStart) / (marginEnd - marginStart)); heightmap[zRes, xRes] = reduceFactor * constHeight; } else if (distX > marginStart && distX <= marginEnd && distY > marginEnd) { reduceFactor = 1 - ((distX - marginStart) / (marginEnd - marginStart)); heightmap[zRes, xRes] = reduceFactor * constHeight; } else { reduceFactor = 1; heightmap[zRes, xRes] = reduceFactor * constHeight; } // Actual height values from neighbours double randFactor = 0.1f; double selfFactor = 1.5; float value = 0; if (zRes > 0 && xRes > 0 && xRes < terrainData.heightmapResolution - 1 && zRes < terrainData.heightmapResolution - 1) { value = (float)( heightmap[zRes, xRes] * selfFactor + rand.NextDouble() * randFactor + heightmap[zRes - 1, xRes - 1] + heightmap[zRes, xRes - 1] + heightmap[zRes - 1, xRes] + heightmap[zRes + 1, xRes - 1] + heightmap[zRes - 1, xRes + 1] + heightmap[zRes + 1, xRes + 1] + heightmap[zRes + 1, xRes] + heightmap[zRes, xRes + 1]) / 10; } else if (xRes == 0 && zRes == 0) { value = (float)( heightmap[zRes, xRes] * selfFactor + rand.NextDouble() * randFactor + heightmap[zRes + 1, xRes + 1] + heightmap[zRes + 1, xRes] + heightmap[zRes, xRes + 1]) / 5; } else if (xRes == 0 && zRes > 0 && zRes < terrainData.heightmapResolution - 1) { value = (float)( heightmap[zRes, xRes] * selfFactor + rand.NextDouble() * randFactor + heightmap[zRes - 1, xRes] + heightmap[zRes - 1, xRes + 1] + heightmap[zRes + 1, xRes + 1] + heightmap[zRes + 1, xRes] + heightmap[zRes, xRes + 1]) / 7; } else if (xRes == 0 && zRes == terrainData.heightmapResolution - 1) { value = (float)( heightmap[zRes, xRes] * selfFactor + rand.NextDouble() * randFactor * randFactor + heightmap[zRes - 1, xRes] + heightmap[zRes - 1, xRes + 1] + heightmap[zRes, xRes + 1]) / 5; } else if (xRes > 0 && xRes < terrainData.heightmapResolution - 1 && zRes == 0) { value = (float)( heightmap[zRes, xRes] * selfFactor + rand.NextDouble() * randFactor + heightmap[zRes, xRes - 1] + heightmap[zRes + 1, xRes - 1] + heightmap[zRes + 1, xRes + 1] + heightmap[zRes + 1, xRes] + heightmap[zRes, xRes + 1]) / 7; } else if (xRes == terrainData.heightmapResolution - 1 && zRes == 0) { value = (float)( heightmap[zRes, xRes] * selfFactor + rand.NextDouble() * randFactor + heightmap[zRes, xRes - 1] + heightmap[zRes + 1, xRes - 1] + heightmap[zRes + 1, xRes]) / 5; } else if (xRes == terrainData.heightmapResolution - 1 && zRes > 0 && zRes < terrainData.heightmapResolution - 1) { value = (float)( heightmap[zRes, xRes] * selfFactor + rand.NextDouble() * randFactor + heightmap[zRes - 1, xRes - 1] + heightmap[zRes, xRes - 1] + heightmap[zRes - 1, xRes] + heightmap[zRes + 1, xRes - 1] + heightmap[zRes + 1, xRes]) / 7; } else if (xRes == terrainData.heightmapResolution - 1 && zRes == terrainData.heightmapResolution - 1) { value = (float)( heightmap[zRes, xRes] * selfFactor + rand.NextDouble() * randFactor + heightmap[zRes - 1, xRes - 1] + heightmap[zRes, xRes - 1] + heightmap[zRes - 1, xRes]) / 5; } else if (xRes > 0 && xRes < terrainData.heightmapResolution - 1 && zRes == terrainData.heightmapResolution - 1) { value = (float)( heightmap[zRes, xRes] * selfFactor + rand.NextDouble() * randFactor + heightmap[zRes - 1, xRes - 1] + heightmap[zRes, xRes - 1] + heightmap[zRes - 1, xRes] + heightmap[zRes - 1, xRes + 1] + heightmap[zRes, xRes + 1]) / 7; } if (value < 0 || distX > marginEnd && distY > marginEnd) { value = 0; } heightmap[zRes, xRes] = value; } } terrainData.SetHeights(0, 0, heightmap); var flatSplat = new SplatPrototype(); var steepSplat = new SplatPrototype(); flatSplat.texture = FlatTexture; steepSplat.texture = SteepTexture; terrainData.splatPrototypes = new SplatPrototype[] { flatSplat, steepSplat }; terrainData.RefreshPrototypes(); var splatMap = new float[terrainData.alphamapResolution, terrainData.alphamapResolution, 2]; for (var zRes = 0; zRes < terrainData.alphamapHeight; zRes++) { for (var xRes = 0; xRes < terrainData.alphamapWidth; xRes++) { var normalizedX = (float)xRes / (terrainData.alphamapWidth - 1); var normalizedZ = (float)zRes / (terrainData.alphamapHeight - 1); var steepness = terrainData.GetSteepness(normalizedX, normalizedZ); var steepnessNormalized = Mathf.Clamp(steepness / 1.5f, 0, 1f); splatMap[zRes, xRes, 0] = 1f - steepnessNormalized; splatMap[zRes, xRes, 1] = steepnessNormalized; } } terrainData.SetAlphamaps(0, 0, splatMap); terrainData.size = new Vector3(length, height, width); var newTerrainGameObject = Terrain.CreateTerrainGameObject(terrainData); newTerrainGameObject.transform.position = new Vector3(x, 0, y); Terrain = newTerrainGameObject.GetComponent <Terrain>(); Terrain.heightmapPixelError = 8; Terrain.materialType = UnityEngine.Terrain.MaterialType.Custom; Terrain.reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off; // Insert Trees and Plants if (ImportAndGenerate.treesEnabled) { // (1) Trees: MonoBehaviour.print("Inserting 3d Plants"); List <TreePrototype> tpa = new List <TreePrototype>(); for (int i = 0; i < plants.Length; i++) { TreePrototype tp = new TreePrototype(); tp.prefab = AssetDatabase.LoadMainAssetAtPath(PathConstants.pathPrefixPlants + plants[i] + ".prefab") as GameObject; tpa.Add(tp); } terrainData.treePrototypes = tpa.ToArray(); for (int i = 0; i < numPlants; i++) { float xnRel = (float)rand.NextDouble(); float xn = terrainData.size.x * xnRel; float ynRel = (float)rand.NextDouble(); float yn = terrainData.size.z * ynRel; float xGlobal = Terrain.transform.TransformPoint(new Vector3(xn, 0, yn)).x; float yGlobal = Terrain.transform.TransformPoint(new Vector3(xn, 0, yn)).z; Boolean freeSpotFound = false; int counter = 0; while (!freeSpotFound && counter < 10) { // Try 10 random positions, if all fail, then discard this plant foreach (Vector3[] polygon in polygons) { freeSpotFound = !InPolyChecker.IsPointInPolygon(xGlobal, yGlobal, polygon); if (!freeSpotFound) { break; } } if (!freeSpotFound) { xnRel = (float)rand.NextDouble(); xn = terrainData.size.x * xnRel; ynRel = (float)rand.NextDouble(); yn = terrainData.size.z * ynRel; xGlobal = Terrain.transform.TransformPoint(new Vector3(xn, 0, yn)).x; yGlobal = Terrain.transform.TransformPoint(new Vector3(xn, 0, yn)).z; counter++; break; } } if (freeSpotFound) { TreeInstance tree = new TreeInstance(); tree.position = new Vector3(xnRel, 0, ynRel); tree.color = Color.white; tree.lightmapColor = Color.white; tree.prototypeIndex = rand.Next(0, plants.Length); tree.heightScale = 1; tree.widthScale = 1; Terrain.AddTreeInstance(tree); } } } // (2) Grass: if (ImportAndGenerate.grassEnabled) { DetailPrototype grass = new DetailPrototype(); grass.prototypeTexture = (Texture2D)AssetDatabase.LoadAssetAtPath <Texture2D>(PathConstants.pathGrassPrototypeTexture2D); grass.minHeight = 1; grass.minWidth = 1; grass.maxHeight = 2; grass.maxWidth = 2; grass.noiseSpread = 0.1f; grass.bendFactor = 0.1f; grass.dryColor = new Color(0.804f, 0.737f, 0.102f, 1.0f); grass.healthyColor = new Color(0.263f, 0.976f, 0.165f, 1.0f); terrainData.detailPrototypes = new DetailPrototype[] { grass }; terrainData.SetDetailResolution(256, 8); int detailCountPerDetailPixel = 6; int detailIndexToMassPlace = 0; int alphamapWidth = terrainData.alphamapWidth; int alphamapHeight = terrainData.alphamapHeight; int detailWidth = terrainData.detailResolution; int detailHeight = detailWidth; int[,] newDetailLayer = new int[detailWidth, detailHeight]; int delta = 1; for (int j = 0; j < detailWidth; j++) { for (int k = 0; k < detailHeight; k++) { float[] coord = getCornerCoordinatesFromPixel(j, k, detailWidth, detailHeight, Terrain.gameObject.transform.position.x, Terrain.gameObject.transform.position.z, terrainData.size.x, terrainData.size.z); // Check if there is a street/junction at the coordinate Boolean occupied = false; foreach (Vector3[] polygon in polygons) { // Check sorrounding of coordinate occupied = InPolyChecker.IsPointInPolygon(coord[0], coord[1], polygon) || InPolyChecker.IsPointInPolygon(coord[0] - delta, coord[1] - delta, polygon) || InPolyChecker.IsPointInPolygon(coord[0] - delta, coord[1], polygon) || InPolyChecker.IsPointInPolygon(coord[0] - delta, coord[1] + delta, polygon) || InPolyChecker.IsPointInPolygon(coord[0] + delta, coord[1] - delta, polygon) || InPolyChecker.IsPointInPolygon(coord[0] + delta, coord[1], polygon) || InPolyChecker.IsPointInPolygon(coord[0] + delta, coord[1] + delta, polygon); if (occupied) { break; } } if (!occupied) { newDetailLayer[j, k] = detailCountPerDetailPixel; } } } terrainData.SetDetailLayer(0, 0, detailIndexToMassPlace, newDetailLayer); } // Finish Terrain.Flush(); }
internal static void generatingBuildings(int count) { GameObject buildingsContainer = new GameObject("Buildings"); for (int i = 0; i < count; i++) { int randomBuildingIndex = UnityEngine.Random.Range(0, PathConstants.pathBuildings.Length - 1); GameObject building = AssetDatabase.LoadMainAssetAtPath(PathConstants.pathBuildings[randomBuildingIndex]) as GameObject; Component[] renderers = building.GetComponentsInChildren <Renderer>(); float maxLength = 0; float maxWidth = 0; foreach (Component renderer in renderers) { float currentLength = ((Renderer)renderer).bounds.size.x - xmin; float currentWidth = ((Renderer)renderer).bounds.size.z - ymin; if (currentLength > maxLength) { maxLength = currentLength; } if (currentWidth > maxWidth) { maxWidth = currentWidth; } } maxLength = Math.Max(maxLength, maxWidth) * 2f; maxWidth = maxLength; float randomXPosition = UnityEngine.Random.Range(Terrain.transform.position.x, Terrain.transform.position.x + terrainData.size.x); float randomYPosition = UnityEngine.Random.Range(Terrain.transform.position.z, Terrain.transform.position.z + terrainData.size.z); float randomOrientation = UnityEngine.Random.Range(0f, 360f); Boolean freeSpotFound = false; int counter = 0; while (!freeSpotFound && counter < 10) { // Try 10 random positions, if all fail, then discard this building int discretePointsCount = 8; foreach (Vector3[] polygon in polygons) { freeSpotFound = true; // Split the ground face into discretePointsCount^2 points to check for (int x = 0; x < discretePointsCount; x++) { for (int y = 0; y < discretePointsCount; y++) { freeSpotFound &= !InPolyChecker.IsPointInPolygon(randomXPosition + x * maxLength / discretePointsCount, randomYPosition + y * maxLength / discretePointsCount, polygon); if (!freeSpotFound) { break; } } } if (!freeSpotFound) { break; } } if (!freeSpotFound) { randomXPosition = UnityEngine.Random.Range(Terrain.transform.position.x, Terrain.transform.position.x + terrainData.size.x); randomYPosition = UnityEngine.Random.Range(Terrain.transform.position.z, Terrain.transform.position.z + terrainData.size.z); randomOrientation = UnityEngine.Random.Range(0f, 360f); counter++; continue; } } if (freeSpotFound) { GameObject instantiatedBuilding = GameObject.Instantiate(building, new Vector3(randomXPosition, 0, randomYPosition), Quaternion.Euler(new Vector3(0, randomOrientation, 0))); instantiatedBuilding.transform.SetParent(buildingsContainer.transform); Vector3[] vertices = new Vector3[] { new Vector3(randomXPosition, 0, randomYPosition), new Vector3(randomXPosition + maxLength, 0, randomYPosition), new Vector3(randomXPosition + maxLength, 0, randomYPosition + maxWidth), new Vector3(randomXPosition, 0, randomYPosition + maxWidth) }; polygons.Add(vertices); } } }