前言
在Unity项目开发中,经常需要调整物体的位置。特别是在处理3D模型时,我们可能需要将一个父物体移动到其所有子物体的中心位置或底部中心位置。本文将介绍如何通过Unity编辑器扩展来实现这个功能,让美术同学在摆放模型时更加方便。
一、效果演示
二、完整代码
这里直接上完整代码了,大家有问题可以在评论区留言
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(Transform))]
public class TransformMethod : Editor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
var transform = target as Transform;
if (transform.TryGetComponent<MeshFilter>(out var meshFilter) || transform.GetComponentInChildren<MeshFilter>() == null)
{
}
else
{
using (new GUILayout.HorizontalScope())
{
// 添加两个按钮
if (GUILayout.Button("Move To Center", GUILayout.Height(EditorGUIUtility.singleLineHeight * 1.5f)))
{
MoveToCenter(transform, false);
}
if (GUILayout.Button("Move To Bottom Center", GUILayout.Height(EditorGUIUtility.singleLineHeight * 1.5f)))
{
MoveToCenter(transform, true);
}
}
}
}
private void MoveToCenter(Transform transform, bool toBottom)
{
// 获取所有子物体的MeshRenderer
var meshRenderers = transform.GetComponentsInChildren<MeshRenderer>();
if (meshRenderers.Length == 0) return;
// 计算所有Mesh的边界框
Bounds bounds = new Bounds(meshRenderers[0].bounds.center, meshRenderers[0].bounds.size);
for (int i = 1; i < meshRenderers.Length; i++)
{
bounds.Encapsulate(meshRenderers[i].bounds);
}
// 记录所有子物体的世界位置
var childCount = transform.childCount;
Vector3[] worldPositions = new Vector3[childCount];
for (int i = 0; i < childCount; i++)
{
worldPositions[i] = transform.GetChild(i).position;
}
// 移动父物体到中心位置
Vector3 targetPosition = bounds.center;
if (toBottom)
{
targetPosition.y = bounds.min.y;
}
transform.position = targetPosition;
// 恢复子物体的世界位置
for (int i = 0; i < childCount; i++)
{
transform.GetChild(i).position = worldPositions[i];
}
// 标记为需要保存
EditorUtility.SetDirty(transform);
}
}
三、总结
这个编辑器扩展工具虽然简单,但在实际开发中非常实用:
1、提高效率:避免手动调整物体位置,一键完成对齐
2、保持准确:通过计算精确的边界框确保对齐的准确性
3、维持层级:在调整过程中保持物体层级关系不变
4、易于使用:直接集成在Transform Inspector中,使用方便
通过这个例子,我们可以看到Unity编辑器扩展的强大之处。通过简单的代码,我们就能为Unity编辑器添加实用的功能,提高开发效率。同时,这个实现也展示了如何在移动物体时保持子物体的世界坐标不变,这是一个在很多场景下都能用到的技巧。