Cara paling efisien untuk mengonversi Vector3 ke Vector2


11

Apa cara paling efisien dan tercepat untuk mengubah Vector3 ke Vector2?

Pengecoran:

Vector2 vector2 = (Vector2)vector3;

Menginisialisasi Vector2 baru:

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

Atau ada metode lain yang saya tidak tahu?


11
Jenis operasi struct ini tidak akan pernah menjadi hambatan yang menentukan kinerja dalam game Anda, jadi daripada terjebak dalam optimasi mikro seperti ini, saya sarankan hanya menggunakan mana yang lebih jelas untuk dipahami dalam konteks yang Anda gunakan Itu. ;)
DMGregory

3
@DMGregory: Kecuali, tentu saja, OP telah melakukan analisis kinerja dan, mungkin karena tinju, sebenarnya memiliki ini dalam loop bersarang yang menyebabkan masalah kinerja. Loop bersarang seperti itu mungkin, misalnya, implementasi A-star atau Dijkstra.
Pieter Geerkens

5
@PieterGeerkens Fair, tetapi jika OP sudah melakukan analisis kinerja, mereka sudah mencoba kedua cara dan akan memiliki angka pada keduanya. ;) Dari menonton lintasan sejumlah pengguna Unity baru (termasuk saya), saya cukup yakin bahwa dalam hal ini optimasi mikro, jadi saya ingin membuat peringatan yang kuat (jika mungkin berlebihan) terhadapnya. Dengan cara itu terletak minggu atau bulan kode tweak dan resah atas optimalitas dalam cara yang tidak membuat permainan kami lebih baik.
DMGregory

Jawaban:


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

Vector3s dapat secara implisit dikonversi ke Vector2 (z dibuang).

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

Jika Anda harus membuat banyak konversi, Anda mungkin harus mengubah cara Anda menggunakan vektor Anda. Buat dua tes dan beri waktu untuk melihat mana yang cocok untuk Anda.

DIPERBARUI DENGAN UJI: Karena Anda bertanya yang mana yang tercepat, saya membuat tes yang menjalankan 10.000.000 konversi masing-masing di Unity. Tampaknya versi Inisialisasi tercepat dalam hal ini. TETAPI, Anda harus selalu menggunakan yang sesuai dengan konteks Anda sendiri, jadi saya sarankan Anda untuk menjalankan tes Anda sendiri di game Anda.

Contoh TestConvertByOperation 10000000: 0,2714049s

Contoh dari TestConvertByCasting 10000000: 0.286027s

TestConvertByInitializing 10000000 instance: 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
Mereka secara implisit dicor. Ini dilakukan dengan mendefinisikan operator konversi baru . Ironisnya Unity melanggar '... jika konversi dijamin tidak menyebabkan hilangnya data.' bagian.
Athos vk

1
Memperbarui jawaban saya dengan contoh kode untuk menguji berbagai pendekatan. Beri tahu saya yang mana yang lebih cepat dalam kasus Anda.
Mattias

1
Hasilnya bergeser sedikit dalam rilis / non-debug build, atau ketika data Vector2 memiliki seumur hidup di luar for for loop (yang membuat kompiler tidak melakukan jenis optimasi tertentu). Saya mendapatkan penyebaran 110 hingga 151 milidetik, atau perbedaan maksimum sekitar 4 nanodetik per tugas. Jadi, kecuali kita melakukan ini ratusan ribu kali setiap frame, ini mungkin bukan kasus yang perlu dikhawatirkan, bahkan jika ada perbedaan yang terukur dalam contoh sintetis seperti ini.
DMGregory

1
@DMGregory Setuju. Itu sebabnya selalu merupakan ide yang baik untuk menjalankan tes kinerja dalam konteks yang benar, dengan data nyata.
Mattias

1
Masalah dengan konversi implisit yadalah terserah. Saat mengonversi a Vector3menjadi Vector2, Anda hampir selalu menginginkan xdan z, tidak, xdan y.
Kevin Krumwiede

6

Baik Vector2 dan Vector3 adalah struct di mesin Unity, jadi penciptaan satu dari yang lain hanya melibatkan alokasi penyimpanan di stack (kecuali tujuan adalah atribut dari objek kelas , yang akan memungkinkan melewatkan langkah pertama ini) dan penyalinan kedua nilai komponen. Kedua mekanisme yang Anda berikan harus dikompilasi dengan tepat kode IL ini.

Jika Anda mengalami masalah kinerja dengan konversi jenis ini maka Anda mungkin memiliki masalah tinju , dengan struct yang dikonversi ke dan kemudian dari objek kelas . Dalam hal ini Anda harus menyelidiki apakah, kapan, dan bagaimana, tinju dapat dihindari di bagian-bagian penting dari kode Anda.


0

Dari pengujian saya, cara terbaik untuk melakukannya adalah menetapkan nilai sendiri secara manual.

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

Ini adalah hasil yang saya dapatkan dari Mattias.

Contoh TestConvertByOperation 10000000: 0,3220527s

Contoh dari TestConvertByCasting 10000000: 0,3226218s

TestConvertByInisialisasi 10.000000 instance: 0.1916729s

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

Harap dicatat, saya mengujinya dengan versi persatuan 5.6.5

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.