Created
February 24, 2024 16:02
-
-
Save m-biernat/9c357afe55fcd662be6491e64ba7ded1 to your computer and use it in GitHub Desktop.
A simple Unity Editor tool that converts trees in a Terrain into GameObjects
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This is a simple Unity Editor tool that converts trees in a Terrain (with multi-terrain support) into GameObjects. | |
// It should be placed in the Assets/Editor directory. Do not use it without any VCS! | |
// Copyright (c) 2023 Michał Biernat @m-biernat, licensed under the MIT License. | |
using System.Collections.Generic; | |
using UnityEditor; | |
using UnityEngine; | |
public class TreeToGameObjectConverter : EditorWindow | |
{ | |
readonly string _rootName = "CONVERTED TREES"; | |
GameObject _root; | |
List<Terrain> _terrainList; | |
[MenuItem("Tools/Tree to GameObject Converter")] | |
public static void ShowEditorWindow() | |
{ | |
EditorWindow window = GetWindow<TreeToGameObjectConverter>(); | |
window.titleContent = new GUIContent("Tree to GameObject Converter"); | |
} | |
void OnGUI() | |
{ | |
if (GUILayout.Button("Add Selected Terrain Objects", GUILayout.Height(40))) | |
AddSelectedTerrainObjects(); | |
GUILayout.Space(10); | |
GUILayout.BeginHorizontal(); | |
GUILayout.FlexibleSpace(); | |
if (_terrainList == null || _terrainList.Count == 0) | |
GUILayout.Label("No Terrain Objects Selected"); | |
else | |
GUILayout.Label($"Currently Selected {_terrainList.Count} Terrain Objects"); | |
GUILayout.FlexibleSpace(); | |
GUILayout.EndHorizontal(); | |
GUILayout.Space(10); | |
if (GUILayout.Button($"Convert Trees into GameObjects", GUILayout.Height(40))) | |
ConvertTreesToGameObjects(); | |
if (GUILayout.Button($"Remove \"{_rootName}\"", GUILayout.Height(40))) | |
RemoveConverted(); | |
GUILayout.Space(10); | |
GUI.color = Color.red; | |
if (GUILayout.Button($"Remove Trees from Terrain Objects", GUILayout.Height(40))) | |
RemoveTrees(); | |
} | |
void AddSelectedTerrainObjects() | |
{ | |
_terrainList = new List<Terrain>(); | |
foreach (var selectedGO in Selection.gameObjects) | |
{ | |
Terrain terrain; | |
if (selectedGO.TryGetComponent(out terrain)) | |
_terrainList.Add(terrain); | |
} | |
} | |
void ConvertTreesToGameObjects() | |
{ | |
if (GetRoot() == null) | |
_root = new GameObject(_rootName); | |
else | |
{ | |
Debug.LogError($"Object with the name \"{_rootName}\" already exists"); | |
return; | |
} | |
int numOfTrees = 0; | |
foreach (var terrain in _terrainList) | |
{ | |
numOfTrees += ConvertTrees(terrain); | |
} | |
Debug.Log($"Converted {numOfTrees} Trees into GameObjects"); | |
} | |
GameObject GetRoot() | |
=> GameObject.Find(_rootName); | |
int ConvertTrees(Terrain terrain) | |
{ | |
var treeInstances = terrain.terrainData.treeInstances; | |
var treePrototypes = terrain.terrainData.treePrototypes; | |
if (treeInstances.Length == 0 && treePrototypes.Length == 0) | |
return 0; | |
var parent = new GameObject(terrain.name); | |
parent.transform.position = terrain.transform.position; | |
parent.transform.SetParent(_root.transform); | |
foreach (var treeInstance in treeInstances) | |
{ | |
var treePrototype = treePrototypes[treeInstance.prototypeIndex]; | |
var go = Instantiate(treePrototype.prefab, parent.transform); | |
go.transform.localPosition = Vector3.Scale(treeInstance.position, | |
terrain.terrainData.size); | |
go.transform.localScale = new Vector3(treeInstance.widthScale, | |
treeInstance.widthScale, | |
treeInstance.heightScale); | |
go.transform.Rotate(0, treeInstance.rotation * Mathf.Rad2Deg, 0); | |
} | |
return treeInstances.Length; | |
} | |
void RemoveTrees() | |
{ | |
foreach (var terrain in _terrainList) | |
{ | |
terrain.terrainData.treeInstances = new TreeInstance[0]; | |
terrain.terrainData.treePrototypes = new TreePrototype[0]; | |
} | |
} | |
void RemoveConverted() | |
=> DestroyImmediate(GetRoot()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment