【Unity】オブジェクトの位置と回転を低負荷に指定する

オブジェクトの位置と回転をスクリプトから変更したい場合、次のようなコードを書くことが多いかもしれません。

transform.position = new Vector3(1, 2, 3);
transform.rotation = Quaternion.Euler(0, 30, 60);

このような処理は、次のようにTransform.SetPositionAndRotation()メソッドを使って書くことも可能です。

transform.SetPositionAndRotation(
    new Vector3(1, 2, 3),
    Quaternion.Euler(0, 30, 60)
);

後者の書き方にすることで、次のメリットが得られます。

メリット
  • 位置と回転を一度に指定できる
  • positionとrotationを別々に指定するより処理負荷が小さい

処理負荷が小さくなる理由は、Transformに送るメッセージが1回で済むようになるためです。このことは、以下スライドの13ページ目で言及されています。

では具体的にどれくらい負荷が小さくなるの~?

実際に処理負荷を計測して確かめていくね。

Transform.SetPositionAndRotation()メソッドにより位置と回転を指定すると、実際にどれくらい負荷が小さくなるか気になる方がいるかもしれません。

本記事では、Unity2021で実際に処理負荷を計測した結果をまとめました。

動作環境
  • Unity2021.1.25f1

Transform.SetPositionAndRotation()メソッド

メソッドの形式は次の通りです。

public void SetPositionAndRotation(Vector3 position, Quaternion rotation);

第1引数位置第2引数回転のクォータニオンを指定します。

両者ともワールド空間での指定となります。

処理負荷の検証

次の2パターンのスクリプトで処理負荷を検証していきます。

10万オブジェクトの位置と回転を毎フレーム更新し、更新にかかった時間をプロファイラより計測するようにします。

positionとrotationを個別指定

TestPattern1.cs
using UnityEngine;
using UnityEngine.Profiling;

public class TestPattern1 : MonoBehaviour
{
    private Transform[] _targets;
    private CustomSampler _sampler;

    private void Start()
    {
        _targets = new Transform[100000];

        for (var i = 0; i < _targets.Length; ++i)
        {
            var target = new GameObject("Target_" + i).transform;
            _targets[i] = target;
        }
        
        _sampler = CustomSampler.Create("Pattern1");
    }

    private void Update()
    {
        for (var i = 0; i < _targets.Length; ++i)
        {
            var position = new Vector3(
                Random.value,
                Random.value,
                Random.value
            );
            var rotation = Quaternion.Euler(Random.value, Random.value, Random.value);

            var target = _targets[i];
            
            _sampler.Begin();
            
            // パターン1 計測部分
            target.position = position;
            target.rotation = rotation;
            
            _sampler.End();
        }
    }
}

SetPositionAndRotation()で指定

TestPattern2.cs
using UnityEngine;
using UnityEngine.Profiling;

public class TestPattern2 : MonoBehaviour
{
    private Transform[] _targets;
    private CustomSampler _sampler;

    private void Start()
    {
        _targets = new Transform[100000];

        for (var i = 0; i < _targets.Length; ++i)
        {
            var target = new GameObject("Target_" + i).transform;
            _targets[i] = target;
        }
        
        _sampler = CustomSampler.Create("Pattern2");
    }

    private void Update()
    {
        for (var i = 0; i < _targets.Length; ++i)
        {
            var position = new Vector3(
                Random.value,
                Random.value,
                Random.value
            );
            var rotation = Quaternion.Euler(Random.value, Random.value, Random.value);

            var target = _targets[i];
            
            _sampler.Begin();
            
            // パターン2 計測部分
            target.SetPositionAndRotation(position, rotation);
            
            _sampler.End();
        }
    }
}

実行結果

1フレームあたりのTransform更新にかかった時間の計測結果です。

パターン処理時間[ms]
positionとrotationを個別指定54.5
SetPositionAndRotation()で指定49.0
計測結果

プロファイラでの計測結果も載せておきます。

positionとrotationを個別指定
SetPositionAndRotation()で指定

概ね1割強のパフォーマンスの差で、SetPositionAndRotation()メソッドのほうが低負荷であるという結果となりました。

この差を大きいと見るか小さいと見るかは状況次第かもしれませんが、特に理由がない限りはSetPositionAndRotation()メソッドを使ったほうが良いと言えるでしょう。

さいごに

オブジェクトの位置と回転を指定する場合、SetPositionAndRotation()メソッドを使用すると低負荷に指定出来ます。

Unity公式のスライドでもこの方式で指定することを推奨しています。

また、ローカル空間の位置と回転を指定する場合は、従来通りlocalPosition、localRotationプロパティから指定する形になる点にはご注意ください。

参考サイト