Vector3'ü Vector2'ye dönüştürmenin en etkili yolu


11

Vector3'ü Vector2'ye dönüştürmenin en verimli ve en hızlı yolu nedir?

Döküm:

Vector2 vector2 = (Vector2)vector3;

Yeni bir Vector2 başlatma:

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

Yoksa bilmediğim başka bir yöntem var mı?


11
Bu tür yapı işlemleri asla oyununuzda performans belirleyici darboğaz olmayacaktır, bu nedenle bunun gibi mikro optimizasyonlarda bataklıktan ziyade, kullandığınız bağlamda anlamak için hangisinin daha açık olduğunu kullanmanızı öneririm o. ;)
DMGregory

3
@DMGregory: Elbette, OP zaten bir performans analizi yapmadıysa ve belki de boks nedeniyle, bunu aslında iç içe bir döngüde bir performans sorununa neden olmadıkça. Böyle bir iç içe döngü, örneğin bir A-yıldızı veya Dijkstra uygulaması olabilir.
Pieter Geerkens

5
@PieterGeerkens Fuarı, ancak OP zaten performans analizi yapsaydı, zaten her iki yolu denerdi ve her ikisinde de sayı olurdu. ;) Bir dizi yeni Birlik kullanıcısının (ben dahil) yörüngesini izlemekten, bu durumda mikro optimizasyon olduğuna eminim, bu yüzden ona karşı güçlü (muhtemelen abartılmışsa) bir uyarı yapmak istedim. Bu şekilde, haftalar ya da aylarca yapılan kod değişiklikleri ve oyunlarımızı daha iyi hale getirmeyen şekillerde iyimserlikten korkmak yatıyor.
DMGregory

Yanıtlar:


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

Vector3s, dolaylı olarak Vector2'ye dönüştürülebilir (z atılır).

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

Çok fazla dönüşüm yapmanız gerekiyorsa, vektörlerinizi kullanma şeklinizi değiştirmeniz gerekebilir. İki test yapın ve hangisinin sizin için uygun olduğunu görmek için onları zamanlayın.

TESTLERLE GÜNCELLEME: Hangisinin en hızlı olduğunu sorduğunuzdan beri Unity'de her birinin 10000000 dönüşümünü çalıştıran bir test oluşturdum. Bu durumda Başlatılan sürümün en hızlı olduğu anlaşılıyor. ANCAK, her zaman kendi bağlamınıza uygun olanı kullanmalısınız, bu yüzden oyununuzda kendi testlerinizi yapmanızı tavsiye ederim.

TestConvertByOperation 10000000 örnekler: 0.2714049s

TestConvertByCasting 10000000 örnek: 0.286027s

TestConvertBy 10000000 örneği başlatma : 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
Bunlar dolaylı olarak dökülür. Bu, yeni dönüşüm operatörleri tanımlanarak yapılır . İronik olarak Unity, '... dönüşümün veri kaybına neden olmaması garanti edilirse' ihlal ediyor. Bölüm.
Athos vk

1
Farklı yaklaşımları test etmek için cevabımı bir kod örneğiyle güncelledim. Durumunuzda hangisinin daha hızlı olduğunu bana bildirin.
Mattias

1
Bir sürümde / hata ayıklamamış derlemede veya Vector2 verilerinin for döngüsü dışında bir ömrü olduğunda (derleyicinin belirli optimizasyon türlerini yapmasını önler) sonuçlar biraz değişir. 110 ila 151 milisaniyelik bir dağılım ya da görev başına maksimum 4 nanosaniye'lik bir fark elde ediyorum . Dolayısıyla, bunu her karede yüz binlerce kez yapmazsak, bunun gibi sentetik bir örnekte ölçülebilir bir fark olsa bile, endişelenecek bir durum değildir.
DMGregory

1
@DMGregory Kabul Edildi. Bu nedenle performans testlerini gerçek verilerle doğru bağlamda çalıştırmak her zaman iyi bir fikirdir.
Mattias

1
Örtük dönüşüm ile ilgili sorun y, yukarı olmasıdır. Bir dönüştürürken Vector3bir etmek Vector2, neredeyse her zaman istediğiniz xve zdeğil xve y.
Kevin Krumwiede

6

Hem Vector2 ve vector3 bir olan yapı Unity motoru, yani (hedef bir bir özelliği olmadığı sürece sadece diğerinden birinin oluşturulması yığında bir depolama tahsisini kapsar sınıfı bu ilk adımı atlayarak sağlayacak nesne) ve iki bileşen değerinin kopyalanması. Verdiğiniz Her iki mekanizma olmalıdır tam olarak bu IL koduna derlenmiş.

Bu tür bir dönüşümle ilgili bir performans sorunuyla karşılaşıyorsanız, büyük olasılıkla yapı bir sınıf nesnesine ve sonra sınıf nesnesine dönüştürülürken bir boks sorununuz vardır . Bu durumda , kodunuzun performans açısından kritik bölümlerinde boksun önlenip önlenemeyeceğini , ne zaman ve nasıl önlenebileceğini araştırmalısınız.


0

Testimden, bunu yapmanın en iyi yolu, değerini kendiniz manuel olarak atamaktır.

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

Bu benim sonucum Mattias'tan uzattığım.

TestConvertByOperation 10000000 örnekler: 0.3220527s

TestConvertByCasting 10000000 örnek: 0.3226218s

TestConvertBy 10000000 örneği başlatma: 0.1916729s

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

Unutmayın, birlik versiyonu 5.6.5 ile test ediyorum

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.