89 lines
3.0 KiB
C#
89 lines
3.0 KiB
C#
![]() |
using UnityEngine;
|
|||
|
using UnityEditor;
|
|||
|
using System.Collections.Generic;
|
|||
|
|
|||
|
public class ReplacePrefabsWithTerrainTrees : EditorWindow
|
|||
|
{
|
|||
|
Terrain targetTerrain;
|
|||
|
|
|||
|
[MenuItem("Tools/Terrain/Replace Prefabs with Trees")]
|
|||
|
static void ShowWindow()
|
|||
|
{
|
|||
|
GetWindow<ReplacePrefabsWithTerrainTrees>("Replace Prefabs");
|
|||
|
}
|
|||
|
|
|||
|
void OnGUI()
|
|||
|
{
|
|||
|
EditorGUILayout.HelpBox("先在 Project 里选中你想替换的 Prefabs,然后点击按钮。", MessageType.Info);
|
|||
|
|
|||
|
targetTerrain = (Terrain)EditorGUILayout.ObjectField("目标 Terrain", targetTerrain, typeof(Terrain), true);
|
|||
|
|
|||
|
if (GUILayout.Button("替换选中 Prefab 实例为 Terrain 树"))
|
|||
|
{
|
|||
|
if (targetTerrain == null)
|
|||
|
targetTerrain = Terrain.activeTerrain;
|
|||
|
|
|||
|
if (targetTerrain == null)
|
|||
|
{
|
|||
|
Debug.LogError("未指定 Terrain,也未检测到活动地形。");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
ReplacePrefabs();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void ReplacePrefabs()
|
|||
|
{
|
|||
|
Object[] selectedPrefabs = Selection.GetFiltered(typeof(GameObject), SelectionMode.Assets);
|
|||
|
if (selectedPrefabs.Length == 0)
|
|||
|
{
|
|||
|
Debug.LogWarning("你需要在 Project 面板中选择 Prefab!");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
TerrainData terrainData = targetTerrain.terrainData;
|
|||
|
Vector3 terrainPos = targetTerrain.transform.position;
|
|||
|
|
|||
|
List<TreeInstance> newTrees = new List<TreeInstance>(terrainData.treeInstances);
|
|||
|
int count = 0;
|
|||
|
|
|||
|
foreach (GameObject prefab in selectedPrefabs)
|
|||
|
{
|
|||
|
GameObject[] instances = FindObjectsOfType<GameObject>();
|
|||
|
foreach (GameObject obj in instances)
|
|||
|
{
|
|||
|
if (PrefabUtility.GetCorrespondingObjectFromSource(obj) == prefab)
|
|||
|
{
|
|||
|
Vector3 worldPos = obj.transform.position;
|
|||
|
|
|||
|
// 转换为 Terrain 本地坐标(归一化)
|
|||
|
Vector3 normalizedPos = (worldPos - terrainPos);
|
|||
|
normalizedPos.x /= terrainData.size.x;
|
|||
|
normalizedPos.z /= terrainData.size.z;
|
|||
|
normalizedPos.y = 0f;
|
|||
|
|
|||
|
// 选择一个随机树种(TreePrototype)
|
|||
|
int prototypeIndex = Random.Range(0, terrainData.treePrototypes.Length);
|
|||
|
TreeInstance tree = new TreeInstance
|
|||
|
{
|
|||
|
position = new Vector3(normalizedPos.x, 0, normalizedPos.z),
|
|||
|
prototypeIndex = prototypeIndex,
|
|||
|
heightScale = 1f,
|
|||
|
widthScale = 1f,
|
|||
|
color = Color.white,
|
|||
|
lightmapColor = Color.white
|
|||
|
};
|
|||
|
|
|||
|
newTrees.Add(tree);
|
|||
|
Undo.DestroyObjectImmediate(obj);
|
|||
|
count++;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
terrainData.treeInstances = newTrees.ToArray();
|
|||
|
Debug.Log($"✅ 替换完成,处理了 {count} 个实例。添加到 Terrain 的 Tree 中。");
|
|||
|
}
|
|||
|
}
|