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 구현 일 수 있습니다.
Pieter Geerkens

5
@PieterGeerkens Fair이지만 OP가 이미 성과 분석을 수행했다면 이미 두 가지 방법을 모두 시도했을 것입니다. ;) 다수의 새로운 Unity 사용자 (자신을 포함하여)의 궤적을 보면서이 경우에는 미세 최적화 된 것이므로 확신 할 수 있습니다. 그 방법은 몇 주 또는 몇 달 동안 코드를 조정하고 게임을 더 나아지지 않는 방식으로 최적 성을 극복하는 것입니다.
DMGregory

답변:


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

Vector3은 암시 적으로 Vector2로 변환 될 수 있습니다 (z는 버림).

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

변환을 많이해야하는 경우 벡터 사용 방식을 변경해야 할 수도 있습니다. 두 가지 테스트를 수행하여 어느 것이 귀하에게 적합한 지 확인하십시오.

테스트로 업데이트 : 어느 것이 가장 빠른지 물었으므로 Unity에서 각각 10000000 변환을 실행하는 테스트를 만들었습니다. 이 경우 초기화 버전이 가장 빠릅니다. 그러나 항상 자신의 상황에 맞는 것을 사용해야하므로 게임에서 자신의 테스트를 실행하는 것이 좋습니다.

TestConvertByOperation 10000000 인스턴스 : 0.2714049s

TestConvertByCasting 10000000 인스턴스 : 0.286027s

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
다른 접근법을 테스트하기 위해 코드 예제로 답변을 업데이트했습니다. 어느 쪽이 더 빠른지 알려주세요.
Mattias

1
릴리스 / 비디 버그 빌드에서 또는 Vector2 데이터의 수명이 for 루프 외부에있을 때 결과가 약간 이동합니다 (컴파일러가 특정 유형의 최적화를 수행하지 못하게 함). 할당 당 110에서 151 밀리 초의 확산 또는 최대 약 4 나노초의 차이를 얻습니다 . 따라서 우리가 매 프레임마다 수십만 번을 수행하지 않는 한, 이와 같은 합성 예제에서 측정 가능한 차이가 있더라도 걱정할 필요는 없습니다.
DMGregory

1
@DMGregory 합의. 따라서 실제 데이터를 사용하여 올바른 컨텍스트에서 성능 테스트를 실행하는 것이 항상 좋은 생각입니다.
Mattias

1
암시 적 변환의 문제점은 작동 중 y입니다. 를 변환 할 때 Vector3A를 Vector2, 당신은 거의 항상 싶어 x하고 z,하지 xy.
케빈 크루 비에 데

6

Vector2Vector3 는 모두 Unity 엔진 의 구조체 이므로 다른 저장소를 만들려면 스택에 저장소를 할당하면됩니다 (대상이 클래스 객체 의 속성이 아닌 경우 첫 단계를 건너 뛸 수 있는 경우 제외 ). 및 두 성분 값의 복사. 제공하는 두 가지 메커니즘 모두 정확히이 IL 코드로 컴파일 해야 합니다.

이 유형의 변환으로 성능 문제가 발생 하면 구조체클래스 객체 로 변환되거나 클래스 객체 에서 변환되는 권투 문제 가있을 수 있습니다 . 이 경우 코드의 성능에 중요한 부분에서 권투 가 언제, 어떻게, 어떻게 피할 수 있는지 조사 해야합니다.


0

내 테스트에서 가장 좋은 방법은 수동으로 값을 할당하는 것입니다.

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

이것이 Mattias에서 확장 한 결과입니다.

TestConvertByOperation 10000000 인스턴스 : 0.3220527s

TestConvertByCasting 10000000 인스턴스 : 0.3226218s

10000000 인스턴스 초기화 : 0.1916729s

TestConvertByManualAssign 10000000 인스턴스 : 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;
        }
    }
}

Unity 버전 5.6.5에서 테스트합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.