310 lines
8.6 KiB
C#
310 lines
8.6 KiB
C#
using UnityEditor;
|
|
using UnityEngine;
|
|
using System.Collections;
|
|
using System.IO;
|
|
|
|
/*
|
|
Tom's Terrain Tools for Unity 3D
|
|
Incremental Splatmapping
|
|
version 1.0 - February 2015
|
|
|
|
(C)2015 by Tom Vogt <tom@lemuria.org>
|
|
|
|
http://lemuria.org/Unity/TTT/
|
|
|
|
*/
|
|
|
|
public class IncrementalSplatmapping : EditorWindow {
|
|
|
|
public Terrain MyTerrain;
|
|
|
|
public Texture2D Splatmap;
|
|
public Texture2D TextureRed;
|
|
public Texture2D TextureGreen;
|
|
public Texture2D TextureBlue;
|
|
public int TileSizeRed = 40;
|
|
public int TileSizeGreen = 40;
|
|
public int TileSizeBlue = 40;
|
|
|
|
public float bias = 1.0f;
|
|
public bool Replacing = false;
|
|
|
|
// internal variables
|
|
Vector2 scrollPosition = new Vector2(0,0);
|
|
|
|
|
|
[MenuItem("Window/Terrain Tools/Incremental Splatmapping",false,100)]
|
|
|
|
static void Init() {
|
|
IncrementalSplatmapping window = (IncrementalSplatmapping)EditorWindow.GetWindow(typeof(IncrementalSplatmapping));
|
|
window.minSize = new Vector2(400,550);
|
|
window.Show();
|
|
}
|
|
|
|
void OnInspectorUpdate() {
|
|
Repaint();
|
|
}
|
|
|
|
void OnGUI() {
|
|
EditorGUILayout.BeginVertical(GUI.skin.box, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true));
|
|
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition, GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true));
|
|
|
|
GUILayout.Label("Incremental Splatmapping",EditorStyles.boldLabel);
|
|
EditorGUILayout.Separator();
|
|
|
|
// bold titles
|
|
GUIStyle myFoldoutStyle = new GUIStyle(EditorStyles.foldout);
|
|
myFoldoutStyle.fontStyle = FontStyle.Bold;
|
|
|
|
EditorGUILayout.Separator();
|
|
GUILayout.BeginHorizontal();
|
|
GUILayout.Label("Terrain");
|
|
MyTerrain = (Terrain)EditorGUILayout.ObjectField("", MyTerrain, typeof(Terrain),true);
|
|
GUILayout.EndHorizontal();
|
|
|
|
EditorGUILayout.Separator();
|
|
|
|
GUILayout.BeginHorizontal();
|
|
EditorGUILayout.PrefixLabel("Splatmap");
|
|
GUILayout.FlexibleSpace();
|
|
Splatmap = (Texture2D)EditorGUILayout.ObjectField("", Splatmap, typeof(Texture2D),false);
|
|
GUILayout.EndHorizontal();
|
|
|
|
EditorGUILayout.Separator();
|
|
|
|
GUILayout.BeginHorizontal();
|
|
EditorGUILayout.PrefixLabel("Texture Red");
|
|
GUILayout.FlexibleSpace();
|
|
TextureRed = (Texture2D)EditorGUILayout.ObjectField("", TextureRed, typeof(Texture2D),false);
|
|
GUILayout.EndHorizontal();
|
|
|
|
GUILayout.BeginHorizontal();
|
|
GUILayout.Label("Tile Size Red");
|
|
GUILayout.FlexibleSpace();
|
|
TileSizeRed = EditorGUILayout.IntSlider(TileSizeRed, 4, 512);
|
|
GUILayout.EndHorizontal();
|
|
|
|
EditorGUILayout.Separator();
|
|
|
|
GUILayout.BeginHorizontal();
|
|
EditorGUILayout.PrefixLabel("Texture Green");
|
|
GUILayout.FlexibleSpace();
|
|
TextureGreen = (Texture2D)EditorGUILayout.ObjectField("", TextureGreen, typeof(Texture2D),false);
|
|
GUILayout.EndHorizontal();
|
|
|
|
GUILayout.BeginHorizontal();
|
|
GUILayout.Label("Tile Size Green");
|
|
GUILayout.FlexibleSpace();
|
|
TileSizeGreen = EditorGUILayout.IntSlider(TileSizeGreen, 4, 512);
|
|
GUILayout.EndHorizontal();
|
|
|
|
EditorGUILayout.Separator();
|
|
|
|
GUILayout.BeginHorizontal();
|
|
EditorGUILayout.PrefixLabel("Texture Blue");
|
|
GUILayout.FlexibleSpace();
|
|
TextureBlue = (Texture2D)EditorGUILayout.ObjectField("", TextureBlue, typeof(Texture2D),false);
|
|
GUILayout.EndHorizontal();
|
|
|
|
GUILayout.BeginHorizontal();
|
|
GUILayout.Label("Tile Size Blue");
|
|
GUILayout.FlexibleSpace();
|
|
TileSizeBlue = EditorGUILayout.IntSlider(TileSizeBlue, 4, 512);
|
|
GUILayout.EndHorizontal();
|
|
|
|
EditorGUILayout.Separator();
|
|
|
|
GUILayout.BeginHorizontal();
|
|
GUILayout.Label("Strength of this layer");
|
|
GUILayout.FlexibleSpace();
|
|
bias = EditorGUILayout.Slider(bias, 0.1f, 10.0f);
|
|
GUILayout.EndHorizontal();
|
|
|
|
EditorGUILayout.Separator();
|
|
|
|
GUILayout.BeginHorizontal();
|
|
GUILayout.Label("replace old textures");
|
|
GUILayout.FlexibleSpace();
|
|
Replacing = EditorGUILayout.Toggle ("", Replacing);
|
|
GUILayout.EndHorizontal();
|
|
|
|
EditorGUILayout.Separator();
|
|
|
|
GUILayout.BeginHorizontal();
|
|
GUILayout.FlexibleSpace();
|
|
if (GUILayout.Button("Add Splat Texture",GUILayout.Width(200), GUILayout.Height(32))) {
|
|
if (CheckSplatmap()) {
|
|
AddSplatTexture();
|
|
}
|
|
}
|
|
GUILayout.FlexibleSpace();
|
|
GUILayout.EndHorizontal();
|
|
|
|
EditorGUILayout.EndScrollView();
|
|
EditorGUILayout.EndVertical();
|
|
}
|
|
|
|
|
|
void FixFormat(Texture2D texture) {
|
|
string path = AssetDatabase.GetAssetPath(texture);
|
|
TextureImporter textureImporter = AssetImporter.GetAtPath(path) as TextureImporter;
|
|
if (texture.format != TextureFormat.RGB24 || !textureImporter.isReadable)
|
|
{
|
|
textureImporter.mipmapEnabled = false;
|
|
textureImporter.isReadable = true;
|
|
textureImporter.textureFormat = TextureImporterFormat.RGB24;
|
|
AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
|
|
Debug.Log("fixed texture format for "+path);
|
|
}
|
|
}
|
|
|
|
public string Reverse(string text) {
|
|
if (text == null) return null;
|
|
|
|
// this was posted by petebob as well
|
|
char[] array = text.ToCharArray();
|
|
System.Array.Reverse(array);
|
|
return new string(array);
|
|
}
|
|
public string FindFile(string basename) {
|
|
string[] extensions = {"tif", "tiff", "png", "jpg", "jpeg"};
|
|
foreach (string ext in extensions) {
|
|
string filename = basename + "." + ext;
|
|
if (File.Exists(filename)) {
|
|
return filename;
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
|
|
bool CheckSplatmap() {
|
|
if (Splatmap==null) return false;
|
|
FixFormat(Splatmap);
|
|
|
|
if (Splatmap.height != Splatmap.width) {
|
|
EditorUtility.DisplayDialog("Wrong size", "Splatmap must be square (width and height must be the same)", "Cancel");
|
|
return false;
|
|
}
|
|
if (Mathf.ClosestPowerOfTwo(Splatmap.width) != Splatmap.width) {
|
|
EditorUtility.DisplayDialog("Wrong size", "Splatmap width and height must be a power of two", "Cancel");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void AddSplatTexture()
|
|
{
|
|
if (!MyTerrain) MyTerrain = Terrain.activeTerrain;
|
|
TerrainData terrain = MyTerrain.terrainData;
|
|
|
|
int splaMaptWidth = Splatmap.width;
|
|
if (splaMaptWidth!=terrain.alphamapWidth)
|
|
{
|
|
Debug.LogError("New splatmap is not same resolution as the current terrain splatmap ("+splaMaptWidth+" != "+terrain.alphamapWidth+")");
|
|
return;
|
|
}
|
|
|
|
Undo.RecordObject(terrain, "Add Splattexture");
|
|
Color[] SplatmapColors = Splatmap.GetPixels();
|
|
int layer = MyTerrain.terrainData.alphamapLayers;
|
|
|
|
int add_layers = 0;
|
|
int red_layer = layer;
|
|
int green_layer = layer+1;
|
|
int blue_layer = layer+2;
|
|
|
|
if (TextureRed) {
|
|
AddTexture(TextureRed, TileSizeRed);
|
|
add_layers++;
|
|
}
|
|
if (TextureGreen) {
|
|
AddTexture(TextureGreen, TileSizeGreen);
|
|
green_layer = layer + add_layers;
|
|
add_layers++;
|
|
}
|
|
if (TextureBlue) {
|
|
AddTexture(TextureBlue, TileSizeBlue);
|
|
blue_layer = layer + add_layers;
|
|
add_layers++;
|
|
}
|
|
float[,,] splatmapData = terrain.GetAlphamaps(0, 0, splaMaptWidth, splaMaptWidth);
|
|
|
|
for (int y = 0; y < splaMaptWidth; y++) {
|
|
if (y%10 == 0) {
|
|
EditorUtility.DisplayProgressBar("add splat", "updating terrain", Mathf.InverseLerp(0.0f, (float)splaMaptWidth, (float)y));
|
|
}
|
|
for (int x = 0; x < splaMaptWidth; x++) {
|
|
float red = SplatmapColors[x*splaMaptWidth + y].r * bias;
|
|
float green = SplatmapColors[x*splaMaptWidth + y].g * bias;
|
|
float blue = SplatmapColors[x*splaMaptWidth + y].b * bias;
|
|
float value = 0.0f;
|
|
|
|
if (TextureRed) {
|
|
if (red>0.0f) {
|
|
splatmapData[x,y,red_layer] = red;
|
|
value+=red;
|
|
} else {
|
|
splatmapData[x,y,red_layer] = 0.0f;
|
|
}
|
|
}
|
|
|
|
if (TextureGreen) {
|
|
if (green>0.0f) {
|
|
splatmapData[x,y,green_layer] = green;
|
|
value+=green;
|
|
} else {
|
|
splatmapData[x,y,green_layer] = 0.0f;
|
|
}
|
|
}
|
|
|
|
if (TextureBlue) {
|
|
if (blue>0.0f) {
|
|
splatmapData[x,y,blue_layer] = blue;
|
|
value+=blue;
|
|
} else {
|
|
splatmapData[x,y,blue_layer] = 0.0f;
|
|
}
|
|
}
|
|
|
|
// normalize
|
|
float total = 0.0f;
|
|
for (int l = 0; l < layer+add_layers; l++) {
|
|
if (Replacing && value >= 1.0f && l < layer) {
|
|
splatmapData[x,y,l] = 0;
|
|
}
|
|
total += splatmapData[x,y,l];
|
|
}
|
|
if (total != 1.0f) {
|
|
for (int l = 0; l < layer+add_layers; l++) {
|
|
splatmapData[x,y,l] *= 1.0f/total;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
terrain.SetAlphamaps(0, 0, splatmapData);
|
|
EditorUtility.SetDirty(MyTerrain);
|
|
Debug.Log("Splatmap texture applied");
|
|
|
|
EditorUtility.ClearProgressBar();
|
|
}
|
|
|
|
void AddTexture(Texture2D Texture, int TileSize)
|
|
{
|
|
SplatPrototype[] oldPrototypes = MyTerrain.terrainData.splatPrototypes;
|
|
SplatPrototype[] newPrototypes = new SplatPrototype[oldPrototypes.Length + 1];
|
|
for (int x=0;x<oldPrototypes.Length;x++) {
|
|
newPrototypes[x] = oldPrototypes[x];
|
|
}
|
|
newPrototypes[oldPrototypes.Length] = new SplatPrototype();
|
|
newPrototypes[oldPrototypes.Length].texture = Texture;
|
|
Vector2 vector = new Vector2(TileSize, TileSize);
|
|
newPrototypes[oldPrototypes.Length].tileSize = vector;
|
|
MyTerrain.terrainData.splatPrototypes = newPrototypes;
|
|
}
|
|
|
|
}
|
|
|