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;
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
 |