Le moyen le plus efficace pour convertir Vector3 en Vector2

11

Quel est le moyen le plus efficace et le plus rapide pour convertir un Vector3 en Vector2?

Moulage:

Vector2 vector2 = (Vector2)vector3;

Initialisation d'un nouveau Vector2:

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

Ou y a-t-il une autre méthode que je ne connais pas?

S. Tarık Çetin
la source
11
Ces types d'opérations de struct ne seront jamais le goulot d'étranglement déterminant les performances dans votre jeu, donc plutôt que de vous enliser dans des micro-optimisations comme celle-ci, je vous recommande d'utiliser simplement ce qui est le plus clair à comprendre dans le contexte que vous utilisez il. ;)
DMGregory
3
@DMGregory: Sauf si, bien sûr, OP a déjà fait une analyse des performances et, peut-être en raison de la boxe, cela a réellement dans une boucle imbriquée provoquant un problème de performances. Une telle boucle imbriquée pourrait, par exemple, être une implémentation A-star ou Dijkstra.
Pieter Geerkens
5
@PieterGeerkens Fair, mais si OP effectuait déjà une analyse des performances, il aurait déjà essayé les deux façons et aurait des chiffres sur les deux. ;) En observant la trajectoire d'un certain nombre de nouveaux utilisateurs d'Unity (y compris moi-même), je suis assez confiant que dans ce cas, il s'agit de micro-optimisation, donc je voulais faire un avertissement fort (si possible surévalué) contre cela. De cette façon, il y a des semaines ou des mois de modifications de code et de s'inquiéter de l'optimalité d'une manière qui n'améliore pas nos jeux.
DMGregory

Réponses:

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

Les Vector3 peuvent être implicitement convertis en Vector2 (z est supprimé).

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

Si vous devez effectuer de nombreuses conversions, vous devrez peut-être modifier la façon dont vous utilisez vos vecteurs. Faites deux tests et chronométrez-les pour voir celui qui vous convient.

MISE À JOUR AVEC LES TESTS: Puisque vous avez demandé lequel est le plus rapide, j'ai créé un test exécutant 10000000 conversions de chacun dans Unity. Il semble que la version Initialisation soit la plus rapide dans ce cas. MAIS, vous devez toujours utiliser celui qui convient à votre propre contexte, je vous conseille donc d'exécuter vos propres tests dans votre jeu.

TestConvertByOperation 10000000 instances: 0,2714049s

TestConvertByCasting 10000000 instances: 0,286027s

TestConvertByInitializing 10000000 instances: 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
la source
1
Ils sont implicitement castés. Cela se fait en définissant de nouveaux opérateurs de conversion . Ironiquement, Unity viole le «... si la conversion est garantie de ne pas provoquer de perte de données». partie.
Athos vk
1
Mise à jour de ma réponse avec un exemple de code pour tester les différentes approches. Faites-moi savoir lequel est le plus rapide dans votre cas.
Mattias
1
Les résultats changent un peu dans une version de version / non-débogage, ou lorsque les données Vector2 ont une durée de vie en dehors de la boucle for (ce qui empêche le compilateur de faire certains types d'optimisation). J'obtiens un écart de 110 à 151 millisecondes, soit une différence maximale d'environ 4 nanosecondes par affectation. Donc, à moins que nous ne le fassions des centaines de milliers de fois par image, ce n'est probablement pas un problème à craindre, même s'il existe une différence mesurable dans un exemple synthétique comme celui-ci.
DMGregory
1
@DMGregory Accepté. C'est pourquoi il est toujours judicieux d'exécuter des tests de performances dans le bon contexte, avec des données réelles.
Mattias
1
Le problème avec la conversion implicite est qu'il yest en place. Lors de la conversion de a Vector3en a Vector2, vous voulez presque toujours xet z, pas xet y.
Kevin Krumwiede
6

Les deux Vector2 et Vector3 sont un struct dans le moteur Unity, donc la création d'un de l'autre implique simplement l'attribution d'un stockage sur la pile (sauf si la destination est un attribut d'une classe objet, ce qui permettrait de sauter cette première étape) et la copie des deux valeurs des composants. Les deux mécanismes que vous donnez doivent être compilés exactement pour ce code IL.

Si vous rencontrez un problème de performances avec une conversion de ce type, vous avez probablement un problème de boxe , la structure étant convertie en puis à partir d'un objet de classe . Dans ce cas, vous devez déterminer si, quand et comment la boxe peut être évitée dans les parties critiques de votre code.

Pieter Geerkens
la source
0

D'après mon test, la meilleure façon de le faire est d'attribuer manuellement sa valeur par vous-même.

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

C'est mon résultat que j'étends de Mattias.

TestConvertByOperation 10000000 instances: 0,3220527s

TestConvertByCasting 10000000 instances: 0,3226218s

TestConvertByInitializing 10000000 instances: 0.1916729s

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

Attention, je le teste avec l'unité version 5.6.5

Vimutti Roatkanjanaporn
la source