198 lines
6.1 KiB
JavaScript
198 lines
6.1 KiB
JavaScript
|
/*
|
||
|
* Copyright (c) 2011 Reijer Hooijkaas.
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* Contact: reijerh AT gmail.com
|
||
|
*
|
||
|
* TERRAIN STITCHER v1.1
|
||
|
*
|
||
|
* TerrainStitcher is free for private, non-commercial use only, please
|
||
|
* refer to License.txt for conditions that apply to commercial use.
|
||
|
*/
|
||
|
|
||
|
class TerrainStitcherWindow extends EditorWindow {
|
||
|
var terrain1 : Terrain;
|
||
|
var terrain2 : Terrain;
|
||
|
var numSamplesAuto = 20;
|
||
|
var numSamplesManual = 20;
|
||
|
var dominatingTerrain = 0;
|
||
|
|
||
|
var setAutoSamples = false;
|
||
|
var setManualSamples = false;
|
||
|
|
||
|
@MenuItem ("Terrain/Terrain Stitcher...")
|
||
|
static function Init () {
|
||
|
// Get existing open window or if none, make a new one:
|
||
|
var window : TerrainStitcherWindow = EditorWindow.GetWindow(TerrainStitcherWindow);
|
||
|
}
|
||
|
|
||
|
function OnSelectionChange() {
|
||
|
Repaint();
|
||
|
}
|
||
|
|
||
|
function findNeighbors(terrain : GameObject, gameObjects, originalPositions) {
|
||
|
var neighbors = new Array();
|
||
|
|
||
|
var thisPos = originalPositions[terrain];
|
||
|
var width = terrain.GetComponent(Terrain).terrainData.size.x;
|
||
|
|
||
|
for (var go : GameObject in gameObjects) {
|
||
|
if (terrain == go)
|
||
|
continue;
|
||
|
|
||
|
var pos = originalPositions[go];
|
||
|
|
||
|
var diffX = pos.x - thisPos.x;
|
||
|
var diffZ = pos.z - thisPos.z;
|
||
|
|
||
|
// A neighbor is positioned N, E, S or W of this terrain
|
||
|
if (((diffZ >= width && diffZ < 1.5 * width) && (diffX > -0.5 * width && diffX < 0.5 * width)) || // N
|
||
|
((diffZ > -0.5 * width && diffZ < 0.5 * width) && (diffX >= width && diffX < width * 1.5)) || // E
|
||
|
((diffZ <= -width && diffZ > -1.5 * width) && (diffX > -0.5 * width && diffX < 0.5 * width)) || // S
|
||
|
((diffZ > -0.5 * width && diffZ < 0.5 * width) && (diffX <= -width && diffX > -1.5 * width))) // W
|
||
|
neighbors.Add(go);
|
||
|
}
|
||
|
|
||
|
return neighbors;
|
||
|
}
|
||
|
|
||
|
function stitchTerrains(terrains, numSamples) {
|
||
|
var originalPositions = new Hashtable();
|
||
|
for (var go : GameObject in terrains) {
|
||
|
var pos = go.GetComponent(Terrain).transform.position;
|
||
|
originalPositions.Add(go, pos);
|
||
|
}
|
||
|
|
||
|
var affectedTerrains = new ArrayList();
|
||
|
var visitedTerrains = new ArrayList();
|
||
|
var performedStitches = new Hashtable();
|
||
|
|
||
|
do {
|
||
|
for (var go : GameObject in terrains) {
|
||
|
if (performedStitches[go] == null)
|
||
|
performedStitches[go] = new ArrayList();
|
||
|
|
||
|
var neighbors = findNeighbors(go, terrains, originalPositions);
|
||
|
// If we have no neighbors we don't need stitching
|
||
|
if (neighbors.length == 0) {
|
||
|
visitedTerrains.Add(go);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Terrain must be the first or already affected by another terrain to be allowed
|
||
|
// to dominate another terrain
|
||
|
if (!((affectedTerrains.Count == 0 || affectedTerrains.Contains(go)) &&
|
||
|
!visitedTerrains.Contains(go)))
|
||
|
continue;
|
||
|
|
||
|
if (EditorUtility.DisplayCancelableProgressBar("Stitching terrains...", "",
|
||
|
parseFloat(visitedTerrains.Count) / terrains.length)) {
|
||
|
EditorUtility.ClearProgressBar();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (var neighbor : GameObject in neighbors) {
|
||
|
// No need to stitch if we are already stitched
|
||
|
if (performedStitches[neighbor] != null && performedStitches[neighbor].Contains(go))
|
||
|
continue;
|
||
|
|
||
|
if (TerrainStitcher.stitch(go.GetComponent(Terrain), neighbor.GetComponent(Terrain), numSamples, 1) == -1) {
|
||
|
EditorUtility.DisplayDialog("Terrain dimensions don't match!", "All terrains must have equal dimensions to"
|
||
|
+ " allow stitching.", "OK");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
performedStitches[go].Add(neighbor);
|
||
|
affectedTerrains.Add(neighbor);
|
||
|
}
|
||
|
|
||
|
visitedTerrains.Add(go);
|
||
|
}
|
||
|
} while (visitedTerrains.Count < terrains.length);
|
||
|
|
||
|
EditorUtility.ClearProgressBar();
|
||
|
}
|
||
|
|
||
|
function OnGUI () {
|
||
|
EditorGUILayout.BeginVertical();
|
||
|
|
||
|
/* AUTO STITCHING */
|
||
|
GUILayout.Label("Auto Stitching");
|
||
|
|
||
|
// Every selected object must be a terrain for stitch button to stay enabled
|
||
|
// and at least 2 terrains must be selected
|
||
|
GUI.enabled = true;
|
||
|
var selected = Selection.gameObjects;
|
||
|
var numTerrains = 0;
|
||
|
for (var go : GameObject in selected) {
|
||
|
if (go.GetComponent(Terrain) == null) {
|
||
|
GUI.enabled = false;
|
||
|
break;
|
||
|
} else {
|
||
|
numTerrains++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
EditorGUILayout.BeginHorizontal();
|
||
|
GUILayout.Label("Number of tiles to smooth: ");
|
||
|
|
||
|
if (numTerrains < 2) {
|
||
|
GUI.enabled = false;
|
||
|
setAutoSamples = false;
|
||
|
numSamplesAuto = EditorGUILayout.IntSlider(numSamplesAuto, 0, 0);
|
||
|
} else {
|
||
|
var width = selected[0].GetComponent(Terrain).terrainData.heightmapWidth;
|
||
|
if (!setAutoSamples) {
|
||
|
numSamplesAuto = width / 25 > 0 ? width / 25 : 1;
|
||
|
setAutoSamples = true;
|
||
|
}
|
||
|
numSamplesAuto = EditorGUILayout.IntSlider(numSamplesAuto, 1, width);
|
||
|
}
|
||
|
EditorGUILayout.EndHorizontal();
|
||
|
|
||
|
EditorGUILayout.BeginHorizontal();
|
||
|
if (GUILayout.Button("Stitch Selected"))
|
||
|
stitchTerrains(selected, numSamplesAuto);
|
||
|
EditorGUILayout.EndHorizontal();
|
||
|
|
||
|
EditorGUILayout.Space();
|
||
|
|
||
|
/* MANUAL STITCHING */
|
||
|
GUI.enabled = true;
|
||
|
GUILayout.Label("Manual Stitching");
|
||
|
|
||
|
terrain1 = EditorGUILayout.ObjectField("Terrain 1", terrain1, Terrain, true);
|
||
|
terrain2 = EditorGUILayout.ObjectField("Terrain 2", terrain2, Terrain, true);
|
||
|
|
||
|
EditorGUILayout.BeginHorizontal();
|
||
|
GUILayout.Label(GUIContent("Don't alter corners of terrain: ", "(0 = alter both terrains)"));
|
||
|
dominatingTerrain = EditorGUILayout.IntSlider(dominatingTerrain, 0, 2);
|
||
|
EditorGUILayout.EndHorizontal();
|
||
|
|
||
|
|
||
|
EditorGUILayout.BeginHorizontal();
|
||
|
GUILayout.Label("Number of samples to smooth: ");
|
||
|
|
||
|
if (terrain1 == null || terrain2 == null) {
|
||
|
GUI.enabled = false;
|
||
|
setManualSamples = false;
|
||
|
numSamplesManual = EditorGUILayout.IntSlider(numSamplesManual, 0, 0);
|
||
|
} else {
|
||
|
width = terrain1.terrainData.heightmapWidth;
|
||
|
if (!setManualSamples) {
|
||
|
numSamplesManual = width / 25 > 0 ? width / 25 : 1;
|
||
|
setManualSamples = true;
|
||
|
}
|
||
|
numSamplesManual = EditorGUILayout.IntSlider(numSamplesManual, 1, width);
|
||
|
}
|
||
|
EditorGUILayout.EndHorizontal();
|
||
|
|
||
|
EditorGUILayout.BeginHorizontal();
|
||
|
if (GUILayout.Button("Stitch")) {
|
||
|
TerrainStitcher.stitch(terrain1, terrain2, numSamplesManual, dominatingTerrain);
|
||
|
}
|
||
|
EditorGUILayout.EndHorizontal();
|
||
|
|
||
|
EditorGUILayout.EndVertical();
|
||
|
}
|
||
|
}
|