オブジェクトの位置と回転をスクリプトから変更したい場合、次のようなコードを書くことが多いかもしれません。
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を個別指定
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メソッドで指定
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 |
プロファイラでの計測結果も載せておきます。
概ね1割強のパフォーマンスの差で、SetPositionAndRotationメソッドのほうが低負荷であるという結果となりました。
この差を大きいと見るか小さいと見るかは状況次第かもしれませんが、特に理由がない限りはSetPositionAndRotationメソッドを使ったほうが良いと言えるでしょう。
SetLocalPositionAndRotationメソッド(2021.3.11f1以降)
Unity 2021.3.11f1以降では、ローカル空間における位置と回転を指定するSetLocalPositionAndRotationメソッドが追加されました。
public void SetLocalPositionAndRotation(Vector3 localPosition, Quaternion localRotation);
第1引数にはローカル空間の位置、第2引数にはローカル空間の回転(クォータニオン)を指定します。
TransformのlocalPositionとlocalRotationプロパティを同時に設定したいとき、このメソッドを用いると僅かに効率的です。ただし、Unity 2021.3.10以前では使用できないメソッドであることにご注意ください。
メソッドが追加されたことは、以下変更履歴より確認できます。
さいごに
オブジェクトの位置と回転を指定する場合、SetPositionAndRotationメソッドを使用すると低負荷に指定出来ます。
Unity公式のスライドでもこの方式で指定することを推奨しています。
また、ローカル空間の位置と回転を指定する場合、新しいUnityバージョンではSetLocalPositionAndRotationメソッドが使用できますが、それより前のバージョンでは従来通りlocalPosition、localRotationプロパティから指定する形になる点にはご注意ください。