Maneira mais eficiente de converter Vector3 para Vector2

11

Qual é a maneira mais eficiente e rápida de converter um Vector3 para um Vector2?

Fundição:

Vector2 vector2 = (Vector2)vector3;

Inicializando um novo Vector2:

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

Ou existe outro método que eu não conheço?

S. Tarık Çetin
fonte
10
Esses tipos de operações struct nunca serão o gargalo que determina o desempenho no seu jogo; portanto, em vez de ficar atolado em micro-otimizações como essa, recomendo apenas o que for mais claro para entender no contexto que você está usando isto. ;)
DMGregory
1
@ DMGregory: A menos que, é claro, o OP já tenha feito uma análise de desempenho e, talvez devido ao boxe, na verdade tenha isso em um loop aninhado, causando um problema de desempenho. Esse loop aninhado pode, por exemplo, ser uma implementação de estrela A ou Dijkstra.
Pieter Geerkens
4
@PieterGeerkens Fair, mas se a OP já estivesse analisando o desempenho, eles já teriam tentado nos dois sentidos e teriam números em ambos. ;) Ao observar a trajetória de vários novos usuários do Unity (inclusive eu), estou bastante confiante de que, neste caso, é uma micro otimização, então eu queria fazer um aviso forte (se possível exagerado) contra ele. Dessa forma, estão semanas ou meses de ajustes no código e se preocupam com a otimização de maneiras que não tornam nossos jogos melhores.
DMGregory

Respostas:

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

Os Vector3s podem ser implicitamente convertidos em Vector2 (z é descartado).

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

Se você precisar fazer muitas conversões, pode ser necessário alterar a maneira como você usa seus vetores. Faça dois testes e cronometre-os para ver qual deles funciona para você.

ATUALIZAÇÃO COM TESTES: Como você perguntou qual é o mais rápido , criei um teste executando 10000000 conversões de cada uma no Unity. Parece que a versão Inicializando é a mais rápida nesse caso. MAS, você deve sempre usar aquele que se adapte ao seu próprio contexto, por isso aconselho a executar seus próprios testes no seu jogo.

Instâncias TestConvertByOperation 10000000: 0.2714049s

Instâncias TestConvertByCasting 10000000: 0.286027s

Instâncias 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;
    }

}
Mattias
fonte
1
Eles são lançados implicitamente. Isso é feito definindo novos operadores de conversão . Ironicamente, o Unity viola o '... se a conversão é garantida para não causar perda de dados.' parte.
Athos vk
1
Atualizei minha resposta com um exemplo de código para testar as diferentes abordagens. Deixe-me saber qual é o mais rápido no seu caso.
Mattias
1
Os resultados mudam um pouco em uma versão / versão sem depuração, ou quando os dados do Vector2 têm uma vida útil fora do loop for (que impede o compilador de fazer certos tipos de otimização). Recebo uma propagação de 110 a 151 milissegundos ou uma diferença máxima de cerca de 4 nanossegundos por tarefa. Portanto, a menos que façamos isso centenas de milhares de vezes a cada quadro, provavelmente este não é um caso para se preocupar, mesmo que haja uma diferença mensurável em um exemplo sintético como este.
DMGregory
1
@DMGregory Concordado. É por isso que é sempre uma boa ideia executar testes de desempenho no contexto correto, com dados reais.
Mattias
1
O problema com a conversão implícita é que yacabou. Ao converter a Vector3para a Vector2, você quase sempre deseja xe z, não xe y.
precisa saber é o seguinte
6

O Vector2 e o Vector3 são uma estrutura no mecanismo do Unity, portanto, a criação de um a partir do outro envolve simplesmente a alocação de um armazenamento na pilha (a menos que o destino seja um atributo de um objeto de classe , o que permitiria ignorar esta primeira etapa) e a cópia dos dois valores de componentes. Os dois mecanismos que você fornece devem ser compilados exatamente nesse código de IL.

Se você estiver enfrentando um problema de desempenho com uma conversão desse tipo, provavelmente terá um problema de boxe , com a estrutura sendo convertida para e a partir de um objeto de classe . Nesse caso, você deve investigar se, quando e como, o boxe pode ser evitado em partes críticas do desempenho do seu código.

Pieter Geerkens
fonte
0

No meu teste, a melhor maneira de fazer isso é atribuir manualmente seu valor.

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

Este é o meu resultado que estendo de Mattias.

Instâncias TestConvertByOperation 10000000: 0.3220527s

Instâncias TestConvertByCasting 10000000: 0.3226218s

Instâncias TestConvertByInitializing 10000000: 0.1916729s

Instâncias 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;
        }
    }
}

Observe que eu testei com a versão 5.6.5 do Unity

Vimutti Roatkanjanaporn
fonte