private void DownScaleHeightmap(TerrainQualityManagerQuery query) { TerrainData terrainData = query.terrainData; if (query.data == null) { object[] data = new object[3]; data[0] = terrainData.GetHeights(0, 0, terrainData.heightmapWidth, terrainData.heightmapHeight); data[1] = new float[heightmapResolution, heightmapResolution]; data[2] = (terrainData.heightmapResolution - 1) / (heightmapResolution - 1); query.data = data; } object[] queryData = query.data as object[]; float[,] heights = queryData[0] as float[, ]; float[,] newHeights = queryData[1] as float[, ]; int step = (int)queryData[2]; int halfStep = step / 2; long startTime = DateTime.Now.Ticks; for (int y = activeQueryIndex; y < heightmapResolution; y++) { query.progress = (float)y / heightmapResolution; activeQueryIndex = y; if (DateTime.Now.Ticks - startTime > maxExecutionTime) { return; } int sy = (y == 0) ? 0 : y * step - halfStep; int ly = (y > 0 && y < heightmapResolution - 1) ? step : halfStep; for (int x = 0; x < heightmapResolution; x++) { int sx = (x == 0) ? 0 : x * step - halfStep; int lx = (x > 0 && x < heightmapResolution - 1) ? step : halfStep; float v = 0; for (int py = 0; py < ly; py++) { for (int px = 0; px < lx; px++) { v += heights[sy + py, sx + px]; } } newHeights[y, x] = v / (lx * ly); } } ApplyNewHeightmap(query.terrainData, newHeights); NextQuery(); }
private TerrainQualityManagerQuery AddQuery(string name, TerrainData terrainData = null) { if (queries == null) { queries = new List <TerrainQualityManagerQuery>(); } TerrainQualityManagerQuery query = new TerrainQualityManagerQuery(terrainData, name); queries.Add(query); return(query); }
private void UpdateNeighbors(TerrainQualityManagerQuery query) { Terrain[] terrains = FindObjectsOfType <Terrain>(); if (terrains == null || terrains.Length == 0) { return; } foreach (Terrain t in terrains) { TerrainData terrainData = t.terrainData; Vector3 rightNeighborPosition = t.transform.position + new Vector3(terrainData.size.x, 0, 0); Vector3 bottomNeighborPosition = t.transform.position + new Vector3(0, 0, terrainData.size.z); Terrain rightNeighbor = terrains.FirstOrDefault(tr => (tr.transform.position - rightNeighborPosition).magnitude < 10); Terrain bottomNeighbor = terrains.FirstOrDefault(tr => (tr.transform.position - bottomNeighborPosition).magnitude < 10); if (rightNeighbor != null) { float[,] th = terrainData.GetHeights(heightmapResolution - 1, 0, 1, heightmapResolution); float[,] rh = rightNeighbor.terrainData.GetHeights(0, 0, 1, heightmapResolution); for (int y = 0; y < heightmapResolution; y++) { th[y, 0] = (th[y, 0] + rh[y, 0]) / 2; } terrainData.SetHeights(heightmapResolution - 1, 0, th); rightNeighbor.terrainData.SetHeights(0, 0, th); } if (bottomNeighbor != null) { float[,] th = terrainData.GetHeights(0, heightmapResolution - 1, heightmapResolution, 1); float[,] rh = bottomNeighbor.terrainData.GetHeights(0, 0, heightmapResolution, 1); for (int x = 0; x < heightmapResolution; x++) { th[0, x] = (th[0, x] + rh[0, x]) / 2; } terrainData.SetHeights(0, heightmapResolution - 1, th); bottomNeighbor.terrainData.SetHeights(0, 0, th); } } NextQuery(); }
private void UpScaleHeightmap(TerrainQualityManagerQuery query) { if (query.data == null) { object[] data = new object[1]; data[0] = new float[heightmapResolution, heightmapResolution]; query.data = data; } object[] queryData = query.data as object[]; float[,] newHeights = queryData[0] as float[, ]; TerrainData terrainData = query.terrainData; long startTime = DateTime.Now.Ticks; for (int x = activeQueryIndex; x < heightmapResolution; x++) { query.progress = (float)x / heightmapResolution; activeQueryIndex = x; if (DateTime.Now.Ticks - startTime > maxExecutionTime) { return; } float rx = (float)x / (heightmapResolution - 1); for (int y = 0; y < heightmapResolution; y++) { float ry = (float)y / (heightmapResolution - 1); newHeights[y, x] = terrainData.GetInterpolatedHeight(rx, ry) / terrainData.size.y; } } ApplyNewHeightmap(query.terrainData, newHeights); NextQuery(); }
private void DownScaleAlphamap(TerrainQualityManagerQuery query) { TerrainData terrainData = query.terrainData; int splatCount = terrainData.splatPrototypes.Length; if (query.data == null) { object[] data = new object[3]; data[0] = terrainData.GetAlphamaps(0, 0, terrainData.alphamapWidth, terrainData.alphamapHeight); data[1] = new float[alphamapResolution, alphamapResolution, splatCount]; query.data = data; } object[] queryData = query.data as object[]; float[,,] alphamaps = queryData[0] as float[, , ]; float[,,] newAlphamaps = queryData[1] as float[, , ]; int step = terrainData.alphamapResolution / alphamapResolution; int halfStep = step / 2; long startTime = DateTime.Now.Ticks; for (int sp = activeQueryIndex; sp < splatCount; sp++) { query.progress = (float)sp / splatCount; activeQueryIndex = sp; if (DateTime.Now.Ticks - startTime > maxExecutionTime) { return; } for (int y = 0; y < alphamapResolution; y++) { int sy = (y == 0) ? 0 : y * step - halfStep; int ly = (y > 0 && y < alphamapResolution - 1) ? step : halfStep; for (int x = 0; x < alphamapResolution; x++) { int sx = (x == 0) ? 0 : x * step - halfStep; int lx = (x > 0 && x < alphamapResolution - 1) ? step : halfStep; float v = 0; for (int py = 0; py < ly; py++) { for (int px = 0; px < lx; px++) { v += alphamaps[sx + px, sy + py, sp]; } } newAlphamaps[x, y, sp] = v / (lx * ly); } } } query.terrainData.alphamapResolution = alphamapResolution; query.terrainData.SetAlphamaps(0, 0, newAlphamaps); NextQuery(); }
private void UpScaleAlphamap(TerrainQualityManagerQuery query) { TerrainData terrainData = query.terrainData; int splatCount = terrainData.splatPrototypes.Length; if (query.data == null) { object[] data = new object[2]; data[0] = terrainData.GetAlphamaps(0, 0, terrainData.alphamapWidth, terrainData.alphamapHeight); data[1] = new float[alphamapResolution, alphamapResolution, splatCount]; query.data = data; } object[] queryData = query.data as object[]; float[, ,] alphamaps = queryData[0] as float[, , ]; float[, ,] newAlphamaps = queryData[1] as float[, , ]; long startTime = DateTime.Now.Ticks; for (int sp = activeQueryIndex; sp < splatCount; sp++) { query.progress = (float)sp / splatCount; activeQueryIndex = sp; if (DateTime.Now.Ticks - startTime > maxExecutionTime) { return; } for (int y = 0; y < alphamapResolution; y++) { float ry = (float)y / alphamapResolution * terrainData.alphamapResolution; int y1 = (int)ry; int y2 = y1 + 1; if (y2 >= terrainData.alphamapResolution) { y2 = terrainData.alphamapResolution - 1; } for (int x = 0; x < alphamapResolution; x++) { float rx = (float)x / alphamapResolution * terrainData.alphamapResolution; int x1 = (int)rx; int x2 = x1 + 1; if (x2 >= terrainData.alphamapResolution) { x2 = terrainData.alphamapResolution - 1; } float p1 = Mathf.Lerp(alphamaps[x1, y1, sp], alphamaps[x2, y1, sp], rx - x1); float p2 = Mathf.Lerp(alphamaps[x1, y2, sp], alphamaps[x2, y2, sp], rx - x1); newAlphamaps[x, y, sp] = Mathf.Lerp(p1, p2, ry - y1); } } } query.terrainData.alphamapResolution = alphamapResolution; query.terrainData.SetAlphamaps(0, 0, newAlphamaps); NextQuery(); }
private void ScaleDetailmap(TerrainQualityManagerQuery query) { TerrainData terrainData = query.terrainData; if (query.data == null) { query.data = new List <int[, ]>(); } List <int[, ]> detailLayers = query.data as List <int[, ]>; int countProts = terrainData.detailPrototypes.Length; int detailWidth = terrainData.detailWidth; int detailHeight = terrainData.detailHeight; long startTime = DateTime.Now.Ticks; for (int p = activeQueryIndex; p < countProts; p++) { query.progress = (float)p / countProts; activeQueryIndex = p; if (DateTime.Now.Ticks - startTime > maxExecutionTime) { return; } int[,] detailLayer = terrainData.GetDetailLayer(0, 0, detailWidth, detailHeight, p); int[,] newDetailLayer = new int[detailResolution, detailResolution]; for (int x = 0; x < detailResolution; x++) { float rx = (float)x / detailResolution * terrainData.detailResolution; int x1 = (int)rx; int x2 = x1 + 1; if (x2 >= terrainData.detailResolution) { x2 = terrainData.detailResolution - 1; } for (int y = 0; y < detailResolution; y++) { float ry = (float)y / detailResolution * terrainData.detailResolution; int y1 = (int)ry; int y2 = y1 + 1; if (y2 >= terrainData.detailResolution) { y2 = terrainData.detailResolution - 1; } float p1 = Mathf.RoundToInt(Mathf.Lerp(detailLayer[x1, y1], detailLayer[x2, y1], rx - x1)); float p2 = Mathf.RoundToInt(Mathf.Lerp(detailLayer[x1, y2], detailLayer[x2, y2], rx - x1)); newDetailLayer[x, y] = Mathf.RoundToInt(Mathf.Lerp(p1, p2, ry - y1)); } } detailLayers.Add(newDetailLayer); } terrainData.SetDetailResolution(detailResolution, resolutionPerPatch); for (int i = 0; i < detailLayers.Count; i++) { terrainData.SetDetailLayer(0, 0, i, detailLayers[i]); } NextQuery(); }
private void Prepare() { TerrainData[] terrainDatas = null; if (mode == TerrainQualityManagerModes.singleTerrain) { if (terrain == null) { EditorUtility.DisplayDialog("Error", "Terrain not selected.", "OK"); state = TerrainQualityManagerState.idle; return; } terrainDatas = new[] { terrain.terrainData }; } else if (mode == TerrainQualityManagerModes.allTerrainsInScene) { Terrain[] terrains = FindObjectsOfType(typeof(Terrain)) as Terrain[]; if (terrains != null) { terrainDatas = terrains.Select(t => t.terrainData).ToArray(); } } else if (mode == TerrainQualityManagerModes.allTerrainsInProject) { string[] terrainsGUID = AssetDatabase.FindAssets("t:terrain"); terrainDatas = new TerrainData[terrainsGUID.Length]; for (int i = 0; i < terrainsGUID.Length; i++) { string assetPath = AssetDatabase.GUIDToAssetPath(terrainsGUID[i]); terrainDatas[i] = AssetDatabase.LoadMainAssetAtPath(assetPath) as TerrainData; } } if (terrainDatas == null) { state = TerrainQualityManagerState.idle; return; } bool changeHeightmap = false; foreach (TerrainData t in terrainDatas) { if (t.heightmapResolution != heightmapResolution) { changeHeightmap = true; TerrainQualityManagerQuery query = AddQuery("Resize heightmap.", t); if (t.heightmapResolution > heightmapResolution) { query.method = DownScaleHeightmap; } else { query.method = UpScaleHeightmap; } } if (t.alphamapResolution != alphamapResolution) { TerrainQualityManagerQuery query = AddQuery("Resize alphamap.", t); if (t.alphamapResolution > alphamapResolution) { query.method = DownScaleAlphamap; } else { query.method = UpScaleAlphamap; } } if (t.detailResolution != detailResolution) { AddQuery("Resize detailmap.", t).method = ScaleDetailmap; } if (t.baseMapResolution != baseMapResolution) { t.baseMapResolution = baseMapResolution; } } if (queries == null || queries.Count == 0) { EditorUtility.DisplayDialog("Error", "Nothing to do.", "OK"); Finish(); return; } Undo.RegisterCompleteObjectUndo(terrainDatas, "Change Terrain Maps Resolution"); if (changeHeightmap && mode == TerrainQualityManagerModes.allTerrainsInScene) { AddQuery("Update Neighbors").method = UpdateNeighbors; } activeQueryIndex = 0; queryIndex = 0; state = TerrainQualityManagerState.working; }