Vector3をVector2に変換する最も効率的な方法


11

Vector3をVector2に変換する最も効率的で最速の方法は何ですか?

鋳造:

Vector2 vector2 = (Vector2)vector3;

新しいVector2の初期化:

Vector2 vector2 = new Vector2(vector3.x, vector3.y);

または私が知らない別の方法はありますか?


10
これらのタイプの構造体操作は、ゲームのパフォーマンスを決定するボトルネックになることは決してないので、このようなマイクロ最適化に行き詰まるのではなく、使用しているコンテキストで理解しやすい方を使用することをお勧めしますそれ。;)
DMGregory

1
@DMGregory:もちろん、OPがすでにパフォーマンス分析を実行していない場合を除き、おそらくボクシングが原因で、ネストされたループにこれが含まれているとパフォーマンスの問題が発生します。このようなネストされたループは、たとえば、Aスターまたはダイクストラの実装です。
Pieter Geerkens 16年

4
@PieterGeerkens Fairですが、OPがすでにパフォーマンス分析を行っている場合、彼らはすでに両方の方法を試していて、両方に数値が表示されます。;)多数の新しいUnityユーザー(自分を含む)の軌跡を見ると、この場合は微最適化であると確信しているので、それに対して強力な(誇張されている場合は)警告を出したかったのです。その方法は、数週間または数ヶ月のコードを微調整し、ゲームをより良くしない方法で最適性を悩ませています。
DMGregory

回答:


12
Vector3 v3 = Vector3.one;
Vector2 v2 = v3;

Vector3は暗黙的にVector2に変換できます(zは破棄されます)。

http://docs.unity3d.com/ScriptReference/Vector2-operator_Vector3.html

多くの変換を行わなければならない場合は、ベクターの使用方法を変更する必要があるかもしれません。2つのテストを行い、どれが効果的かを確認するために時間を計ります。

テストで更新: あなたがどれが最も速いか尋ねたので、私はUnityでそれぞれの10000000変換を実行するテストを作成しました。この場合、初期化バージョンが最も速いようです。ただし、常に自分のコンテキストに合ったものを使用する必要があるため、ゲームで独自のテストを実行することをお勧めします。

TestConvertByOperation 10000000インスタンス:0.2714049s

TestConvertByCasting 10000000インスタンス:0.286027s

TestConvertByInitializing 10000000インスタンス:0.1458781s

using UnityEngine;

public class TestVector3Conversion : MonoBehaviour
{

    readonly int iterations = 10000000;
    Vector3 testVector = new Vector3(3f, 14f, 42f);

    void Start()
    {
        Debug.Log(string.Format("TestConvertByOperation {0} instances: {1}s", iterations, TestConvertByOperation()));
        Debug.Log(string.Format("TestConvertByCasting {0} instances: {1}s", iterations, TestConvertByCasting()));
        Debug.Log(string.Format("TestConvertByInitializing {0} instances: {1}s", iterations, TestConvertByInitializing()));
    }

    float TestConvertByOperation()
    {
        var timeStart = Time.realtimeSinceStartup;

        for (int i = 0; i < iterations; i++)
        {
            Vector2 v2 = testVector;
        }

        return Time.realtimeSinceStartup - timeStart;
    }

    float TestConvertByCasting()
    {
        var timeStart = Time.realtimeSinceStartup;

        for (int i = 0; i < iterations; i++)
        {
            Vector2 v2 = (Vector2)testVector;
        }

        return Time.realtimeSinceStartup - timeStart;
    }

    float TestConvertByInitializing()
    {
        var timeStart = Time.realtimeSinceStartup;

        for (int i = 0; i < iterations; i++)
        {
            Vector2 v2 = new Vector2(testVector.x, testVector.y);
        }

        return Time.realtimeSinceStartup - timeStart;
    }

}

1
それらは暗黙的にキャストされます。これは、新しい変換演算子を定義することによって行われます。皮肉なことに、Unityは「変換によってデータが失われないことが保証されている場合」に違反します。部。
Athos vk

1
さまざまなアプローチをテストするために、コード例で私の回答を更新しました。あなたの場合、どちらが速いか教えてください。
Mattias

1
リリース/非デバッグビルド、またはVector2データにforループ外のライフタイムがある場合(コンパイラーが特定のタイプの最適化を行わないようにする場合)、結果は少しシフトします。110〜151ミリ秒の広がり、つまり割り当てごとに最大で約4 ナノ秒の差が出ます。したがって、毎フレーム数十万回これを行わない限り、このような合成例に測定可能な違いがあるとしても、これはおそらく心配する必要はありません。
DMGregory

1
@DMGregory同意する。そのため、実際のデータを使用して、適切なコンテキストでパフォーマンステストを実行することをお勧めします。
Mattias

1
暗黙的な変換の問題は、それが発生していることyです。a Vector3をに変換する場合Vector2、ほとんどの場合x、and zではなくxandが必要yです。
Kevin Krumwiede 2017

6

Vector2Vector3はどちらもUnityエンジンの構造体であるため、一方から他方を作成するには、単にスタックにストレージを割り当てる必要があります(宛先がクラスオブジェクトの属性でない限り、 この最初のステップをスキップできます)。 2つのコンポーネント値のコピー。どちらのメカニズムも、このILコードに合わせてコンパイルする必要があります。

この型の変換でパフォーマンスの問題が発生している場合は、構造体クラスオブジェクトとの間で変換されるため、ボクシングの問題が発生している可能性があります。その場合、コードのパフォーマンスが重要な部分でボクシングを回避できるかどうか、いつ、どのようにして回避できるかを調査する必要があります。


0

私のテストから、それを行う最善の方法は、自分で値を手動で割り当てることです。

Vector2 vector2;
vector2.x = vector3.x;
vector2.y = vector3.y;

これは私がマティアスから拡張した私の結果です。

TestConvertByOperation 10000000インスタンス:0.3220527s

TestConvertByCasting 10000000インスタンス:0.3226218秒

TestConvertByInitializing 10000000インスタンス:0.1916729s

TestConvertByManualAssign 10000000インスタンス:0.09500527s

using UnityEngine;

namespace myTest
{
    public class test: MonoBehaviour 
    {
        readonly int iterations = 10000000;
        Vector3 testVector = new Vector3(3f, 14f, 42f);

        void Start()
        {
            Debug.Log(string.Format("TestConvertByOperation {0} instances: {1}s", iterations, TestConvertByOperation()));
            Debug.Log(string.Format("TestConvertByCasting {0} instances: {1}s", iterations, TestConvertByCasting()));
            Debug.Log(string.Format("TestConvertByInitializing {0} instances: {1}s", iterations, TestConvertByInitializing()));
            Debug.Log(string.Format("TestConvertByManualAssign {0} instances: {1}s", iterations, TestConvertByManualAssign()));
        }

        float TestConvertByOperation()
        {
            var timeStart = Time.realtimeSinceStartup;
            Vector2 v2;
            for (int i = 0; i < iterations; i++)
            {
                v2 = testVector;
            }

            return Time.realtimeSinceStartup - timeStart;
        }

        float TestConvertByCasting()
        {
            var timeStart = Time.realtimeSinceStartup;
            Vector2 v2;
            for (int i = 0; i < iterations; i++)
            {
                v2 = (Vector2)testVector;
            }

            return Time.realtimeSinceStartup - timeStart;
        }

        float TestConvertByInitializing()
        {
            var timeStart = Time.realtimeSinceStartup;
            Vector2 v2;
            for (int i = 0; i < iterations; i++)
            {
                v2 = new Vector2(testVector.x, testVector.y);
            }

            return Time.realtimeSinceStartup - timeStart;
        }
        float TestConvertByManualAssign()
        {
            var timeStart = Time.realtimeSinceStartup;
            Vector2 v2;
            for (int i = 0; i < iterations; i++)
            {
                v2.x = testVector.x;
                v2.y = testVector.y;
            }

            return Time.realtimeSinceStartup - timeStart;
        }
    }
}

Unityバージョン5.6.5でテストしています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.