NewN_UAVPlane/Assets/Tom's Terrain Tools/Editor/SplatMapGenerator.cs

265 lines
6.4 KiB
C#

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.IO;
// create splatmaps from existing terrain, work in progress, not much features here yet
namespace TTT_Tools
{
public class SplatMapGenerator : EditorWindow
{
Terrain myTerrain;
// options
float redThresholdMin=0f;
float redThresholdMax=25f;
float greenThresholdMin=25f;
float greenThresholdMax=75f;
float blueThresholdMin=75f;
float blueThresholdMax=100f;
float minHeight=0f;
float maxHeight=100f;
float? lowestPoint=null;
float? highestPoint=null;
[MenuItem ("Window/Terrain Tools/Create Splatmap from Terrain",false,105)]
public static void ShowWindow ()
{
var window = EditorWindow.GetWindow(typeof(SplatMapGenerator));
window.titleContent = new GUIContent("SplatmapGenerator");
window.minSize = new Vector2(450,300);
}
void OnGUI ()
{
DrawGUITitle();
DrawGUITerrainSelection();
DrawGUISettings();
}
void DrawGUITitle ()
{
GUILayout.BeginHorizontal ();
GUILayout.Label ("Splatmap Generator", EditorStyles.boldLabel);
GUILayout.EndHorizontal ();
EditorGUILayout.Separator ();
}
void DrawGUITerrainSelection()
{
GUILayout.BeginHorizontal();
GUILayout.Label("Terrain");
myTerrain = (Terrain)EditorGUILayout.ObjectField("", myTerrain, typeof(Terrain),true);
GUILayout.EndHorizontal();
EditorGUILayout.Separator();
}
void DrawGUISettings()
{
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
GUILayout.Label("World height");
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.Label(lowestPoint!=null?((int)lowestPoint).ToString("0"):"-");
GUILayout.FlexibleSpace();
GUILayout.Label(highestPoint!=null?((int)highestPoint).ToString("0"):"-");
GUILayout.EndHorizontal();
GUI.enabled = false;
GUILayout.BeginHorizontal();
GUILayout.Label("R",GUILayout.Width(20));
EditorGUILayout.MinMaxSlider(ref redThresholdMin,ref redThresholdMax,minHeight,maxHeight);
GUILayout.EndHorizontal();
redThresholdMin=0;
redThresholdMax=greenThresholdMin;
GUI.enabled = true;
GUILayout.BeginHorizontal();
GUILayout.Label("G",GUILayout.Width(20));
EditorGUILayout.MinMaxSlider(ref greenThresholdMin,ref greenThresholdMax,minHeight,maxHeight);
GUILayout.EndHorizontal();
GUI.enabled = false;
GUILayout.BeginHorizontal();
GUILayout.Label("B",GUILayout.Width(20));
EditorGUILayout.MinMaxSlider(ref blueThresholdMin,ref blueThresholdMax,minHeight,maxHeight);
GUILayout.EndHorizontal();
blueThresholdMin=greenThresholdMax;
blueThresholdMax = maxHeight;
GUI.enabled = true;
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
//float val = (greenThresholdMax-greenThresholdMin);
if (lowestPoint!=null)
{
float val = Mathf.Lerp((float)lowestPoint,(float)highestPoint,greenThresholdMin/100f);
GUILayout.Label(((int)val).ToString("0"));
GUILayout.FlexibleSpace();
val = Mathf.Lerp((float)lowestPoint,(float)highestPoint,greenThresholdMax/100f);
GUILayout.Label(((int)val).ToString("0"));
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button ("Generate Splatmap", GUILayout.Width (200), GUILayout.Height (32)))
{
GenerateSplatmap();
}
GUILayout.FlexibleSpace ();
GUILayout.EndHorizontal ();
}
void GenerateSplatmap()
{
if (!ValidateTerrain()) return;
// TODO: read heightdata
var terrainData = myTerrain.terrainData;
var width = terrainData.heightmapResolution;
var length = terrainData.heightmapResolution;
// var height = terrainData.size.y;
var newSplatmap = new Texture2D(width,length,TextureFormat.RGB24,false);
var pixels = newSplatmap.GetPixels();
Vector2 terrainBounds = GetTerrainHeightRange();
lowestPoint = terrainBounds.x;
highestPoint = terrainBounds.y;
float worldHeight = 0;
float normalizedHeight=0;
float r=0,g=0,b=0;
for (int x = 0; x < width; x++)
{
for (int y = 0; y < length; y++)
{
worldHeight = terrainData.GetHeight(y,x);
normalizedHeight = Remap(worldHeight,lowestPoint,highestPoint,0,100);
if (normalizedHeight<=redThresholdMax)
{
r=1;
}else{
r=0;
}
if (normalizedHeight>=greenThresholdMin && normalizedHeight<=greenThresholdMax)
{
g=1;
}else{
g=0;
}
if (normalizedHeight>=blueThresholdMin)
{
b=1;
}else{
b=0;
}
pixels[x*width+y] = new Color(r,g,b,0);
}
}
newSplatmap.SetPixels(pixels);
newSplatmap.Apply(false);
byte[] texBytes = newSplatmap.EncodeToPNG();
string basename = Path.GetFileNameWithoutExtension(terrainData.name);
string fullPath = AssetDatabase.GetAssetPath(terrainData);
string assetDirectory = Path.GetDirectoryName(fullPath);
fullPath = Path.Combine(assetDirectory, basename);
string savePath = Path.GetDirectoryName(fullPath) + "/" + basename +"_splatmap.png";
File.WriteAllBytes(savePath, texBytes);
AssetDatabase.Refresh();
Debug.Log("New splatmap saved to: "+savePath);
DestroyImmediate(newSplatmap);
}
// checks if terrain is assigned and terrainData is accessible
bool ValidateTerrain()
{
if (myTerrain==null)
{
Debug.LogError("No terrain assigned");
return false;
}
if (myTerrain.terrainData==null)
{
Debug.LogError("Unable to get terrainData from "+myTerrain.name);
return false;
}
return true;
}
// HELPERS
float Remap(float source, float sourceFrom, float sourceTo, float targetFrom, float targetTo)
{
return targetFrom + (source-sourceFrom)*(targetTo-targetFrom)/(sourceTo-sourceFrom);
}
float Remap(float source, float? sourceFrom, float? sourceTo, float targetFrom, float targetTo)
{
return (float)(targetFrom + (source-sourceFrom)*(targetTo-targetFrom)/(sourceTo-sourceFrom));
}
// returns min and max height
Vector2 GetTerrainHeightRange()
{
var terrainData = myTerrain.terrainData;
var width = terrainData.heightmapResolution;
var length = terrainData.heightmapResolution;
float minY = Mathf.Infinity;
float maxY = Mathf.NegativeInfinity;
for (int x = 0; x < width; x++)
{
for (int y = 0; y < length; y++)
{
float worldHeight = terrainData.GetHeight(y,x);
minY = Mathf.Min(worldHeight,minY);
maxY = Mathf.Max(worldHeight,maxY);
}
}
return new Vector2(minY,maxY);
}
}
}