

Unity新版数学库简介(七)
dvuCR5AddC
程序员
阅读 2710
2020年3月11日
Unite2019哥本哈根学习笔记之Introduction to Unity.Mathematics
1.
转换你的游戏到DOTS(一)https://connect.unity.com/p/zhuan-huan-ni-de-you-xi-dao-dots-yi
2.
转换场景数据到DOTS(二)https://connect.unity.com/p/zhuan-huan-chang-jing-shu-ju-dao-dots-er
3.
拆解DOTS工作流程(三) https://connect.unity.com/p/chai-jie-dotsgong-zuo-liu-cheng-san
4.
DOTS创建第三人称僵尸射击游戏(四)https://connect.unity.com/p/dotschuang-jian-di-san-ren-cheng-jiang-shi-she-ji-you-xi
5.
Burst 编译器入门(五)https://connect.unity.com/p/burst-bian-yi-qi-ru-men-wu
6.
Burst 编译器底层开发(六)https://connect.unity.com/p/burst-bian-yi-qi-di-ceng-kai-fa-liu
终于迎来了一张亚洲面孔的小哥哥,看他分享的还是比较带劲的,我们就给他起名“亚洲小哥哥”(起名是这套教程的传统哈哈~)如果想在项目中更好的应用SIMD,新版数学库一定要学好!

什么是新版数学库Unity.Mathematics?
1.
像shader代码中一样写法的数学库,比如float4(1,2,3,4)这种写法,并且支持SIMD
2.
同样支持向量float2 float3、矩阵float3x3 float4x4、四元数quaternion
3.
还有一些常用的基本数学函数。比如,min max fabs sin cos sqrt normalize dot cross 等等

什么时候会使用到数学库
1.
DOTS中的实体包、物理包、Burst编译器都需要用到新版数学库
2.
浮点数确定性,在多个平台下浮点数计算出的结果可能不一致,使用新版数学库未来会保证一致性(未来支持这项功能,现在还不支持) 比如像帧同步这样的游戏,必须要保证计算结果一致。
3.
新版数学库会提升性能

什么时候不会使用新版数学库
1.
新版数学库和原本的UnityEngine.Mathf并不一样。
2.
无法将UnityEngine.Mathf直接切换到新版数学库,免不了需求修改代码
3.
比如依赖一些第三方库,它们内部就是传统的Mathf,或者它们直接使用Vector和Materix4x4的方法进行运算的。不过我们可以将vector3、Materix4x4直接等于float3 flot4x4,它内部实现了运算符重载使用起来挺方便的。
Vector3 v = float3(0, 1, 0);
float3 a = v;
transform.position = v;
transform.position = a;

在PackageManager中安装数学库

引用Unity.Mathematics命名空间 using static Unity.Mathematics.math;

开始进入例子环节,例子1,两个Vector4向量相乘,传统的方式使用Vector4.Scale(x,y)

新版数学库可以直接相乘,并且它们是SIMD一条CPU指令同时计算4个结果出来,效率是很高的。

例子2,创建一个矩阵,很容易看懂两者的区别。


例子3,注意两个矩阵相乘的结果是不一样的,新版数学库的结果显然更好理解一些。


float4x4 a = Matrix4x4.identity;
float4x4 b = new Matrix4x4() {
m00 = 0.5f,m01 = 0.5f,m02 = 0.5f,m03 = 0.5f,
m10 = 0.5f,m11 = 0.5f,m12 = 0.5f,m13 = 0.5f,
m20 = 0.5f,m21 = 0.5f,m22 = 0.5f,m23 = 0.5f,
m30 = 0.5f,m31 = 0.5f,m32 = 0.5f,m33 = 0.5f
};
Matrix4x4 a1 = a;
Matrix4x4 b1 = b;
Debug.Log(a * b);
Debug.Log(a1 * b1);
例子4,矩阵4乘向量4,由于矩阵相乘本身就不满足交换律,所以传统的乘法不能交换乘数与被乘数,必须是矩阵4乘向量4,如果向量4乘矩阵4则会报错

新版数学库可以用math.mul就可以随意的乘了,因为自己提供了调用函数它满足交换律了。

例子5,已知一个欧拉角度(45,90,180)绕着Y轴方向旋转45°。

由于版数学库使用的是弧度,角度取值范围0-360度,而弧度的取值范围是0-2π(0-6.28)角度与弧度之间可以乘一个常量来相互转换,新版数学库中的math.radinas就是将角度转换成弧度。

例子6,随机数,传统的方式生成随机数使用UnityEngine.Random就可以。Random.Value就可以取到一个0至1(包含)之间的随机数,Random(x,y)可以取到x(包含) 至y(包含)之间的随机数。

新版数学库需要提供随机数种子,看起来似乎比之前的麻烦,但其实有了种子会更加灵活。UnityEngine.Random无法在多线程中使用,而Unity.Mathematics.Random可以在多线程中用,并且可以让每个线程线程的随机数不同,还有个好处就是,如果是相同种子生成的随机数是一致的。

新版数学库可以提供各种各样的随机数类型,比如float flaot2 int3 bool4 等等,注意NextInt(0,1)由于右边是不包含1,所以这样取出来的随机数永远只是0。

1.
如果需要将传统的数学库换成新版数学库,直接粘贴复制可能行不通
2.
矩阵、向量、弧度制、随机数生成都和传统数学库不一样
3.
有些地方不要盲目切换新数学库,仔细对比两者区别在考虑。
4.
传统数学计算和新版数学库计算的结果可能略有不用,比如四元数,但是由于精度费非常低可以忽略不计
5.
新版数学库对外的接口都在C#中,大家可以查看代码。比如我们想看看nul矩阵乘法,可以点进去看看它是如何实现的。

再次回到性能问题上,一百万次 向量4相加、矩阵4向量4相乘、向量4矩阵4相乘、矩阵4逆矩阵,对比Mono、Il2cpp、Burtst编译器以及传统unity数学的效率如何?

从下往上是毫秒数,柱状条越高代表越耗时。可以看出传统的数学库中,Il2cpp+Burst和Mono+Burst效率差不多计算速度最快、接着是Il2cpp、Mono计算效率最慢。

然后我们换成新版的数学库来做同样的事情,几乎是完全秒杀传统的数学库了。

可以看出新版数学库单纯数学计算上性能超了大概10倍。

例子1,向量4相加,似乎在IL2cpp + Burst模式下,传统的数学库比新版数学库还要快0.4毫秒。

例子2,矩阵4乘以向量4,似乎在IL2cpp + Burst模式下,传统的数学库比新版数学库还要快1.1毫秒。

例子3,矩阵4乘以矩阵4在IL2cpp + Burst模式下,新版数学库扳回一城,比传统数学库快2.8毫秒。

例子4,逆矩阵4,新版数学库显然已经超神比传统数学库快了6倍,性能杠杠的。

目前看来传统数学库和新版数学库各有优劣,那么到底谁的最终的赢家呢?通过上面的4个例子,为什么在逆矩阵的情况下新版数学库效率上会大幅度反超?

传统的数学库在计算逆矩阵在C++中完成的,它用到了高斯消除法,而新版数学库则使用的SIMD,所以性能会有一个巨大的差异。

来看看新版数学库编译出来的汇编指令,哇!清一色的xxxxps指令,效率强到爆炸。(如果对SIMD汇编指令不了解的朋友可以看我上一篇文章)

movups表示移动指令,它可将内存中的矩阵4加载到xmm7 xmm0 xmm1 xmm3 四个寄存器中

每个寄存器中存了128位也就是4个float数据,然后分别对上面4个寄存器进行mulps相乘、addps相加、subps相减 由于SIMD一次CPU指令操作的是4个float 所以速度会非常快

4个寄存器中已经完成了逆矩阵操作,最终这4个寄存器中的数值传递给内存中。

小哥哥给了个满意的微笑表情

在看看Il2cpp版本,没有Burst编译的情况,原本丝滑的xxxps指令大部分变成了xxxss指令,ss指令上篇我们也讲过,虽然它保存的是4个float但实际参与计算的只有1个float,这样效率就打折扣了

新版数学库中,看到了吗?我们使用的是m128一次进行4个float的计算。

来看看LI2CPP的代码,由于IL2CPP的代码是通过DLL生成的,并不是直接通过C#编译的,这样就会造成上下文的丢失,最终生成结果不是那么令人满意。

新版数学库和Burst一起使用
1.
不会造成IL2CPP后代码上下文的丢失。
2.
数据可以直接映射在CPU内部执行。
3.
如果使用SIMD风格编程,就是上百篇提到过的,尽量使用float4 、bool4、这样的,不建议使用float3和bool3。
4.
Burst不会变魔术的帮你自动向量化代码,需要我们自己指定。比如float3点乘float3可以用float4进行点乘只不过不计算z,上一篇有这个介绍。

如果使用mono 不带burst 不要使用unity.mathematics,如果使用burst或者il2cpp就一定要使用unity.mathematics

结论
1.
Unity.Mathematics现在已经可以使用,结合使用DOTS和Burst会让他性能更好
2.
根据自己的情况考虑使用新版数学库,比如那些对性能有要求的代码,老代码的移植、是否计划未来使用DOTS。

最后给这个帅气的小哥哥点赞吧!

发布于技术交流
0条评论

问
AI
全新AI功能上线
1. 基于Unity微调:专为Unity优化,提供精准高效的支持。
2. 深度集成:内置于团结引擎,随时查阅与学习。
3. 多功能支持:全面解决技术问题与学习需求。

问
AI