265 lines
6.4 KiB
C#
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);
|
|
}
|
|
|
|
|
|
}
|
|
} |