Найефективніший спосіб перетворення Vector3 в Vector2


11

Який найефективніший і найшвидший спосіб перетворити Vector3 в Vector2?

Кастинг:

Vector2 vector2 = (Vector2)vector3;

Ініціалізація нового Vector2:

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

Або є інший метод, про який я не знаю?


11
Ці типи структурних операцій ніколи не будуть визначати ефективність у вашій грі, тому замість того, щоб зануритися в такі мікро-оптимізації, я рекомендую просто використовувати те, що зрозуміліше зрозуміти в контексті, який ви використовуєте це. ;)
DMGregory

3
@DMGregory: Якщо, звичайно, ОР вже не зробила аналіз продуктивності і, можливо, завдяки боксу, насправді це є вкладеним циклом, що спричиняє проблеми з продуктивністю. Такий вкладений цикл може бути, наприклад, зіркою A або Dijkstra.
Пітер Ґеркенс

5
@PieterGeerkens Fair, але якби ОП вже робила аналіз продуктивності, вони б уже спробували обидва способи і мали б номери на обох. ;) Переглядаючи траєкторію ряду нових користувачів Unity (включаючи мене), я впевнений, що в цьому випадку це мікрооптимізація, тому я хотів зробити сильне (якщо можливо завищене) попередження проти цього. Таким чином лежать тижні чи місяці виправлення коду та намагання про оптимальність способами, які не покращують наші ігри.
DMGregory

Відповіді:


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

Vector3s можна неявно перетворити на Vector2 (z відкидається).

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

Якщо вам доведеться зробити багато перетворень, можливо, доведеться змінити спосіб використання своїх векторів. Зробіть два тести і приділіть їм час, щоб побачити, який з них працює.

ОНОВЛЕННЯ З ТЕСТОВАМИ: Оскільки ви запитали, який з них найшвидший, я створив тест із виконанням 10000000 перетворень кожної в Unity. Здається, що в цьому випадку версія ініціалізації є найшвидшою. Але, ви завжди повинні використовувати той, який відповідає вашому власному контексту, тому я раджу вам запустити власні тести у своїй грі.

10000000 екземплярів TestConvertByOperation: 0,2714049s

TestConvertByCasting 10000000 екземплярів: 0,286027s

TestConvertByІніціалізація 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;
    }

}

1
Вони неявно відлиті. Це робиться шляхом визначення нових операторів перетворення . За іронією долі, Unity порушує "... якщо конверсія гарантовано не призведе до втрати даних". частина.
Athos vk

1
Оновив свою відповідь прикладом коду, щоб перевірити різні підходи. Дайте мені знати, хто з них швидший у вашому випадку.
Маттіас

1
Результати трохи зміщуються у складанні випуску / не налагодження або коли дані Vector2 мають термін експлуатації поза циклом for (що не дозволяє компілятору робити певні типи оптимізації). Я отримую розкид від 110 до 151 мілісекунд, або максимальна різниця приблизно 4 наносекунди за завдання. Тому, якщо ми не робимо це в сотні тисяч разів кожен кадр, це, мабуть, не варто турбуватися, навіть якщо в такому синтетичному прикладі є вимірна різниця.
DMGregory

1
@DMGregory Погоджено. Ось чому завжди корисно запускати тести на ефективність у правильному контексті з реальними даними.
Маттіас

1
Проблема з неявною конверсією полягає в тому, що yвгору. Перетворюючи a Vector3в a Vector2, ви майже завжди хочете, xа z, не, xі y.
Кевін Крумвієде

6

І Vector2, і Vector3 є структурою в двигуні Unity, тому створення одного з іншого просто передбачає виділення сховища в стеку (якщо призначення не є атрибутом об’єкта класу , який дозволив би пропустити цей перший крок) і копіювання двох компонентних значень. Обидва механізми, які ви надаєте, повинні бути складені саме до цього ІЛ-коду.

Якщо ви стикаєтеся з проблемою продуктивності при перетворенні цього типу, то, ймовірно, виникла проблема з боксом : структура перетворюється на об'єкт класу, а потім на нього . У такому випадку слід дослідити, чи можна, коли і як уникнути боксу в критичних для продуктивності частинах вашого коду.


0

З мого тесту, найкращий спосіб зробити це вручну призначити його значення самостійно.

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

Це мій результат, який я поширюю від Маттіаса.

10000000 екземплярів TestConvertByOperation: 0,3220527s

TestConvertByCasting 10000000 екземплярів: 0,3226218s

TestConvertByІніціалізація 10000000 екземплярів: 0,1916729

10000000 екземплярів: 0.09500527s. TestConvertByManualAssign

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.