微信号:Unity-GreaterChina

介绍:Unity官方开发者平台,分享最前沿的技术文章和开发经验,精彩的Unity活动和社区相关信息.

面向数据技术栈DOTS之ECS实体组件系统

2019-04-09 12:12 Unity

本文是面向数据技术栈DOTS的系列文章之一,我们将在本系列文章分享DOTS技术的进展以及未来的发展方向。


在《面向数据技术栈DOTS的C++和C#》文章中,我们介绍了Unity今后的底层基础技术:HPC#和Burst,我们把这种级别的技术栈称为“游戏引擎的底层引擎”。


任何人将可以使用该技术栈来编写游戏引擎,我们也会使用这些技术栈进行编写。同样地,如果你不喜欢我们的底层引擎,你也可以编写自己的底层引擎或按自己的喜好进行修改。


MegaCity

请观看Unite LA 2018大会上,Unity CTO Joachim Ante和Unity全球技术美术总监Martin Kümmel关于《MegaCity》的演讲。


《MegaCity》的灵感来自于知名的香港九龙城寨,是由一个二人团队,短短二个月时间创作出未来风格的城市景观,展示了本文中所描述的Unity新一代引擎技术面向数据技术栈DOTS的卓越性能。 



《Megacity》项目现已正式推出,可供下载使用,你可以拆分其中的内容,进行实验与研究,并通过它获得新项目的灵感启发。


《Megacity》项目下载地址:

https://unity.com/megacity


Unity的组件系统

我们要开发的下一个部分是全新的组件系统,Unity一直以组件的概念为中心。例如:我们可以添加Rigidbody组件到游戏对象上,使对象能够向下掉落。我们也可以添加Light组件到游戏对象上,使它可以发射光线。我们添加AudioEmitter组件,可以使游戏对象发出声音。


无论对程序员还是非程序员而言,组件都是非常容易理解的概念,它可以轻松地构建直观的UI。组件的演变非常令人惊讶,因此我们希望保留组件的概念。

 

我们实现组件系统的方法并没有很好地演变。我们过去使用面向对象的思维编写组件系统。组件和游戏对象都是“大量使用C++代码”的对象,创建或销毁它们需要使用互斥锁修改“id到对象指针”的全局列表。


所有游戏对象都有名称,每一个游戏对象都有指向C++相应对象的C#包装器对象。C#对象可以在内存的任何位置,C++也可以,所以会出现大量缓存丢失情况。我们想尽可能减小这种情况的影响,但可以做的事情并不多。

 

通过使用面向数据的思维方式,我们可以更好地处理这种情况。我们可以保留用户眼中的优良特性,即只需添加组件就可以实现功能,而同时通过新组件系统取得出色的性能和并行效果

 

这个全新的组件系统就是实体组件系统ECS。简单来说,如今我们对游戏对象进行的操作可用于处理新系统的实体,组件仍称作组件。那么区别是什么?区别在于数据布局。


下面是常见的数据处理模式,我们通常在Unity中会这样编写组件:

class Orbit : MonoBehaviour

{

   public Transform _objectToOrbitAround;

 

   void Update()

   {

       var currentPos = GetComponent<Transform>().position;

       var targetPos = _objectToOrbitAround.position;

       GetComponent<RigidBody>().velocity += SomehowSteerTowards(currentPos,targetPos)

   }

}


这种模式会被反复使用:组件必须找到相同游戏对象上的一个或多个组件,然后给它读取或写入数值。

 

这种方法存在很多问题:

  • 该Update()方法为一个Orbit组件而调用。下次Update()调用会面向完全不同的组件,在下次该代码为另一个Orbit组件运行这一帧时,它很可能造成代码从缓存移出。


  • Update()必须使用GetComponent()来找到Rigidbody组件。该组件也可以被缓存起来,但必须保证Rigidbody组件不被销毁。

      

  • 我们要处理的其它组件位于内存中完全不同的位置。

 

ECS使用的数据布局会把这些情况看作一种非常常见的模式,并优化内存布局,使类似操作更加快捷。


ECS数据布局

ECS会在内存中对带有相同组件集的所有实体进行组合。ECS把这类组件集称为原型(Archetype)。例如:由Position组件、Velocity组件、Rigidbody组件和Collider组件组成的原型。ECS以16k大小的块来分配内存,每个块仅包含单个原型中所有实体的组件数据。

 

我们不必使用用户的Update方法搜索组件,然后在运行时对每个Orbit实例进行操作,使用ECS时我们只需静态地声明:我想对同时附带Velocity组件、Rigidbody组件和Orbit组件的所有实体进行操作。为了找到所有实体,我们只需找到所有符合特定“组件搜索查询”的原型即可。

 

每个原型一个Chunks块列表,用来保存原型的实体。我们会循环所有块,并在每个块中,对紧凑打包的内存进行线性循环处理,以读取或写入组件数据。该线性循环会对每个实体运行相同的代码,同时为Burst创造向量化处理的机会。

 

很多情况下,这个过程会分成多个作业,使处理ECS组件的代码达到几乎100%的核心利用率。ECS会完成所有工作,我们只需要提供对每个实体运行的代码即可。我们也可以手动处理块迭代过程。

 

当我们从实体添加或移除组件时,ECS会切换原型。我们会把它从当前块移动到新原型的块,然后交换之前块的最后实体来“填补空缺”。

  

在ECS中,我们还要静态声明要对组件数据进行什么处理,是ReadOnly只读还是ReadWrite读写。通过确定仅对Position组件进行读取,ECS可以更高效地调度作业,其它需要读取Position组件的作业不必进行等待。

 

这种数据布局也处理了我们长期以来的困扰,即:加载时间和序列化的性能。为大型场景加载或流式处理ECS数据时,主要的操作是从硬盘加载和使用原始字节。

 

这就是《MegaCity》演示能以几秒时间在手机上完成加载的原因。


实体

实体是什么?实体只是一个32位的整数,所以除了实体的组件数据外,不必为实体保存或分配内存。实体可以实现游戏对象的所有功能,甚至更多功能,因为实体非常轻量。


实体的性能消耗很低,所以我们可以把实体用在不适合游戏对象的情况,例如:为粒子系统内的每个单独粒子使用一个实体。


下一代游戏引擎开发

我们需要开发的下一个部分非常庞大,它是由“渲染器”、“物理”、“联网功能”、“输入”、“动画”等功能组成的“游戏引擎”部分。我们已经开始开发引擎这部分功能,但是它们不会很快完成。

 

这么说或许有点令人失望,但从另一角度看,却未必会令人失望。因为ECS及建立在其之上的功能都通过C#代码编写,它可以在Unity中运行,所以我们可以编写使用“预ECS”功能的ECS组件。

 

虽然目前没有纯粹的ECS网格绘制系统,但我们可以编写一个特别的ECS MeshRenderSystem(网格渲染系统),它会使用预ECS的Graphics.DrawMeshIndirect API来实现,同时我们等待着ECS专用版本的推出,这就是《MegaCity》演示所使用的方法:加载、流式处理、剔除、LOD处理和动画制作都使用纯ECS系统完成,而最终绘制处理不使用纯ECS系统。

 

因此我们可以混合使用ECS的功能,这样做的优点是:我们可以同时让游戏代码利用Burst编译的优点和ECS的性能,不必等待Unity正式推出所有子系统的纯ECS版本。但缺点是:在这种传统阶段中,我们会遇到“结合使用二种不同功能”产生的阻碍。

 

我们会通过资源包发布ECS HPC#子系统的所有源代码。你可以查看,调试和修改每个子系统,并在更新子系统时有更好的粒度控制,例如:你可以只更新Physics物理子系统资源包,不必更新其它部分。


对游戏对象的影响

游戏对象不会发生任何改变。十年来,众多开发者成功地使用游戏对象开发出了许多优秀的游戏,这一基础不会发生任何变化。

 

发生改变的是,你将看到对游戏对象功能的特别改进逐渐转向ECS功能


API可用性和样板代码

对ECS的常见观点是:ECS需要编写很多代码。因此,实现想要的功能需要处理很多样板代码。现在针对移除多数样板代码需求的大量改进即将推出,这些改进会使开发者更简单地表达自己的目的。


我们暂时没有实现太多这类改进,因为我们现在正专注于处理基础性能,但我们知道:太多样板代码对ECS游戏代码没有好处,我们不能让编写ECS代码比编写MonoBehaviour更麻烦。

 

Project Tiny已经实现了部分改进,例如:基于lambda函数的迭代API。


Project Tiny的ECS如何适应这些变化

Project Tiny会基于C# ECS开发,它将成为ECS的重要里程碑:

  • Project Tiny能够运行在完全仅使用ECS的环境,它是没有过去包袱的全新项目。

  • 这意味着Project Tiny纯粹基于ECS,必须使用实际小型游戏需要的所有ECS子系统。

  • 我们将采用Project Tiny的编辑器支持,它会处理所有ECS环境的实体编辑功能,而不仅仅处理小游戏。


小结

面向数据技术栈DOTS之ECS实体组件系统为大家介绍到这里,后续的系列文章中,我们会介绍DOTS更多信息,尽请期待。

 

更多Unity技术文章分享,尽在Unity Connect平台(Connect.unity.com)。


推荐阅读


官方活动

直播预告|影视动画与游戏开发中的角色设计探讨

4月10日晚8点,Unity技术美术专家林翰为大家带来CG角色设计方面的知识分享。了解直播内容,请点击此处

直播地址:

https://connect.unity.com/events/live_session_cg_character_design


Unite Shanghai 2019

5月10日-12日上海,Unite大会强势回归。技术门票正在热销中,购票即获指定Asset Store资源商店精品21款资源的5折优惠券。

购票请访问:Unite2019.csdn.net



点击“阅读原文”访问Unity Connect

 
Unity官方平台 更多文章 使用Tilemap创作等距2D环境 3款创作游戏的五星工具资源包 直播预告|影视动画与游戏开发中的角色设计探讨 达哥课堂|使用Shader Graph制作飘动的巨龙 Planet:使用Unity构建《David Bowie is》AR应用
猜您喜欢 Openstack 云计算平台中的网络性能优化 自动化测试工具Watir pywebview 2.0发布 Ceph管理节点故障mds迁移到存储节点 伤心的人别喝鸡汤