找回密码
 立即注册
查看: 309|回复: 0

Unity DOTS简明教程

[复制链接]
发表于 2021-9-12 15:31 | 显示全部楼层 |阅读模式
什么是DOTS

首先,先来了解下什么是DOTS?
DOTS是Data-Oriented-Tech-Stack,官方中文翻译是:多线程式数据导向型技术堆栈。
它主要由三部分组成:
    任务系统实体组件系统Burst编译器
下图是Unite2019的介绍截图:


所以,DOTS是一套集合型的高效技术堆栈,整合了Job System(编写多线程代码)、ECS(编写高性能代码)、Burst Compliler(编译生成高性能代码)。通过使用DOTS可以让Unity项目跑的更高效,在移动平台上可以表现为更高的fps,更低的电池消耗,更小的发热。另外关于ECS可以查看本博客的另一篇简明教程。
如何使用DOTS

(一)安装环境

先确认下版本,这里推荐最新Unity版本,博主这里用的是Unity2019.3正式版;
1.打开菜单栏-window->package manager,右侧的Advanced下拉切换为show preview package(截至目前2020.2.9依旧是预览版),安装:Burst、Entities、Jobs、Hybrid Renderer(用于DOTS的渲染相关)、Unity Physics(用于DOTS的高性能物理组件)


2.启用Entity Debugger(调试器),菜单栏-Window-Analysis-Entity Debugger,可以自行拖拽窗口到合适位置方便查看调试信息;


(二) 创建一个简单实例

(1)创建子场景:新建一个场景,创建一个Cube,移除Box collider组件,选中并右键New SubScene From Selection,当然也可以自行创建一个空物体,挂载SubScene脚本。


创建后则会自动在Assets下产生一个场景文件及对应的缓存文件。可以在Assets下自行更改刚创建的SubScene的名称,本质上还是一个Unity Scene,不一样的是Cube所挂载的父节点,多挂了一个SubScene脚本而已,用于管理和标记此场景是一个DOTS的SubScene。


在SubScene脚本下,可以进行一些配置,包括对应的场景、面板hierarchy 颜色,是否自动载入场景,关闭和启用编辑子场景,保存等。打开编辑时,可以在SubScene节点下自由编辑填充其他内容,可以参考project tiny 的小赛车项目,里面就将整个大地图就被作为了一个子场景。关闭编辑时,则整个子场景的子节点不可见,也不可编辑,被当作一个GameObject。
打开子场景编辑后,查看Entity Debugger,点击右边的All Entities(Editor World)可以看到当前子场景的一些状态信息,参考(一)2.图
(2)编码
创建一个C#脚本,Rotate.cs,没什么,就是一个结构体,它将作为数据:
  1. using Unity.Entities;
  2. public struct Rotate:IComponentData{
  3.   public float radiansPerSecond;
  4. }
复制代码
创建第二个脚本,RotateAuthoring.cs,主要作用是将GameObeject转化为Entity:
  1. using UnityEngine;
  2. using Unity.Entities;
  3. using Unity.Mathematics;using Unity.Transforms;
  4. public class RotateAuthoring :MonoBehaviour,IConvertGameObjectToEntity
  5. {
  6.     [SerializeField]
  7.     private float degresPerSecond;
  8.     public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)   
  9.     {        
  10.         dstManager.AddComponentData(entity, new Rotate
  11.             { ratiansPerSecond = math.radians(degresPerSecond) });        
  12.         dstManager.AddComponentData(entity, new RotationEulerXYZ());   
  13.      }
  14. }
复制代码
IConvertGameObjectToEntity接口用于将当前的GameObject(Cube)进行转换为DOTS的entity,然后绑定数据;
其中RotationEulerXYZ是transform的旋转,为了提高性能,DOTS里重写了一套组件,将原来的Transform里的旋转、位置、缩放等都单独出来。
第三个脚本是RotateSystem,继承自ComponentSystem,作用是做entity的行为驱动。
  1. using Unity.Entities;
  2. using Unity.Transforms;
  3. public class RotateSystem : ComponentSystem
  4. {   
  5.     protected override void OnUpdate()   
  6.     {        
  7.         Entities.ForEach((ref Rotate rotate, ref RotationEulerXYZ euler)=>        
  8.         {            
  9.             euler.Value.y += rotate.ratiansPerSecond * Time.DeltaTime;
  10.         });   
  11.     }
  12. }
复制代码
Entities.ForEach用于遍历当前所有的entity,然后将数据赋值给entity进行操作;
编写代码完毕,就将第二个脚本RotateAuthoring挂载在Cube上。设置DegresPerSecond的值为50:



运行项目,cube开始旋转。查看status:


(3)使用JobSystem进行优化

修改RotateSystem.cs脚本:
  1. using Unity.Entities;
  2. using Unity.Jobs;
  3. using Unity.Transforms;
  4. public class RotateSystem : JobComponentSystem
  5. {
  6.     private struct RotateJob : IJobForEach<RotationEulerXYZ, Rotate>
  7.     {
  8.         public float deltaTime;
  9.         public void Execute(ref RotationEulerXYZ euler, ref Rotate rotate)
  10.         {
  11.             euler.Value.y += rotate.ratiansPerSecond * deltaTime;
  12.         }
  13.     }
  14.     protected override JobHandle OnUpdate(JobHandle inputDeps)
  15.     {
  16.         var job = new RotateJob { deltaTime = Time.DeltaTime };
  17.         return job.Schedule(this, inputDeps);
  18.     }
  19. }
复制代码
主要变动是将继承改为了JobComponentSystem,增加了一个RotateJob,然后到OnUpdate中调用job;
(4)使用BurstCompile

在菜单栏中启用BurstCompile


在RotateSystem代码中的RotateJob结构体上添加[BurstCompile]特性,需要using Unity.Burst;
  1.     [BurstCompile]
  2.     private struct RotateJob : IJobForEach<RotationEulerXYZ, Rotate>
  3.     {
  4.         public float deltaTime;
  5.         public void Execute(ref RotationEulerXYZ euler, ref Rotate rotate)
  6.         {
  7.             euler.Value.y += rotate.ratiansPerSecond * deltaTime;
  8.         }
  9.     }
复制代码
(5)验证

开启SubScene的编辑,并大量复制cube,3000个以上。保存子场景。运行,开启unity编辑器的Status来查看:



我们发现,帧率依旧很稳定,只是Batches飙高到了3359。我们也需要优化掉:
(6)优化Batches
在Project面板下创建一个Material,命名为cube,并勾选Enable GPU Instancing.


选中子场景的所有cube,并将材质赋值到所有cube上。保存子场景,再次运行,发现batches已经获得了优化,帧率也大幅度提高。


小结

DOTS带来的性能改进是十分客观的,可以想象一些弹幕游戏、塔防游戏,使用上DOTS是可以非常直观的看到性能改进的。目前Unity也在大力推这套开发技术,相信未来会有越来越多的项目使用DOTS,并得益于DOTS.

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-28 11:01 , Processed in 0.103240 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表