37.Transform相关优化

37.性能优化-CPU-脚本-Transform


37.1 知识点

避免运行时修改 Transform 父节点

在运行时通过 SetParent 修改 Transform 的父节点是一项开销较大的操作。

主要原因:

  1. 触发 Transform 系统重建
    修改父节点后,Unity 会重建该物体及其子物体的层级关系与矩阵缓存,触发一系列递归更新,在父子层级多时尤其耗性能。

  2. 可能导致批处理中断
    若对象原本参与同一静态批处理,修改父节点后可能触发重新分组甚至退出批处理。

  3. 可能导致缓冲区扩展
    Transform 底层父子关系类似动态数组,修改父节点可能引起缓冲区扩展,带来不必要的内存分配。

因此应尽量避免在运行时频繁或大规模地改父节点;若必须在运行时挂到新父节点下,尽量集中、少量地做。

避免运行时频繁修改 Transform 相关属性

频繁修改 Transform 的属性会“牵一发动全身”,可能引发连锁更新,在物体多或低端设备上影响更明显,应尽量避免。

position、rotation、scale 的开销

Transform 内部会存储与父节点相关的数据,直接改 positionrotationscale 等世界属性时,引擎内部会做大量矩阵运算,且物体在 Hierarchy 中层级越深,计算量越大。

优化建议: 在逻辑允许的前提下,优先使用 localPositionlocalRotationlocalScale 等本地属性,修改成本相对更小。

对其他组件的影响

每次修改 Transform 属性,引擎会向依赖它的组件发送内部通知,例如 Collider、Rigidbody、Light、Camera 等,物理与渲染系统都要拿到新的 Transform 数据才能更新。因此应避免在一帧内多次修改 Transform 属性。

优化建议:缓存方式减少写回次数:先读取到局部变量,在局部变量上做完所有运算,最后再一次性写回。

示例(先取位置,在托管侧做完运算再写回):

// 先拿到位置信息,在局部变量上做一系列操作
Vector3 cachedPosition = transform.position;

cachedPosition += new Vector3(1, 1, 1);
cachedPosition += new Vector3(1, 1, 1);
cachedPosition += new Vector3(1, 1, 1);
cachedPosition -= new Vector3(1, 1, 1);
cachedPosition -= new Vector3(1, 1, 1);
cachedPosition -= new Vector3(1, 1, 1);
cachedPosition -= new Vector3(1, 1, 1);

// 最后再设置回去,只触发一次桥接与内部更新
transform.position = cachedPosition;

若相对父节点修改即可满足需求,可改用本地属性,减少内部矩阵链更新:

// 能用本地属性时优先用本地属性,成本更小
transform.localPosition += offset;
// 或先缓存再写回
Vector3 localPosition = transform.localPosition;
localPosition += offset;
transform.localPosition = localPosition;

避免运行时频繁使用 Transform 相关方法

避免滥用封装好的方法

LookAtRotateAround 等封装方法内部可能包含额外计算,在每帧或高频调用时会带来明显开销。若对性能敏感,可自行用向量、四元数等计算旋转或“看向”逻辑,按需只做必要运算。

避免频繁使用层级遍历方法

transform.Find(string) 等查找方法会在内部做层级遍历,在子物体多时非常耗性能,不应在 Update 等每帧执行的方法里使用。

优化建议:AwakeStart 中查找一次并缓存引用,后续直接使用缓存。

// 不推荐:在 Update 中每帧查找
void Update()
{
    Transform child = transform.Find("SomeChild");
}

// 推荐:初始化时查找并缓存
private Transform cachedChild;

void Awake()
{
    cachedChild = transform.Find("SomeChild");
}

37.2 知识点代码

Lesson37_性能优化_CPU_脚本_Transform.cs

using UnityEngine;

public class Lesson37_性能优化_CPU_脚本_Transform : MonoBehaviour
{
    void Start()
    {
        #region 知识点一 避免运行时修改Transform父节点问题

        /* 运行时 SetParent 会触发:层级与矩阵重建、批处理可能中断、缓冲区可能扩展;
         * 应尽量避免在运行时频繁或大规模修改父节点。*/

        #endregion

        #region 知识点二 避免运行时频繁修改Transform相关属性

        /* 频繁改 position/rotation/scale 会触发大量矩阵运算并通知 Collider、Rigidbody 等;
         * 优化:优先用 localPosition/localRotation/localScale,并用缓存减少写回次数。*/

        #endregion

        #region 知识点三 避免运行时频繁使用Transform相关方法

        /* LookAt、RotateAround 等内部有额外计算,可改为自行计算;
         * transform.Find 等会遍历层级,应在 Awake/Start 中缓存,避免在 Update 中使用。*/

        #endregion
    }

    void Update()
    {
        // 先拿到位置信息,做好一系列操作后最后再设置回去,减少对 transform 的写回次数
        Vector3 cachedPosition = transform.position;

        // 一系列操作在局部变量上完成
        cachedPosition += new Vector3(1, 1, 1);
        cachedPosition += new Vector3(1, 1, 1);
        cachedPosition += new Vector3(1, 1, 1);
        cachedPosition -= new Vector3(1, 1, 1);
        cachedPosition -= new Vector3(1, 1, 1);
        cachedPosition -= new Vector3(1, 1, 1);
        cachedPosition -= new Vector3(1, 1, 1);

        // 最后再设置回去
        transform.position = cachedPosition;
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏