动态骨骼Dynamic Bone优化

栏目: 后端 · 发布时间: 6年前

内容简介:这是侑虎科技第484篇文章,感谢作者FrankZhou供稿。欢迎转发分享,未经作者授权请勿转载。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群465082844)作者主页:Dynamic Bone是基于弹簧质点算法的弹性节点模拟组件,可以用于柔性绳索和其他的简单的柔体,上一篇我们已经详细的对于算法进行过研究,

这是侑虎科技第484篇文章,感谢作者FrankZhou供稿。欢迎转发分享,未经作者授权请勿转载。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群465082844)

作者主页: https://www.zhihu.com/people/pkhere ,作者也是U Sparkle活动参与者,UWA欢迎更多开发朋友加入USparkle开发者计划,这个舞台有你更精彩!

Dynamic Bone是基于弹簧质点算法的弹性节点模拟组件,可以用于柔性绳索和其他的简单的柔体,上一篇我们已经详细的对于算法进行过研究, 想回顾的可以到这里查看

上周主要在对原版代码进行优化以适应大规模的应用,优化过程主要是减少了向量、矩阵的数学运算的消耗,缓存每个节点的状态变化,降低计算频度高,减少其一帧内的计算量,并且进行了ECS化和Job System的尝试,最终效果目前符合预期。

场景内50个模型,共450个组件对象,2700个节点 ,测试为PC环境,CPU为i7-8700,属于高配,数据仅供参考。

动态骨骼Dynamic Bone优化
优化的相关结果

DynamicBone经历一系列优化之后,单帧耗时下降非常明显,目前只有原始C#版本代码开销的4%不到。不考虑Culling和Distance机制仅有原版的2.5%的开销,对于distance的计算后面不会每帧去计算,最后会采用间隔几帧来处理,原版插件没有culling这部分。

上面数据的这一系列优化除了C#到C++的迁移之外,还涉及到Unity引擎内部的相关调整,在下面会一并的进行介绍。

一、Transform的结构与算法优化

Dynamic Bone优化过程遇到的Transform的最主要的性能坑点,或者说最主要的不必要的高额性能开销,就是Transform提供的最通用的各项全局数据(例如位置、旋转、变换矩阵等)的获取和设置接口开销相当之高。从上图的数据可以看出与Transform进行数据交互至少占了整个计算流程30%的时间;

Transform的数据读写接口的高耗时与其数据结构有关。由于Unity场景内所有GameObject都是以层级关系相互关联的,所以Transform使用层级关系结构来储存变换数据,每个Transform对应层级关系树中的一个节点,其只储存本身的局部位置、局部旋转和局部缩放;

这样Transform只用关心自身局部变换数据的修改,父节点发生变化后不用修改所有的子孙节点的数据(虽然实现上不是完全没有修改)。但是由于所有的Transform都只存储局部变换数据,所以当需要读取或者设置某个Transform的任何全局变换数据时,这个Transform都需要向上回溯计算得到他的全局变换数据。

动态骨骼Dynamic Bone优化
Unity的Transform结构

Transform的全局变换的计算开销问题本身可以用Cache处理——当每次读取Transform都将读取过程计算得到的结果储存到Cache,而当两次读取之间Transform的变换数据没有发生变化时,Transform不进行计算直接返回Cache值,需要计算时再进行更新计算——由于Unity中整体逻辑流程是串行的,没有逻辑上的并行(Job System只是计算并行),因此这个功能不难实现。

但是Transform却没有任何Cache逻辑,虽然其有一种ChangeMask机制用于保存当前Transform是否有过修改的信息,但是Transform没有基于ChangeMask建立Cache,这就导致对于Transform全局位置、旋转、缩放数据的每次读取和修改都会导致Transform从当前节点出发,逐层递归或者迭代直至根节点计算出全局变换数据;

这其中,SetPosition\SetRotation的逻辑也是会先逐层向上求逆,直到求到当前节点应有的局部变换数据之后再进行设置,但是与全局Getter函数不同的是,Setter函数求逆的过程是递归的,同样的简单逻辑递归的实现要比迭代耗时很多,这就导致Setter函数的性能更加低下;我们的优化也就对其进行了CACHE,CACHE后数据看出效率提升明显。

二、SIMD数学库对于普通数学库的修改

原始的代码是不经过SIMD的,改为C++代码以后编译也就编译器的默认的simd的优化,而Unity内部几乎所有的数学计算都使用它自己的数学库的SIMD优化,因此我们对代码进行了改写保持与引擎内部的计算一致。

动态骨骼Dynamic Bone优化

顺手进行了下测试,测试代码的编译环境是VC++2010,优化全开,通过查看反汇编代码可以看出VC编译器是会自动进行SIMD优化的;

结果中的向量点乘和四元数乘向量都有明显的SIMD优化,以至于普通运算耗时接近SIMD运算耗时,这对测试结果影响比较明显,但考虑到安卓平台编译环境依然可能有自动的SIMD优化,所以这里没有关闭编译器的SIMD优化开关;

从测试结果可以看出:

1、SIMD对向量四元数矩阵等数据结构运算优化是比较明显的,能减少40-50%的耗时;

2、虽然有编译器的自动SIMD优化,但是其优化幅度有限,实际优化还是要依赖技术手动调用SIMD接口;

三、ECS机制以及Job System化

ECS机制以及Job System是Unity为了提供代码性能而提出的设计框架,ECS即Entity-Component-System,核心理念是把原先的OOP思想改为DOD思想。DOD的好处是可以将同种数据集中到一起并放在内存中密集排布,大幅增加CPU Cache的命中率,降低代码抽象度,将数据独立出来,并且断开各种数据之间的耦合,这样Job System就可以将同种数据分散到不同的线程进行处理。具体ECS机制官方已经有详细的DEMO和数篇文章介绍,在这里也就不再重复,下面说说对于Dynamic Bone原始的结构改进以满足优化要求。

1.数据的拆分-ECS化

查看插件源码可以知道DynamicBone是每个实例各自储存自己的组件数据以及自身粒子(DynamicBone会将每根骨骼抽象为一个弹簧粒子)的数据,并且在每帧Update和LateUpdate中完成自身数据的更新,

我们增加了一个DynamicBoneManager进行整体的管理,Manager的好处可以统一储存所有组件和所有粒子的数据,并且所有数据都是以直接数组的形式平坦储存的;然后Manager会在自身的Update和LateUpdate中通过JobSystem一次性并行更新所有粒子的数据,并且将其Apply至对应的Transform对象上;

动态骨骼Dynamic Bone优化

经过这样设计以后,DynamicBoneManger把原本分散作为DynamicBone和Particle属性的数据全部集中在集合DynamicBones中,然后再对集合进行分类,分类依据就是DynamicBone组件对象拥有的节点数量;

动态骨骼Dynamic Bone优化

如上图中所示的DynamicBones对象,红框部分就是Particle数据,其他是DynamicBone数据以及有效列表数据,而这里Particle数据集合永远保持为其他DynamicBone数据集合大小的两倍,也就是说这个DynamicBones对象专门容纳有2个节点的DynamicBone对象的数据。同理,就可以创建N个DynamicBones对象,分别容纳有2到(N+1)节点的DynamicBone对象的数据。这样的设计完成后,所有组件和粒子的数据都是内存紧密排布的;Manager会一次性申请大量的空闲内存,而当新的组件Entity注册的时候,Manager只会就近找一个没有被使用的无效索引分配给这个组件Entity,并且将这个索引置为有效,随后初始化Component数据,并且将数据存入索引的空闲内存中。反之,当Entity注销的时候,Manager并不真正释放内存,而只是将这个索引置为无效. 同时,Manager会维护一个有效索引表,Manager每一帧只用按照这个表去更新有效索引指向的所有Component数据。

动态骨骼Dynamic Bone优化

2.Dynamic Bone的JobSystem使用

动态骨骼Dynamic Bone优化

由于Manager使用索引逻辑,所以Job只需要和有效索引一一绑定就好了,DynamicBoneManager的JobData内只有索引相关的信息,还有Component数组指针。每次当有索引被设置为有效,就会添加新的Job,反之就会删除存在的Job。例外补充一下对于Job的拆分后需要注意下本身的Job消耗太小比如处于0.001MS的消耗,建议对于Job进行BATCH测试,大家在2018的Job SYSTEM的使用中需要注意。

文末,再次感谢FrankZhou的分享,如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群:465082844)。

也欢迎大家来积极参与U Sparkle开发者计划,简称“US”,代表你和我,代表UWA和开发者在一起!


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

编程卓越之道

编程卓越之道

Hyde R / 韩东海 / 电子工业出版社 / 2006-4-1 / 49.80

各位程序员一定希望自己编写的代码是能让老板赞赏、满意的代码;是能让客户乐意掏钱购买的代码;是能让使用者顺利使用的代码;是能让同行欣赏赞誉的代码;是能让自己引以为豪的卓越代码。本书作者为希望能编写出卓越代码的人提供了自己积累的关于卓越编程的真知灼见。它弥补了计算机科学和工程课程中被忽略的一个部分——底层细节,而这正是构建卓越代码的基石。具体内容包括:计算机数据表示法,二进制数学运算与位运算,内存组织......一起来看看 《编程卓越之道》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

URL 编码/解码
URL 编码/解码

URL 编码/解码