在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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Boyce Lig

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值