MRが楽しい

MRやVRについて学習したことを書き残す

Vector3.sqrMagnitudeを使ってより高速な距離比較を行う

本日は Unity の小ネタ枠です。
Vector3.sqrMagnitudeを使ってより高速な距離比較を行う検証を行います。

Vector3.sqrMagnitude

2点間のベクトルの 2 乗の長さを返します。
Vector3.Distance で2点間の距離を算出する場合、ルートの計算に時間がかかります。
このため、単純に距離の遠近を比較したい場合は sqrMagnitude を利用し、2乗値で比較するようにすると処理が高速に行えます。
docs.unity3d.com

検証シーンの作成

実際にサンプルシーンを作成して2つのコードの実行時間を比較してみます。
指定する2つのオブジェクトとメインカメラの距離を比較して近い方を検出する以下のスクリプトを作成しました。
・DistanceComparison.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DistanceComparison : MonoBehaviour
{
    [SerializeField, Tooltip("チェック対象A")]
    private Transform p_ObjectA;

    [SerializeField, Tooltip("チェック対象B")]
    private Transform p_ObjectB;

    // Start is called before the first frame update
    void Start()
    {
        Vector3DistanceCheck(p_ObjectA, p_ObjectB);

        Vector3SqrMagnitudeCheck(p_ObjectA, p_ObjectB);
    }

    void Vector3DistanceCheck(Transform a_ObjectA, Transform a_ObjectB)
    {
        // カメラ位置を取得
        Transform myPosition = Camera.main.transform;

        // Stopwatchの開始
        System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
        stopwatch.Start();

        // Vector3Distance で距離を取得
        float distanceA = Vector3.Distance(myPosition.position, a_ObjectA.position);

        // Vector3Distance で距離を取得
        float distanceB = Vector3.Distance(myPosition.position, a_ObjectB.position);

        // 経過時間
        Debug.Log("ElapsedMilliseconds : " + stopwatch.ElapsedMilliseconds + " ms");
        stopwatch.Stop();

        // 結果を表示
        Debug.Log("distanceA : " + distanceA + ", distanceB : " + distanceB + ".");
        Debug.Log("Near : " + ((distanceA < distanceB) ? "ObjectA" : "ObjectB") + ".");
    }
    void Vector3SqrMagnitudeCheck(Transform a_ObjectA, Transform a_ObjectB)
    {
        // カメラ位置を取得
        Transform myPosition = Camera.main.transform;

        // Stopwatchの開始
        System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
        stopwatch.Start();

        // Vector3Magnitude で距離の2乗値を取得
        float distanceA = Vector3.SqrMagnitude(myPosition.position - a_ObjectA.position);

        // Vector3Magnitude で距離の2乗値を取得
        float distanceB = Vector3.SqrMagnitude(myPosition.position - a_ObjectB.position);

        // 経過時間
        Debug.Log("ElapsedMilliseconds : " + stopwatch.ElapsedMilliseconds + " ms");
        stopwatch.Stop();

        // 結果を表示
        Debug.Log("distanceA : " + distanceA + ", distanceB : " + distanceB + ".");
        Debug.Log("Near : " + ((distanceA < distanceB) ? "ObjectA" : "ObjectB") + ".");
    }
}

f:id:bluebirdofoz:20210512040924j:plain

処理時間の計測には以下の記事の方法を利用しています。
bluebirdofoz.hatenablog.com

シーンにスクリプトを配置し、比較する2つのオブジェクトを指定しました。
f:id:bluebirdofoz:20210512041014j:plain

処理時間の検証

処理を実行してそれぞれの経過時間を表示してみました。
f:id:bluebirdofoz:20210512041024j:plain

結果としてはどちらもミリ秒未満の処理速度で実行され、1度比較する程度では優位な差は見られませんでした。
普段はあまり意識する必要はないかもしれませんが、ルートの算術演算が通常の算術より時間がかかるのは確かなため、非常に多くの距離計算を毎フレーム行う場合などは試してみるとよいかもしれません。