将Vector3转换为Vector2的最有效方法


11

将Vector3转换为Vector2的最有效,最快的方法是什么?

铸件:

Vector2 vector2 = (Vector2)vector3;

初始化一个新的Vector2:

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

还是我不知道另一种方法?


11
这些类型的struct操作永远不会成为游戏中决定性能的瓶颈,因此,我建议不要使用像这样的微优化而感到困惑的方法,而只是使用在您所使用的上下文中更清楚地了解的一种方法它。;)
DMGregory

3
@DMGregory:当然,除非OP已经进行了性能分析,并且可能是由于装箱,否则实际上是在嵌套循环中进行此操作,从而导致性能问题。这样的嵌套循环可能是A-star或Dijkstra实现。
Pieter Geerkens '16

5
@PieterGeerkens Fair,但如果OP已经在进行性能分析,他们将已经尝试过两种方法,并且两种方法上都有数字。;)通过观察许多Unity新用户(包括我自己)的运行轨迹,我非常有信心在这种情况下它是微优化的,因此我想对此提出强烈的警告(如果可能夸大了)。那就是数周或数月的代码调整,并以无法使我们的游戏变得更好的方式为最优而烦恼。
DMGregory

Answers:


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

TestConvertByInitializing千万实例: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。将a转换Vector3为a时Vector2,几乎总是需要xand z,而不是xand y
凯文·克鲁姆维德

6

Vector2的Vector3是一个结构在Unity引擎,因此从另一个简单的创建涉及在堆栈上存储的分配(除非目标是一个的属性 对象,这将允许跳过该第一步骤)并复制两个分量值。您提供的两种机制都应完全编译为该IL代码。

如果您遇到这种类型的转换带来的性能问题,那么您可能会遇到装箱问题,将结构转换为对象,然后再转换为对象。在那种情况下,您应该调查在代码的性能关键部分中是否可以避免装箱以及何时避免装箱


0

根据我的测试,最好的方法是自己手动分配其值。

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

这是我从Mattias扩展过来的结果。

TestConvertByOperation 10000000实例:0.3220527s

TestConvertByCasting 10000000实例:0.3226218s

TestConvertBy初始化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;
        }
    }
}

请注意,我使用统一版本5.6.5进行了测试

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.