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

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

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


优化的相关结果

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都需要向上回溯计算得到他的全局变换数据。


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优化,因此我们对代码进行了改写保持与引擎内部的计算一致。

顺手进行了下测试,测试代码的编译环境是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对象上;

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

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

2.Dynamic Bone的JobSystem使用

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


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

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

动态骨骼Dynamic Bone优化相关推荐

  1. Dynamic Bone ——Unity 3D动态骨骼插件

    Dynamic Bone插件的Unity Store链接地址https://assetstore.unity.com/packages/tools/animation/dynamic-bone-167 ...

  2. CEC2015:(一)动态多目标野狗优化算法(Dynamic Multi-objective Dingo Optimization Algorithm,DMODOA)求解FDA4与FDA5

    一.cec2015中测试函数FDA4.FDA5.FDA5_iso.FDA5_dec详细信息 CEC2015:动态多目标测试函数之FDA4.FDA5.FDA5_iso.FDA5_dec 二.动态多目标野 ...

  3. Unity【Dynamic Bone】- 关于人物模型头发、衣物等细节的处理

    关于Dynamic Bone的介绍: Dynamic Bone是一个Unity的动态骨骼插件,这个插件允许开发者指定对应的根骨骼,从而允许该骨骼的子骨骼进行物理结算,而根骨骼将不进行物理结算.Dyna ...

  4. Dynamic Bone

    Dynamic Bone插件的Unity Store链接地址:https://assetstore.unity.com/packages/tools/animation/dynamic-bone-16 ...

  5. 从五大结构体,带你掌握鸿蒙轻内核动态内存Dynamic Memory

    摘要:本文带领大家一起剖析了鸿蒙轻内核的动态内存模块的源代码,包含动态内存的结构体.动态内存池初始化.动态内存申请.释放等. 本文分享自华为云社区<鸿蒙轻内核M核源码分析系列九 动态内存Dyna ...

  6. CEC2015:动态多目标野狗优化算法求解CEC2015(提供完整MATLAB代码,含GD、IGD、HV和SP评价指标)

    一.动态多目标优化问题简介 现实世界中,许多优化问题不仅具有多属性,而且与时间相关,即随着时间的变化,优化问题本身也发生改变,这类问题称为动态多目标优化问题(dynamic multi-objecti ...

  7. Dynamic Bone(Unity拖尾插件)使用说明

    Root :拖尾所在骨骼群的第一个骨骼(跟3dMax的Spring拖尾插件类似) Roots:多个类似的骨骼群(跟Root二选一,都用于同类多个的骨骼,比如耳朵,胸等) Update Rate:运算频 ...

  8. 基于动态骨骼的动作识别方法ST-GCN

    解读:基于动态骨骼的动作识别方法ST-GCN(时空图卷积网络模型) 2018年04月09日 01:14:14 我是婉君的 阅读数 16076更多 分类专栏: 计算机视觉 论文 版权声明:本文为博主原创 ...

  9. 动态多目标优化算法:动态多目标狮群优化算法DMOLSO求解cec2015(提供完整MATLAB代码及所有测试问题的真实POF,含GD、IGD、HV和SP评价指标)

    一.CEC2015简介 现实世界中,许多优化问题不仅具有多属性,而且与时间相关,即随着时间的变化,优化问题本身也发生改变,这类问题称为动态多目标优化问题(dynamic multi-objective ...

最新文章

  1. 寻找一个字符串的重复子串 后缀数组
  2. Nature:揭示大脑中的免疫记忆
  3. springmvc是如何和前端页面联系起来的
  4. 继注册版权之后又将白皮书上传学术资料库,澳本聪为何这么执着?
  5. ResultSet 的相关介绍
  6. 单片机温度控制系统DS18B20
  7. Linux虚拟内存映射分析以及CMA测试 - 以SSD202为例
  8. 如何修复:There is no command installed for 7-zip archive files
  9. 揭秘-选择迅捷PDF转Word转换器的原因
  10. GridView控件RowDataBound事件中获取列字段的几种途径
  11. VisualSVN Server 和 SVN 服务器架设
  12. jmeter无法启动的解决办法
  13. 数学猜想验证步骤_高考数学19种答题方法,数学130+必备技能,附解题技巧word版!...
  14. 全自动mysql数据监控平台_Prometheus+Grafana打造Mysql监控平台
  15. 2021年6月安全生产月 全国安全知识网络竞赛 链工宝“测测你的安全力”最终最全题库 四百多道不重复真题、含答案 辛苦收集整理,供收藏学习
  16. unity自动生成敌人_unity 2d AI 敌人 自动追踪(2)
  17. 【Codeforces Round #476 (Div. 2) [Thanks, Telegram!] B】Battleship
  18. 提升计算机科学素养,中职学生计算机科学与技术专业素养提升策略
  19. mysql数据库二级_全国计算机二级mysql数据库模拟试题及答案
  20. 若要赞美晴天 请等到黄昏之后

热门文章

  1. 通过物联网网关如何进行三菱PLC的远程程序上下载?
  2. linux查看网卡驱动信息,linux 查看网卡驱动信息
  3. duckstation免费开源的ps1模拟器
  4. 【芯片验证学习纪实】System Verilog语法(1)
  5. FastAdmin对接易支付、码支付、源支付、免签插件
  6. layui数据表格增加序号列(第二页从1开始 or 接上一页序号开始)
  7. PMP学员:项目管理无处不在
  8. 测量学计算机,顾孝烈测量学第4版课后习题答案解析
  9. arduino pro mini NRF2401使用
  10. 子序列自动机 学习笔记