La forma más eficiente de convertir Vector3 a Vector2

11

¿Cuál es la forma más eficiente y rápida de convertir un Vector3 en un Vector2?

Fundición:

Vector2 vector2 = (Vector2)vector3;

Inicializando un nuevo Vector2:

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

¿O hay otro método que no conozco?

S. Tarık Çetin
fuente
11
Este tipo de operaciones de estructura nunca serán el cuello de botella que determina el rendimiento en su juego, por lo que en lugar de atascarse en micro optimizaciones como esta, recomendaría usar lo que sea más claro de entender en el contexto que está usando eso. ;)
DMGregory
3
@DMGregory: a menos que, por supuesto, OP ya haya realizado un análisis de rendimiento y, tal vez debido al boxeo, en realidad lo tenga en un bucle anidado que causa un problema de rendimiento. Tal bucle anidado podría, por ejemplo, ser una implementación de A-star o Dijkstra.
Pieter Geerkens
55
@PieterGeerkens Fair, pero si OP ya estuviera haciendo un análisis de rendimiento, ya lo habrían intentado en ambos sentidos y tendrían números en ambos. ;) Al observar la trayectoria de una serie de nuevos usuarios de Unity (incluido yo mismo), estoy bastante seguro de que en este caso se trata de una microoptimización, por lo que quería hacer una advertencia fuerte (si posiblemente exagerada) en su contra. De esa manera se encuentran semanas o meses de ajustes de código y preocuparse por la optimización de maneras que no mejoran nuestros juegos.
DMGregory

Respuestas:

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

Vector3s se puede convertir implícitamente a Vector2 (se descarta z).

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

Si tiene que hacer muchas conversiones, puede que tenga que cambiar la forma en que usa sus vectores. Haga dos pruebas y cronometralas para ver cuál funciona para usted.

ACTUALIZACIÓN CON PRUEBAS: como usted preguntó cuál es la más rápida , creé una prueba con 10000000 conversiones de cada una en Unity. Parece que la versión de inicialización es más rápida en este caso. PERO, siempre debes usar el que se adapte a tu propio contexto, por lo que te aconsejo que realices tus propias pruebas en tu juego.

TestConvertByOperation 10000000 instancias: 0.2714049s

TestConvertByCasting 10000000 instancias: 0.286027s

TestConvertByInitializing 10000000 instancias: 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
fuente
1
Están implícitamente fundidos. Esto se hace definiendo nuevos operadores de conversión . Irónicamente, Unity viola el '... si se garantiza que la conversión no causará una pérdida de datos'. parte.
Athos vk
1
Actualicé mi respuesta con un ejemplo de código para probar los diferentes enfoques. Déjame saber cuál es más rápido en tu caso.
Mattias
1
Los resultados cambian un poco en una versión de lanzamiento / no depuración, o cuando los datos de Vector2 tienen una vida útil fuera del ciclo for (lo que evita que el compilador realice ciertos tipos de optimización). Obtengo una extensión de 110 a 151 milisegundos, o una diferencia máxima de aproximadamente 4 nanosegundos por tarea. Entonces, a menos que estemos haciendo esto cientos de miles de veces en cada cuadro, probablemente este no sea un motivo de preocupación, incluso si hay una diferencia apreciable en un ejemplo sintético como este.
DMGregory
1
@DMGregory De acuerdo. Es por eso que siempre es una buena idea ejecutar pruebas de rendimiento en el contexto correcto, con datos reales.
Mattias
1
El problema con la conversión implícita es que yestá arriba. Al convertir a Vector3a a Vector2, casi siempre quieres xy z, no xy y.
Kevin Krumwiede
6

Tanto Vector2 como Vector3 son una estructura en el motor de Unity, por lo que la creación de uno desde el otro simplemente implica la asignación de un almacenamiento en la pila (a menos que el destino sea un atributo de un objeto de clase , lo que permitiría omitir este primer paso) y la copia de los dos valores componentes. Ambos mecanismos que proporcione deben compilarse exactamente con este código IL.

Si se encuentra con un problema de rendimiento con una conversión de este tipo, es probable que tenga un problema de boxeo , con la estructura convertida ay desde un objeto de clase . En ese caso, debe investigar si, cuándo y cómo, podría evitarse el boxeo en partes críticas de su código.

Pieter Geerkens
fuente
0

Desde mi prueba, la mejor manera de hacerlo es asignar manualmente su valor usted mismo.

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

Este es mi resultado que extiendo de Mattias.

TestConvertByOperation 10000000 instancias: 0.3220527s

TestConvertByCasting 10000000 instancias: 0.3226218s

TestConvertByInitializing 10000000 instancias: 0.1916729s

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

Tenga en cuenta que lo pruebo con la versión 5.6.5 de unity.

Vimutti Roatkanjanaporn
fuente