141 lines
5.4 KiB
C#
141 lines
5.4 KiB
C#
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Linq;
|
||
|
using UnityEditor;
|
||
|
|
||
|
namespace UnityEngine.TerrainTools
|
||
|
{
|
||
|
[Serializable]
|
||
|
internal class Layer
|
||
|
{
|
||
|
public bool IsSelected;
|
||
|
public TerrainLayer AssignedLayer;
|
||
|
}
|
||
|
|
||
|
internal class TerrainToolboxLayer
|
||
|
{
|
||
|
// add a list of terrain layers to terrain, and have an option of clear existing ones
|
||
|
public static void AddLayersToTerrain(TerrainData terrainData, List<TerrainLayer> layers, bool clearExisting)
|
||
|
{
|
||
|
if (terrainData == null || layers == null)
|
||
|
return;
|
||
|
|
||
|
if (clearExisting)
|
||
|
{
|
||
|
terrainData.SetTerrainLayersRegisterUndo(layers.ToArray(), "Clearing layers");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// check and remove existing layers
|
||
|
var filteredLayers = layers.Where(i => !terrainData.terrainLayers.Contains(i)).ToArray();
|
||
|
int oldLength = terrainData.terrainLayers.Length;
|
||
|
int newLength = oldLength + filteredLayers.Length;
|
||
|
var newArray = new TerrainLayer[newLength];
|
||
|
terrainData.terrainLayers.CopyTo(newArray, 0);
|
||
|
filteredLayers.CopyTo(newArray, oldLength);
|
||
|
terrainData.SetTerrainLayersRegisterUndo(newArray, "Add terrain layers");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// add layer to terrain
|
||
|
public static void AddLayerToTerrain(TerrainData terrainData, TerrainLayer inputLayer)
|
||
|
{
|
||
|
if (inputLayer == null)
|
||
|
return;
|
||
|
|
||
|
var layers = terrainData.terrainLayers;
|
||
|
for (var idx = 0; idx < layers.Length; ++idx)
|
||
|
{
|
||
|
if (layers[idx] == inputLayer)
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
int newIndex = layers.Length;
|
||
|
var newarray = new TerrainLayer[newIndex + 1];
|
||
|
Array.Copy(layers, 0, newarray, 0, newIndex);
|
||
|
newarray[newIndex] = inputLayer;
|
||
|
terrainData.SetTerrainLayersRegisterUndo(newarray, "Add terrain layer");
|
||
|
}
|
||
|
|
||
|
public static void CopyTerrainLayers(Terrain fromTerrain, Terrain toTerrain)
|
||
|
{
|
||
|
// wipe out existing layers and splatmaps
|
||
|
RemoveAllLayers(toTerrain.terrainData);
|
||
|
|
||
|
toTerrain.terrainData.terrainLayers = fromTerrain.terrainData.terrainLayers;
|
||
|
}
|
||
|
|
||
|
public static void RemoveAllLayers(TerrainData terrainData)
|
||
|
{
|
||
|
terrainData.SetTerrainLayersRegisterUndo(new TerrainLayer[0], "Remove All terrain layer");
|
||
|
}
|
||
|
|
||
|
// remove a single layer and clear splatmap
|
||
|
public static void RemoveLayerFromTerrain(TerrainData terrainData, int index)
|
||
|
{
|
||
|
|
||
|
int width = terrainData.alphamapWidth;
|
||
|
int height = terrainData.alphamapHeight;
|
||
|
float[,,] alphamap = terrainData.GetAlphamaps(0, 0, width, height);
|
||
|
int alphaCount = alphamap.GetLength(2);
|
||
|
|
||
|
int newAlphaCount = alphaCount - 1;
|
||
|
float[,,] newalphamap = new float[height, width, newAlphaCount];
|
||
|
|
||
|
// move further alphamaps one index below
|
||
|
for (int y = 0; y < height; ++y)
|
||
|
{
|
||
|
for (int x = 0; x < width; ++x)
|
||
|
{
|
||
|
for (int a = 0; a < index; ++a)
|
||
|
newalphamap[y, x, a] = alphamap[y, x, a];
|
||
|
for (int a = index + 1; a < alphaCount; ++a)
|
||
|
newalphamap[y, x, a - 1] = alphamap[y, x, a];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// normalize weights in new alpha map
|
||
|
for (int y = 0; y < height; ++y)
|
||
|
{
|
||
|
for (int x = 0; x < width; ++x)
|
||
|
{
|
||
|
float sum = 0.0F;
|
||
|
for (int a = 0; a < newAlphaCount; ++a)
|
||
|
sum += newalphamap[y, x, a];
|
||
|
if (sum >= 0.01)
|
||
|
{
|
||
|
float multiplier = 1.0F / sum;
|
||
|
for (int a = 0; a < newAlphaCount; ++a)
|
||
|
newalphamap[y, x, a] *= multiplier;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// in case all weights sum to pretty much zero (e.g.
|
||
|
// removing splat that had 100% weight), assign
|
||
|
// everything to 1st splat texture (just like
|
||
|
// initial terrain).
|
||
|
for (int a = 0; a < newAlphaCount; ++a)
|
||
|
newalphamap[y, x, a] = (a == 0) ? 1.0f : 0.0f;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// remove splat from terrain prototypes
|
||
|
var layers = terrainData.terrainLayers;
|
||
|
var newSplats = new TerrainLayer[layers.Length - 1];
|
||
|
for (int a = 0; a < index; ++a)
|
||
|
newSplats[a] = layers[a];
|
||
|
for (int a = index + 1; a < alphaCount; ++a)
|
||
|
newSplats[a - 1] = layers[a];
|
||
|
int group = Undo.GetCurrentGroup();
|
||
|
Undo.SetCurrentGroupName("Remove terrain layer");
|
||
|
terrainData.SetTerrainLayersRegisterUndo(newSplats, "Remove Layer");
|
||
|
var undoObjects = new List<Object>();
|
||
|
undoObjects.AddRange(terrainData.alphamapTextures);
|
||
|
Undo.RegisterCompleteObjectUndo(undoObjects.ToArray(), "Apply Modified Alphamaps");
|
||
|
Undo.CollapseUndoOperations(Undo.GetCurrentGroup());
|
||
|
terrainData.SetAlphamaps(0, 0, newalphamap);
|
||
|
}
|
||
|
}
|
||
|
}
|