Files
KopMap/Assets/NatureManufacture Assets/WorldStreamer/Scritps/Terrain/Editor/TerrainSplitterCPU.cs
2025-09-02 18:55:19 +08:00

342 lines
14 KiB
C#

// /**
// * Created by Pawel Homenko on 02/2024
// */
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System;
using UnityEngine;
using UnityEditor;
namespace WorldStreamer2
{
public static class TerrainSplitterCPU
{
private static TerrainManagerSettings _terrainManagerSettings;
public static void SplitTerrain(TerrainManagerSettings managerSettings, bool allTerrains = false)
{
_terrainManagerSettings = managerSettings;
if (!Directory.Exists("Assets/" + _terrainManagerSettings.terrainsDataPath))
{
Directory.CreateDirectory("Assets/" + _terrainManagerSettings.terrainsDataPath);
}
Undo.SetCurrentGroupName("Split Terrain");
_terrainManagerSettings.terrainsCount = _terrainManagerSettings.splitSize * _terrainManagerSettings.splitSize;
Terrain[] terrains = Selection.GetFiltered<Terrain>(SelectionMode.TopLevel);
if (allTerrains)
terrains = Terrain.activeTerrains;
var currentObjectIndex = 0;
List<TreeInstance> treeInstancesList = new List<TreeInstance>();
TreeInstance[] treeInstances;
TreeInstance ti;
foreach (var terrain in terrains)
{
currentObjectIndex++;
if (terrain == null)
{
continue;
}
var progressCaption = "Spliting terrain " + terrain.name + " (" + currentObjectIndex.ToString() +
" of " + terrains.Length.ToString() + ")";
for (int i = 0; i < _terrainManagerSettings.terrainsCount; i++)
{
int xI = (i % _terrainManagerSettings.splitSize);
int yI = (i / _terrainManagerSettings.splitSize);
float size = 1 / (float)_terrainManagerSettings.splitSize;
string progressText = "Generating terrain split " + i + "/terrainsCount";
float progress = i / (float)_terrainManagerSettings.terrainsCount;
EditorUtility.DisplayProgressBar(progressCaption, progressText, progress);
TerrainData td = new TerrainData();
GameObject tgo = Terrain.CreateTerrainGameObject(td);
Undo.RegisterCreatedObjectUndo(td, "Create terrain data");
Undo.RegisterCreatedObjectUndo(tgo, "Create terrain split");
tgo.name = terrain.name + " " + xI + "_" + yI;
Terrain newTerrain = tgo.GetComponent<Terrain>();
newTerrain.terrainData = td;
AssetDatabase.CreateAsset(td,
"Assets" + _terrainManagerSettings.terrainsDataPath + newTerrain.name + ".asset");
//copy all prototypes
newTerrain.terrainData.terrainLayers = terrain.terrainData.terrainLayers;
newTerrain.terrainData.detailPrototypes = terrain.terrainData.detailPrototypes;
newTerrain.terrainData.treePrototypes = terrain.terrainData.treePrototypes;
TerrainSettingsSetter.SetTerrainSettings(newTerrain,_terrainManagerSettings);
newTerrain.materialTemplate = terrain.materialTemplate;
Vector3 parentPosition = terrain.GetPosition();
float spaceShiftX = terrain.terrainData.size.z / _terrainManagerSettings.splitSize;
float spaceShiftY = terrain.terrainData.size.x / _terrainManagerSettings.splitSize;
float xWShift = (i % _terrainManagerSettings.splitSize) * spaceShiftX;
float zWShift = (i / _terrainManagerSettings.splitSize) * spaceShiftY;
//Debug.Log(xWShift + " " + zWShift);
td.heightmapResolution = terrain.terrainData.heightmapResolution / _terrainManagerSettings.splitSize;
td.size = new Vector3(terrain.terrainData.size.x / _terrainManagerSettings.splitSize,
terrain.terrainData.size.y,
terrain.terrainData.size.z / _terrainManagerSettings.splitSize
);
float[,] terrainHeight = terrain.terrainData.GetHeights(0, 0,
terrain.terrainData.heightmapResolution, terrain.terrainData.heightmapResolution);
float[,] partHeight =
new float[terrain.terrainData.heightmapResolution / _terrainManagerSettings.splitSize + 1,
terrain.terrainData.heightmapResolution / _terrainManagerSettings.splitSize + 1];
int heightShift = terrain.terrainData.heightmapResolution / _terrainManagerSettings.splitSize;
int startX = 0;
int startY = 0;
int end = terrain.terrainData.heightmapResolution / _terrainManagerSettings.splitSize + 1;
for (int x = startX; x < end; x++)
{
bool cancel = EditorUtility.DisplayCancelableProgressBar(progressCaption,
progressText + " (Split height)",
progress + (((float)x / (end - startX)) / 5f) /
(float)_terrainManagerSettings.terrainsCount);
if (cancel)
{
Undo.CollapseUndoOperations(Undo.GetCurrentGroup());
EditorUtility.ClearProgressBar();
return;
}
for (int y = startY; y < end; y++)
{
float ph = terrainHeight[x + heightShift * xI, y + heightShift * yI];
partHeight[x, y] = ph;
}
}
newTerrain.terrainData.SetHeights(0, 0, partHeight);
//hole data
bool[,] terrainHole = terrain.terrainData.GetHoles(0, 0,
terrain.terrainData.holesResolution, terrain.terrainData.holesResolution);
bool[,] partHole =
new bool[terrain.terrainData.holesResolution / _terrainManagerSettings.splitSize,
terrain.terrainData.holesResolution / _terrainManagerSettings.splitSize];
int endHole = terrain.terrainData.holesResolution / _terrainManagerSettings.splitSize;
int holeShift = terrain.terrainData.heightmapResolution / _terrainManagerSettings.splitSize;
for (int x = startX; x < endHole; x++)
{
bool cancel = EditorUtility.DisplayCancelableProgressBar(progressCaption,
progressText + " (Split height)",
progress + (1 / 5f + ((float)x / (endHole - startX)) / 5f) /
(float)_terrainManagerSettings.terrainsCount);
if (cancel)
{
Undo.CollapseUndoOperations(Undo.GetCurrentGroup());
EditorUtility.ClearProgressBar();
return;
}
for (int y = startY; y < endHole; y++)
{
partHole[x, y] = terrainHole[x + holeShift * xI, y + holeShift * yI];
}
}
newTerrain.terrainData.SetHoles(0, 0, partHole);
//td.holesResolution = terrain.terrainData.heightmapResolution / _terrainManagerSettings.splitSize;
// terrain.terrainData.holesTexture
td.alphamapResolution = terrain.terrainData.alphamapResolution / _terrainManagerSettings.splitSize;
float[,,] terrainSplat = terrain.terrainData.GetAlphamaps(0, 0,
terrain.terrainData.alphamapResolution, terrain.terrainData.alphamapResolution);
float[,,] partSplat =
new float[terrain.terrainData.alphamapResolution / _terrainManagerSettings.splitSize,
terrain.terrainData.alphamapResolution / _terrainManagerSettings.splitSize,
terrain.terrainData.alphamapLayers
];
int splatShift = terrain.terrainData.alphamapResolution / _terrainManagerSettings.splitSize;
int start = 0;
end = terrain.terrainData.alphamapResolution / _terrainManagerSettings.splitSize;
for (int s = 0; s < terrain.terrainData.alphamapLayers; s++)
{
bool cancel = EditorUtility.DisplayCancelableProgressBar(progressCaption,
progressText + " (Processing splat " + s + ")",
progress + (2 / 5f + (s / (float)terrain.terrainData.alphamapLayers) / 5f) /
(float)_terrainManagerSettings.terrainsCount);
if (cancel)
{
Undo.CollapseUndoOperations(Undo.GetCurrentGroup());
EditorUtility.ClearProgressBar();
return;
}
for (int x = start; x < end; x++)
{
for (int y = start; y < end; y++)
{
partSplat[x, y, s] = terrainSplat[x + splatShift * xI, y + splatShift * yI, s];
}
}
}
newTerrain.terrainData.SetAlphamaps(0, 0, partSplat);
td.SetDetailResolution(terrain.terrainData.detailResolution / _terrainManagerSettings.splitSize,
terrain.terrainData.detailResolutionPerPatch);
int detailShift = terrain.terrainData.detailResolution / _terrainManagerSettings.splitSize;
for (int d = 0; d < terrain.terrainData.detailPrototypes.Length; d++)
{
bool cancel = EditorUtility.DisplayCancelableProgressBar(progressCaption,
progressText + " (Processing detail " + d + ")",
progress + (3 / 5f + (d / (float)terrain.terrainData.detailPrototypes.Length) / 5f) /
(float)_terrainManagerSettings.terrainsCount);
if (cancel)
{
Undo.CollapseUndoOperations(Undo.GetCurrentGroup());
EditorUtility.ClearProgressBar();
return;
}
int[,] terrainDetail = terrain.terrainData.GetDetailLayer(0, 0,
terrain.terrainData.detailResolution, terrain.terrainData.detailResolution, d);
int[,] partDetail = new int[detailShift, detailShift];
startX = startY = 0;
for (int x = startX; x < detailShift; x++)
{
for (int y = startY; y < detailShift; y++)
{
int detail = terrainDetail[x + detailShift * xI, y + detailShift * yI];
partDetail[x, y] = detail;
}
}
newTerrain.terrainData.SetDetailLayer(0, 0, d, partDetail);
}
float sizeCheckX = size * xI;
float sizeCheckX1 = size * (xI + 1);
float sizeCheckY = size * yI;
float sizeCheckY1 = size * (yI + 1);
treeInstances = terrain.terrainData.treeInstances;
treeInstancesList.Clear();
for (int t = 0; t < treeInstances.Length; t++)
{
if (t % 1000 == 0)
{
bool cancel = EditorUtility.DisplayCancelableProgressBar(progressCaption,
progressText + " (Processing trees " + t + "/" + treeInstances.Length + ")",
progress + (4 / 5f + ((float)t / treeInstances.Length) / 5f) /
(float)_terrainManagerSettings.terrainsCount);
if (cancel)
{
Undo.CollapseUndoOperations(Undo.GetCurrentGroup());
EditorUtility.ClearProgressBar();
return;
}
}
ti = treeInstances[t];
if (ti.position.x >= sizeCheckY && ti.position.x <= sizeCheckY1 &&
ti.position.z >= sizeCheckX && ti.position.z <= sizeCheckX1)
{
ti.position = new Vector3((ti.position.x * _terrainManagerSettings.splitSize) % 1,
ti.position.y, (ti.position.z * _terrainManagerSettings.splitSize) % 1);
treeInstancesList.Add(ti);
}
}
//Debug.Log("end");
newTerrain.terrainData.SetTreeInstances(treeInstancesList.ToArray(), true);
newTerrain.gameObject.AddComponent<TerrainCullingSystem>();
tgo.transform.position = parentPosition + new Vector3(tgo.transform.position.x + zWShift,
tgo.transform.position.y,
tgo.transform.position.z + xWShift);
/*
tgo.transform.position = new Vector3(tgo.transform.position.x + parentPosition.x,
tgo.transform.position.y + parentPosition.y,
tgo.transform.position.z + parentPosition.z
);
*/
terrain.gameObject.SetActive(false);
AssetDatabase.SaveAssets();
GC.Collect();
}
EditorUtility.ClearProgressBar();
}
Undo.CollapseUndoOperations(Undo.GetCurrentGroup());
}
}
}