Zephus 发表于 2023-2-17 08:28

UWA2020(八)_DOTS在Unity引擎不同模块中的应用

DOTS在Unity引擎不同模块中的应用

emmmmmmmmmmmmmmm这个视频看完感觉像是DOTS的简介

推荐一手ECS大手子:https://www.zhihu.com/people/benzx-84/posts

(Github正常排版: DOTS在Unity引擎不同模块中的应用)
<hr/>1. 简介
2. 渲染
3. 转换
4. 蒙皮动画
5. 物理
6. 场景
7. UI
8. 建议
<hr/>1. 简介


[*]DOTS(Data Oriented Technology Stack)

[*]有啥?

[*]Entity Component System(ECS)
[*]C# Job System
[*]Burst Compiler

[*]做啥?

[*]解决大批数据计算性能的问题

[*] 要啥?

[*]关注性能
[*]面向数据思想
[*]硬件并行能力




[*]ECS

[*]简介

[*]面向数据
[*]组成:Entity(id) Component(数据) System(逻辑)
[*]World拥有n个Entity,Entity拥有n个Component,System处理Component

[*]面向对象(非ECS)

[*]数据散放于内存中.(减慢缓存写入速度)
[*]多余数据一起加载.(占用缓存空间)

[*]ECS

[*]Archetype:不同Components的特定组合
[*]相同的Archetype的数据,在内存中,会连续存放于固定大小(16k)的Chunk中.(相关Component数据可以快速写入缓存)
[*]Chunk中同类型的Component数据连续存放(SOA).(同类型的数据线性存储避免缓存行浪费)

[*] ECS优点

[*]Chunk数据连续存放布局,可以提升缓存命中
[*]内存管理不使用托管堆,避免GC
[*]快速查询entity以及获取component数组数据的效率大幅度提高,远大于GameObject.Find,GameObject.Getcomponents


[*]Job System

[*]CPU多线程实现方式

[*]把主线程的事情,分割成一个个Job,放入JobQueue,再由JobQueue分发到多线程上处理

[*] C# Job System

[*]使用C#调用,隐藏线程调度,资源竞争等处理方式
[*]数据类型的限制,struct/blittable/非托管内存容器


[*]Burst

[*]简介

[*]基于LLVM的编译器
[*]把逻辑语言转换成中间语言,再对中间语言进行优化,最后把中间语言生成目标平台的机器码

[*]如:Clang->LLVMIR->x86/ARM等

[*]Unity实现了C#->.NET assembly,即逻辑语言到中间语言

[*]使用限制

[*]用于Job System和Function Pointer(FunctionPointer)
[*]不能使用引用类型
[*]无法trycatch
[*]无法访问托管对象
[*]无法写入静态变量

[*]优点

[*]因为代码进行优化,所以更高效运行
[*]SIMD指令优化,让数据并行处理

[*]以往A1+B1=C1,A2+B2=C2 2个指令
[*]Burst 可以只用 1个指令并行

[*]运行效率比肩C++,比IL2CPP快


<hr/>2. 渲染


[*]ECS渲染

[*]数据准备:位置+模型信息(Mesh+Material)
[*]调用Draw API / Hybrid Render

[*]Hybrid Render

[*]通过Package Manager安装
[*]渲染System(勾选RenderMeshSystemV2):Culling,API调用
[*]Entity需要挂载LocaltoWorld和RenderMesh
[*]LocaltoWorld->ComponentData

[*]个体自己的数据
[*]非托管chunk内存布局
[*]IComponentData

[*]struct类型
[*]使用blittabl变量,不能引用托管类型
[*]Managed IComponentData(引用类型用)

[*]Class类型,不能使用Burst,Job



[*] RenderMesh->SharedComponentData

[*]同chunk的Entity共同关联数据
[*]chunk之外由SharedComponentManager进行管理

[*]可以使用引用类型

[*]数据可以共享,对entity进行chunk进行分组

[*]降低Set pass call,优化GPU Instancing



[*]Draw API

[*]DrawMesh
[*]DrawMeshInstanced

[*]移动平台大部分兼容

[*]DrawMeshInstanceIndirect

[*]功能完善,移动平台不一定兼容

[*] BatchRendererGroup

[*]https://zhuanlan.zhihu.com/p/105616808?utm_source=qq
[*]Unity2019新增
[*]通用渲染类,兼容ECS,Builtin,SRP , 当前版本的Hybrid Render也用这个API
[*]渲染API的高层封装
[*]方便用户使用自己的culling方法

[*]var xx = new BatchRendererGroup(MyCullingMethod)



[*]对比

[*]BatchRendererGroupVSDrawMeshInstanced

[*]BatchRendererGroup有可以传入culling放
[*]DrawMeshInstanced没有culling,需要自己culling完成把结果传入渲染





[*]ECSVSGameObject(无Instance)

[*]ECS 的 Set pass call 更少,因为GameObject的渲染时,材质被打乱,Shader切换导致
[*]Batches 一样 , 因为大家都没有合批
[*]ECS 的 CPU耗时更低 , FPS更高





[*]ECSVSGameObject(有Instance)

[*]Batches 减少,GameObject的渲染,材质球合批被打乱导致
[*]ECS 的 CPU耗时更低 , FPS更高





[*]ECSVSGameObject

[*]ECS提升渲染效率
[*]避免GameObject管理开销(场景管理,逐物体方法的调用)
[*]属性更新适合Job加速运算

[*]如:让一堆cube向上移动
[*]GameObject + 25k Cube > 10FPS
[*]ECS + 25k Cube > 30FPS
[*]ECS + Job + 50K Cube >= 50FPS
[*]ECS + Job + Burst + 50K Cube = 60 FPS
[*]主线程耗时大大减少了,因为位置更新时,主线程出现了计算瓶颈



<hr/>3. 转换


[*]问题

[*]GameObject全部转换ECS任务艰巨

[*]MonoBehaviour组件逻辑转换System繁琐
[*]使用了复杂的渲染管线
[*]使用了第三方插件难以转换


[*]自动转换

[*]目的

[*]设计阶段保留Unity传统模式
[*]Runtime阶段使用ECS高效处理方式





[*] 方法

[*]渲染可能需要Hybrid Renderer
[*]挂载自动转换脚本 ConvertToEntity

[*]Transform -> LocalToWorld
[*]MeshRender -> RenderMesh

[*]转换自定义MonoBehaviour组件

[*]转移逻辑到System
[*]自定义数据转换

[*]GameObjectConversionSystem
[*]IConverGameObjectToEntity
[*]IDeclareReferencedPrefabs




[*]DOTS+GameObject混合使用

[*]目的

[*]ECS/Job System负责部分逻辑运算,使用GameObject进行渲染
[*]可以继续使用原来的渲染管线
[*]之前的MonoBehaviour继续有效





[*]举个粒子:ECS更新GameObject位置信息

[*]挂载ConvertToEnity脚本->选择Coversion Mode->Convert And Inject GameObject让LocalToWorld和Transform同时拥有
[*]方式一 : 直接在System中获取Transform组件

[*]ForEach(Transform).WithoutBurst().Run()

[*]方式二 : Job中更新Entity位置数据后,同步至GameObject

[*]需要给entity添加CopyTransformToGameObject
[*]EntityManager.AddComponentData(entity,new CopyTransformGameObject())

[*]方式三 : 使用IJobSystem

[*]使用IJobParallelForTransform 和 TransformAccess,只针对Transform
[*]可以用BurstCompile
[*]可以多线程更新transform信息,相同Root共线程
[*]不需要ECS的概念,改造简便

[*]如 10K Cubes + 位移

[*]主要耗时都在主线程上,ECS+Job使用了多线程缓解了压力



老做法ECS Injection(main thread)ECS Injection(Job)IJobParallelForTransform20FPS25FPS30FPS33FPS


[*]如 35K Cubes , MI9 Pro

方式帧率备注ECS + Job + Burst60FPSGO完全转换为ECS,并使用多线程更新属性ECS + Job54FPSECS30FPSIJobParallelForTransform11FPS无需ECS,针对TransformECS Injection10FPSECS与GO混合使用,利用Job多线程更新属性Classic(老做法)<8FPS<hr/>4. 蒙皮动画


[*]问题

[*] Hybrid Render / API绘制 都 不支持Skinned mesh

[*]解决方案

[*]Unity Animations

[*]开发中(emmmmm Unity一堆TODO的)

[*]GameObject+DOTS混用

[*]ECS Injection
[*]IJobParallelForTransform

[*]渲染Mesh,GPU进行动画

[*]Vertex Animation
[*]Geometry Shader 传入VerticesBuffer(Unity的SKinedMesh和原神都这么干)(https://zhuanlan.zhihu.com/p/126294753)

[*]需要DX10(Stream Out)或OpenGL ES 3.0(Transform Feedback) (https://www.zhihu.com/question/67301295/answer/251750311)

[*]GPU Skinning


[*]GPU Skinning + Instancing

[*]将动画信息写入纹理
[*]运行时在Shader中采样纹理,进行GPU Skinning
[*] GPU Animation

[*]https://blog.uwa4d.com/archives/UWALab_GPUAnimation.html


[*]ECS + GPU Skinning + Instancing

[*]烘焙动画纹理
[*]运行时ECS多线程更新位置及其其他角色信息
[*]调用DrawMeshInstanced/DrawMeshInstancedIndirect进行渲染
[*] 渲染时候用GPU Animation完成动画播放

[*]混合使用方案

[*]子弹等->ECS
[*]玩家角色->GameObject+ECS Injection
[*]小兵->ECS+GPU Skinning+Instancing

<hr/>5. 物理


[*]Unity Physics/Havok Physics

[*]相同的数据协议,Editor设置,切换方便
[*]Unity Physics

[*]C#开源
[*]扩展性强
[*]不依赖缓存
[*]效率相对慢,但是比原生快

[*]Havok Physics

[*]运算精确
[*]缓存策略提升性能
[*]效率相对快
[*]UnityPro用户订阅收费,但是新版本PackageManager好像免费

[*]如 20K Cubes

[*]GameObject FPS:8
[*]Unity Physics FPS:50
[*]Havok Physics FPS:60


[*]物理动画

[*]头发布料适合ECS/Job加速
[*]Automatic Dynamic Bone

[*]https://github.com/OneYoungMean/Automatic-DynamicBone

[*]UWA Blog

[*]https://blog.uwa4d.com/archives/Sparkle_DynamicBone.html


<hr/>6. 场景


[*]SubScene

[*]https://zhuanlan.zhihu.com/p/109943463
[*]加载/卸载效率高:SubScene -> RAM

[*]二进制存储,加载直接进入内存,不需要序列化
[*]多线程加载
[*]避免同一帧内大量GameObejct的active的调用

[*]限制

[*]本地存储,不能用到AssetBundle一些地方
[*]ECS,Prefab需要完全转换到ECS

[*]如 10k Trees (PC) 实例化

[*]GameObject Prefab 1518ms
[*]ECS Prefab 262ms

[*]如 1k Trees (Mi9 Pro) 实例化

[*]GameObject Prefab 97ms
[*]ECS 15ms


<hr/>7. UI


[*]DOTS UI

[*]DOTS UI

[*]https://github.com/supron54321/DotsUI

[*]DOTS UGUI

[*]https://github.com/initialPrefabs/UGUIDOTS

[*]ECS+Job+Burst加速网格重建

<hr/>8. 建议


[*]项目中使用DOTS建议

[*]交互简单,数量多的物体尝试ECS化

[*]植物,副本建筑等静态环境物体

[*]加载/实例化
[*]batch/instancing
[*]降低场景开销

[*]子弹,物理道具等交互简单的物体

[*]属性多线程更新
[*]DOTS Physics
[*]instancing
[*]快速查询

[*]小怪等重复动画

[*]GPU Skinning + Instancing
[*]属性多线程更新



<hr/>Emmmm,差不多都看完了,应该更新完了.
剩下的一些视频一些不方便总结(<<手中的银河>>,<<轻量级Web3D引擎关键技术及移动网页在线可视化示范应用>>).
还有一些视频可能不感兴趣,偏美术向,偏立项和项目管理,偏项目QA测试,所以就过了一遍不细写了.

ainatipen 发表于 2023-2-17 08:32

真复杂,,,内容真多,,,

kirin77 发表于 2023-2-17 08:40

挺实在,有个小问题:目录的链接不对

ainatipen 发表于 2023-2-17 08:50

知乎BUG 没有办法....正常排版要去GITHUB
页: [1]
查看完整版本: UWA2020(八)_DOTS在Unity引擎不同模块中的应用