Unity中让父物体的位置调整到子物体的中心位置(子物体位置不变)

image.png

image.png

image.png

逻辑原理:

  1. 遍历所有的子Transform
  2. 查找带Renderer的取Renderer的世界位置的Bound中心值,不带Renderer的看是否只有一个Transform或者没有子物体的取世界坐标每次计算xyz分量的最大和最小值
  3. 最后把最大和最小的取中

上代码:

using UnityEditor;
using UnityEngine;

public class TransformCenterOnChildren : Editor
{
    [MenuItem("Tools/坐标归到子物体中心点位置")]
    static void Start()
    {
        GameObject[] seGO = Selection.gameObjects;
        if (seGO.Length == 0)
        {
            return;
        }
        for (int i = 0; i < seGO.Length; i++)
        {
            Transform curTr = seGO[i].transform;
            Vector3 curPos = curTr.position;

            Vector3 cenPos = Center(curTr);

            int childCount = curTr.childCount;

            for (int k = 0; k < childCount; k++)
            {
                Vector3 offset = cenPos - curPos;
                curTr.GetChild(k).position -= offset;
            }
            Undo.RecordObject(curTr, "变换当前位置");
            curTr.position = cenPos;
        }
    }

    /// <summary>
    /// 计算子层级的物体中心点
    /// </summary>
    /// <param name="parentTransform">当前的 Transform</param>
    /// <returns>返回子物体的中心点</returns>
    static Vector3 Center(Transform parentTransform)
    {
        // 获取当前 Transform 的所有子物体
        Transform[] allTrans = parentTransform.GetComponentsInChildren<Transform>(true);
        if (allTrans.Length == 1)
        {
            return parentTransform.position;
        }

        //初始化初始值
        float xMax = allTrans[1].position.x,
            yMax = allTrans[1].position.y,
            zMax = allTrans[1].position.z,
            xMin = allTrans[1].position.x,
            yMin = allTrans[1].position.y,
            zMin = allTrans[1].position.z;



        foreach (var tran in allTrans)
        {
            if (tran.TryGetComponent(out Renderer renderer))
            {
                // 获取子物体包围盒中心点(在世界坐标系中)
                Vector3 childBoundsCenter = renderer.bounds.center;
                // 计算所有子物体中心点的最大最小值
                xMax = Mathf.Max(childBoundsCenter.x, xMax);
                yMax = Mathf.Max(childBoundsCenter.y, yMax);
                zMax = Mathf.Max(childBoundsCenter.z, zMax);

                xMin = Mathf.Min(childBoundsCenter.x, xMin);
                yMin = Mathf.Min(childBoundsCenter.y, yMin);
                zMin = Mathf.Min(childBoundsCenter.z, zMin);
            }
            else if (tran.GetComponents<Component>().Length > 1 || tran.childCount == 0)
            {
                // 如果当前物体的 Component 数量除了 Transform 以外还有其他 Component ,或者子物体是空的,也考虑在内
                xMax = Mathf.Max(tran.position.x, xMax);
                yMax = Mathf.Max(tran.position.y, yMax);
                zMax = Mathf.Max(tran.position.z, zMax);

                xMin = Mathf.Min(tran.position.x, xMin);
                yMin = Mathf.Min(tran.position.y, yMin);
                zMin = Mathf.Min(tran.position.z, zMin);
            }
        }

        // 组合大小值
        Vector3 min = new Vector3(xMin, yMin, zMin);
        Vector3 max = new Vector3(xMax, yMax, zMax);
        // 计算中心点
        Vector3 averageBoundsCenter = (min + max) / 2;

        return averageBoundsCenter;
    }
}

使用方法:

在任何一个路径下带有Editor文件夹的里面创建一个C#脚本,命名交TransformCenterOnChildren,把代码完整复制进去。
等Unity编译完成在上方有一个Tools的菜单,选中要调整的父层级Gameobject,点击坐标归到子物体中心点位置。

image.png

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容