Самый эффективный способ конвертировать Vector3 в Vector2

11

Какой самый эффективный и быстрый способ конвертировать Vector3 в Vector2?

Кастинг:

Vector2 vector2 = (Vector2)vector3;

Инициализация нового Vector2:

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

Или есть другой метод, который я не знаю?

С. Тарык Четин
источник
11
Эти типы структурных операций никогда не станут узким местом, определяющим производительность в вашей игре, поэтому вместо того, чтобы увязать в таких микрооптимизациях, я бы рекомендовал использовать то, что яснее для понимания в контексте, который вы используете. Это. ;)
DMGregory
3
@DMGregory: Если, конечно, OP уже не выполнил анализ производительности и, возможно, из-за упаковки, фактически сделал это во вложенном цикле, вызывая проблему производительности. Такой вложенный цикл может быть, например, реализацией A-star или Dijkstra.
Питер Гиркенс
5
@PieterGeerkens Справедливо, но если бы ОП уже проводила анализ производительности, они бы уже попробовали оба способа и имели бы цифры на обоих. ;) Наблюдая за траекторией ряда новых пользователей Unity (включая меня), я вполне уверен, что в данном случае это микрооптимизация, поэтому я хотел сделать сильное (если возможно завышенное) предупреждение против него. Таким образом, кроются многие недели или месяцы кодов, которые беспокоятся об оптимальности, и это не делает наши игры лучше.
DMGregory

Ответы:

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

Vector3s могут быть неявно преобразованы в Vector2 (z отбрасывается).

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

Если вам нужно сделать много конверсий, вам, возможно, придется изменить способ использования векторов. Сделайте два теста и рассчитайте, какой из них вам подходит.

ОБНОВЛЕНИЕ С ТЕСТАМИ: Так как вы спросили, какой из них самый быстрый, я создал тест, в котором 10000000 конверсий каждого в Unity. Похоже, что Инициализирующая версия является самой быстрой в этом случае. НО, вы всегда должны использовать тот, который соответствует вашему собственному контексту, поэтому я советую вам запускать собственные тесты в своей игре.

TestConvertByOperation 10000000 экземпляров: 0.2714049s

TestConvertByCasting 10000000 экземпляров: 0.286027s

TestConvertByInitializing 10000000 экземпляров: 0,1458781 с

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
Они неявно кастуются. Это делается путем определения новых операторов преобразования . По иронии судьбы Unity нарушает «... если преобразование гарантированно не приведет к потере данных». часть.
Athos vk
1
Обновил мой ответ с примером кода, чтобы проверить различные подходы. Дайте мне знать, какой из них быстрее в вашем случае.
Маттиас
1
Результаты немного изменяются в сборке выпуска / без отладки, или когда данные Vector2 имеют время жизни вне цикла for (что не позволяет компилятору выполнять определенные типы оптимизации). Я получаю разброс от 110 до 151 миллисекунды, или максимальную разницу около 4 наносекунд на назначение. Поэтому, если мы не будем делать это сотни тысяч раз за каждый кадр, это, вероятно, не повод для беспокойства, даже если в синтетическом примере, подобном этому, есть ощутимая разница.
DMGregory
1
@DMGregory Согласен. Вот почему всегда полезно запускать тесты производительности в правильном контексте с реальными данными.
Маттиас
1
Проблема с неявным преобразованием в том, что yвверх. Преобразовывая Vector3в a Vector2, вы почти всегда хотите, xа zне xи y.
Кевин Крумвиде
6

И Vector2, и Vector3 являются структурой в движке Unity, поэтому создание одного из другого просто включает выделение хранилища в стеке (если место назначения не является атрибутом объекта класса , что позволило бы пропустить этот первый шаг) и копирование двух значений компонентов. Оба механизма, которые вы даете, должны быть скомпилированы именно для этого кода IL.

Если вы столкнулись с проблемой производительности с преобразованием этого типа , то вы , вероятно, бокс проблемы с структура преобразуются в и затем из класса объекта. В этом случае вам следует выяснить, можно ли избежать , когда и как, в определенных частях кода, связанных с производительностью , бокса .

Питер Гиркенс
источник
0

Из моего теста лучший способ сделать это - вручную установить его значение.

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

Это мой результат, который я расширяю от Маттиаса.

TestConvertByOperation 10000000 экземпляров: 0.3220527s

TestConvertByCasting 10000000 экземпляров: 0.3226218s

TestConvertByInitializing 10000000 экземпляров: 0,1916729 с

TestConvertByManualAssign 10000000 экземпляров: 0,09500527 с

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;
        }
    }
}

Обратите внимание, я тестирую его с единой версией 5.6.5

Вимутти Роатканжанапорн
источник