Il modo più efficiente per convertire Vector3 in Vector2


11

Qual è il modo più efficiente e veloce per convertire un Vector3 in un Vector2?

Casting:

Vector2 vector2 = (Vector2)vector3;

Inizializzazione di un nuovo Vector2:

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

O c'è un altro metodo che non conosco?


11
Questi tipi di operazioni strutt non saranno mai il collo di bottiglia nel determinare le prestazioni nel tuo gioco, quindi piuttosto che impantanarti in micro-ottimizzazioni come questa, ti consiglio di usare qualsiasi cosa sia più chiara da capire nel contesto che stai usando esso. ;)
DMGregory

3
@DMGregory: A meno che, ovviamente, OP non abbia già effettuato un'analisi delle prestazioni e, forse a causa del pugilato, lo abbia effettivamente in un ciclo nidificato causando un problema di prestazioni. Un tale ciclo nidificato potrebbe, ad esempio, essere un'implementazione A-star o Dijkstra.
Pieter Geerkens,

5
@PieterGeerkens Fair, ma se OP stesse già eseguendo un'analisi delle prestazioni, avrebbe già provato in entrambi i modi e avrebbe numeri su entrambi. ;) Osservando la traiettoria di un certo numero di nuovi utenti Unity (incluso me stesso), sono abbastanza fiducioso che in questo caso si tratti di micro-ottimizzazione, quindi ho voluto dare un forte avvertimento (se possibile sopravvalutato). In questo modo si trovano settimane o mesi di modifiche al codice e preoccuparsi dell'ottimalità in modi che non migliorano i nostri giochi.
DMGregory

Risposte:


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

I Vector3 possono essere convertiti implicitamente in Vector2 (z viene scartato).

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

Se devi fare molte conversioni, potresti dover cambiare il modo in cui usi i tuoi vettori. Fai due test e cronometri per vedere quale funziona per te.

AGGIORNAMENTO CON I TEST: da quando hai chiesto quale sia il più veloce ho creato un test eseguendo 10000000 conversioni di ciascuno in Unity. Sembra che la versione di inizializzazione sia la più veloce in questo caso. MA, dovresti sempre usare quello che si adatta al tuo contesto, quindi ti consiglio di eseguire i tuoi test nel tuo gioco.

Istanze TestConvertByOperation 10000000: 0,2714049s

Istanze TestConvertByCasting 10000000: 0,286027s

TestConvertByInitializing 10000000 istanze: 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
Sono espressamente espressi. Questo viene fatto definendo nuovi operatori di conversione . Ironia della sorte Unity viola il "... se la conversione è garantita per non causare una perdita di dati". parte.
Athos vk,

1
Aggiornato la mia risposta con un esempio di codice per testare i diversi approcci. Fammi sapere quale è più veloce nel tuo caso.
Mattias,

1
I risultati cambiano leggermente in una build di rilascio / non debug o quando i dati Vector2 hanno una vita al di fuori del ciclo for (che impedisce al compilatore di eseguire determinati tipi di ottimizzazione). Ottengo uno spread da 110 a 151 millisecondi, o una differenza massima di circa 4 nanosecondi per incarico. Quindi, a meno che non lo facciamo centinaia di migliaia di volte ogni frame, questo probabilmente non è un caso di cui preoccuparsi, anche se c'è una differenza misurabile in un esempio sintetico come questo.
DMGregory

1
@DMGregory Concordato. Ecco perché è sempre una buona idea eseguire test delle prestazioni nel contesto corretto, con dati reali.
Mattias,

1
Il problema con la conversione implicita è che yc'è. Quando si converte a Vector3in a Vector2, quasi sempre si desidera xe z, non xe y.
Kevin Krumwiede il

6

Sia Vector2 che Vector3 sono una struttura nel motore Unity, quindi la creazione dell'una dall'altra implica semplicemente l'allocazione di una memoria nello stack (a meno che la destinazione non sia un attributo di un oggetto di classe , che consentirebbe di saltare questo primo passaggio) e la copia dei valori dei due componenti. Entrambi i meccanismi forniti devono essere compilati esattamente con questo codice IL.

Se stai riscontrando un problema di prestazioni con una conversione di questo tipo, probabilmente hai un problema di boxe , con la struttura convertita in e quindi da un oggetto di classe . In tal caso, è necessario verificare se, quando e come, la boxe potrebbe essere evitata in parti critiche per le prestazioni del codice.


0

Dal mio test, il modo migliore per farlo è assegnare manualmente il suo valore da solo.

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

Questo è il mio risultato che estendo da Mattias.

Istanze TestConvertByOperation 10000000: 0,3220527s

Istanze TestConvertByCasting 10000000: 0,3226218s

TestConvertByInitializing 10000000 istanze: 0.1916729s

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

Si prega di notare che lo collaudo con l'unità versione 5.6.5

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.