Die effizienteste Methode zum Konvertieren von Vector3 in Vector2

11

Was ist der effizienteste und schnellste Weg, um einen Vector3 in einen Vector2 umzuwandeln?

Casting:

Vector2 vector2 = (Vector2)vector3;

Initialisieren eines neuen Vektors2:

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

Oder gibt es eine andere Methode, die ich nicht kenne?

S. Tarık Çetin
quelle
10
Diese Art von Strukturoperationen wird niemals den leistungsbestimmenden Engpass in Ihrem Spiel darstellen. Anstatt sich in solchen Mikrooptimierungen festzumachen, würde ich empfehlen, nur das zu verwenden, was in dem von Ihnen verwendeten Kontext klarer zu verstehen ist es. ;)
DMGregory
1
@DMGregory: Es sei denn, OP hat bereits eine Leistungsanalyse durchgeführt und hat diese möglicherweise aufgrund des Boxens tatsächlich in einer verschachtelten Schleife, was zu einem Leistungsproblem führt. Eine solche verschachtelte Schleife kann beispielsweise eine A-Stern- oder Dijkstra-Implementierung sein.
Pieter Geerkens
4
@PieterGeerkens Fair, aber wenn OP bereits eine Leistungsanalyse durchgeführt hätte, hätten sie bereits beide Möglichkeiten ausprobiert und hätten Zahlen auf beiden. ;) Nachdem ich die Flugbahn einer Reihe neuer Unity-Benutzer (einschließlich meiner selbst) beobachtet habe, bin ich ziemlich zuversichtlich, dass es sich in diesem Fall um eine Mikrooptimierung handelt, und wollte daher eine starke (wenn möglicherweise überbewertete) Warnung davor aussprechen. Auf diese Weise liegen Wochen oder Monate voller Code-Optimierungen und der Sorge um die Optimalität auf eine Weise, die unsere Spiele nicht besser macht.
DMGregory

Antworten:

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

Vector3s können implizit in Vector2 konvertiert werden (z wird verworfen).

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

Wenn Sie viele Konvertierungen vornehmen müssen, müssen Sie möglicherweise die Art und Weise ändern, wie Sie Ihre Vektoren verwenden. Machen Sie zwei Tests und messen Sie sie, um festzustellen, welcher für Sie funktioniert.

UPDATE MIT TESTS: Da Sie gefragt haben, welches das schnellste ist, habe ich einen Test erstellt, in dem jeweils 10000000 Conversions in Unity ausgeführt werden. In diesem Fall scheint die Initialisierungsversion am schnellsten zu sein. ABER du solltest immer die verwenden, die zu deinem eigenen Kontext passt, also rate ich dir, deine eigenen Tests in deinem Spiel durchzuführen.

TestConvertByOperation 10000000 Instanzen: 0.2714049s

TestConvertByCasting 10000000 Instanzen: 0.286027s

TestConvertByInitializing 10000000 Instanzen: 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;
    }

}
Mattias
quelle
1
Sie sind implizit gegossen. Dies erfolgt durch Definieren neuer Konvertierungsoperatoren . Ironischerweise verstößt Unity gegen das "... wenn die Konvertierung garantiert keinen Datenverlust verursacht". Teil.
Athos vk
1
Meine Antwort wurde mit einem Codebeispiel aktualisiert, um die verschiedenen Ansätze zu testen. Lassen Sie mich wissen, welches in Ihrem Fall schneller ist.
Mattias
1
Die Ergebnisse verschieben sich ein wenig in einem Release- / Non-Debug-Build oder wenn die Vector2-Daten eine Lebensdauer außerhalb der for-Schleife haben (was den Compiler davon abhält, bestimmte Arten der Optimierung durchzuführen). Ich erhalte einen Spread von 110 bis 151 Millisekunden oder eine maximale Differenz von etwa 4 Nanosekunden pro Zuordnung. Wenn wir dies also nicht hunderttausend Mal in jedem Frame tun, ist dies wahrscheinlich kein Grund zur Sorge, selbst wenn es in einem synthetischen Beispiel wie diesem einen messbaren Unterschied gibt.
DMGregory
1
@ DMGregory vereinbart. Deshalb ist es immer eine gute Idee, Leistungstests im richtigen Kontext mit realen Daten durchzuführen.
Mattias
1
Das Problem mit der impliziten Konvertierung ist, dass es vorbei yist. Wenn Sie a Vector3in a konvertieren Vector2, möchten Sie fast immer xund znicht xund y.
Kevin Krumwiede
6

Sowohl Vector2 als auch Vector3 sind eine Struktur in der Unity-Engine. Bei der Erstellung einer Struktur aus der anderen wird lediglich ein Speicher auf dem Stapel zugewiesen (es sei denn, das Ziel ist ein Attribut eines Klassenobjekts , mit dem dieser erste Schritt übersprungen werden kann.) und das Kopieren der beiden Komponentenwerte. Beide von Ihnen angegebenen Mechanismen sollten genau zu diesem IL-Code kompiliert werden.

Wenn bei einer Konvertierung dieses Typs ein Leistungsproblem auftritt , liegt wahrscheinlich ein Boxproblem vor , bei dem die Struktur in ein Klassenobjekt und dann von einem Klassenobjekt konvertiert wird. In diesem Fall sollten Sie untersuchen, ob, wann und wie das Boxen in leistungskritischen Teilen Ihres Codes vermieden werden kann.

Pieter Geerkens
quelle
0

Nach meinem Test ist es am besten, den Wert manuell selbst zuzuweisen.

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

Dies ist mein Ergebnis, das ich von Mattias ausgehe.

TestConvertByOperation 10000000-Instanzen: 0.3220527s

TestConvertByCasting 10000000 Instanzen: 0.3226218s

TestConvertByInitializing 10000000 Instanzen: 0.1916729s

TestConvertByManualAssign 10000000 Instanzen: 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;
        }
    }
}

Bitte beachten Sie, dass ich es mit Unity Version 5.6.5 teste

Vimutti Roatkanjanaporn
quelle