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

面向数据设计与Unity3d ECS笔记

[复制链接]
发表于 2022-1-17 19:46 | 显示全部楼层 |阅读模式
1、部分历史

  • 2002 GDC,《A Data-Driven Game Object System》 http://scottbilas.com/files/2002/gdc_san_jose/game_objects_slides.pdf 用组合不用继承来实现游戏对象的实例,运行时组合带来了不少优势
  • 2006 《Out of Tar Pit》http://curtclifton.net/papers/MoseleyMarks06a.pdf 感觉这个可以认为是面向数据方法或ECS在软件工程方面的理论基础
  • 2007 《Entity Systems are the future of MMOG development》Entity Systems are the future of MMOG development - Part 1 这个系列基本上已经把ECS的概念阐述的很清晰了
  • 2010 《 Introduction To Data Oriented Design 》面向数据的性能优势在这里已经基本总结出来了
  • ?~2018《 Data-Oriented Design》 Richard Fabian https://www.dataorienteddesign.com/dodbook/ 作者应该跟进面向数据挺长时间了,软件工程层面与性能方面都有涵盖,但感觉作者比较偏激,不能除了面向数据就不能有别的开发方法了吧
  • 2015 《 Comments on Data Oriented Design》 Comments on Data Oriented Design – Part I Comments on Data Oriented Design – Part II 一些思考,似乎没有新的东西
  • 2020 《 Data oriented design is not about SoA and ECS》 Data oriented design is not about SoA and ECS – Alex Dixon 继续一些思考,好像也没啥新东西

2、概念

  • Entity---仅仅标识实体,没有方法、没有数据
  • Component---代表数据,没有方法
  • System---与某类或几类Component相关的行为,主动处理,集合处理
  • 依赖某种查询机制,来获取一个Entity集合上各Entity的符合条件的Component集合

    • 游戏对象数据库(key/Data/Query)
    • 关系数据库与关系代数
    • Unity3d ECS的EntityQuery

3、FRP范式论文《Out of Tar Pit》

  • 复杂性是软件工程的核心问题

    • 三种复杂性来源

      • 状态引起的复杂性(State)
      • 控制引起的复杂性(Control)
      • 代码量引起的复杂性(代码量的增长需要脑力的平方增长来理解)


  • 三种主要的编程范式

    • 命令式(以面向对象为代表讲述)
    • 函数式(Haskell、ML、Lisp)
    • 逻辑编程(Prolog)

  • 降低复杂性的解决方案

    • 分离状态与控制,亦即用户数据与核心逻辑
    • 分离本质状态、逻辑与偶然状态、逻辑,消除不必要的偶然状态、逻辑




  • 提出一种新的编程范式—函数关系式(FRP)


4、提升性能的原理

  • Cache友好(0~10倍提升)

    • 保证遍历时访问的数据连续存放并且只包含需要访问的数据
    • SOA---数组的结构
    • SOAOS--结构的数组的结构
    • Unity3d ECS的Component Data Chunk

  • SIMD(0~4倍提升)
  • multithread(0~8倍提升)

    • Job System

  • 分支预测,避免if/else(感觉提升不明显,同时很难避免)
  • 异构编程(严格说与ECS无关,但ECS好像通常就是在实现异构编程的cpu部分)

    • cpu--延迟消除架构,利用cache与缓存来消除延迟
    • gpu--延迟隐藏架构,利用大量并发与快速切换来隐藏延迟(SIMT)

5、unity ECS 0.17

  • system可以使用托管对象,job不可以,猜测原因是引用类型互相关联无法进行编译时分析,而job要运行在多线程必须保证没有数据访问冲突,因此不开启burst编译不使用多线程的job是可以使用托管数据的
  • component里不能使用数组,nativearray也不可以(官方说这个是暂时的限制,后续会努力消除)
  • shared component+archtype确定了chunk,目前看chunk的组织可以认为是固定的,或者说数据目前组织为2个层级:thunk与component data
  • 应优先用systembase和Entities.ForEach,除IJobEntityBatch外,其它IJob开头的接口已经不推荐使用
  • generic component应该是最多使用的component类型,后续应该会一直存在
  • buffer component用来记录动态变化的数据,这应该是为了弥补component里不能使用数组的限制
  • chunk component加IJobEntityBatch可以用来给每组同步数据或汇总每组数据

    • 因为chunk与component只有2级,所以只能用于2个层级的概念,比如一个部分作为一个整体可以接受指令,这些指令可以在部队逻辑里暂存到chunk component上,然后在IJobEntityBatch job里同步到部队里的各个单位。
    • 但是如果部队分为多个小队,每个小队再由单位构成这样的三层结构就没有类似的机制了

  • Blob Asset用来保存只读的信息,可以用于配置数据,能在component里使用

    • 这看来是在ECS里访问配置数据的官方途径
    • 否则可能就只能将配置数据复制多份放到component data上了

  • 在system里使用元素是struct的托管队列可以在system间传递信息,通过局部变量闭包,job里也能访问
  • system的惯用法其实是fork and join的多线程风格
6、一些问题

  • Unity3d ECS的版本目前还是早期实验性的,据说0.50版本2022年Q1推出,之后是1.0版本,但1.0版本只考虑支持unity 2022及以上版本
  • Unity3d ECS可能存在不必要的内存拷贝,在移动设备上对内存带宽有一定影响,基于struct的开发方式非常不自然,开发效率较低
  • chunk的组织方式只能是2级结构,对数据组织与遍历方式的设计有很大的约束
  • 各System间传递信息有时候还是需要借助非ECS的方式,很难仅仅借助component data来传递信息(不是共享信息)
  • 对功能逻辑,往往数据互相关联,component与system的拆分并不容易
  • system拆分的依据很模糊(感觉仍然得是功能导向的),性能的提升仍然需要借助profiler来确定,很难在开发过程中进行大致判断
  • 性能提升的技术原理来源于硬件底层,与问题域是割裂的,并且是实现细节相关的,在设计早期很难兼顾(因为此时如何实现还很模糊)
7、从面向对象到面向数据

  • 感觉面向数据方法依赖实现细节,所以不太适合在分析与设计层面使用,一种可能的方式是设计时仍然采用适合问题域的方法,然后性能要求高的部分与面向数据开发方法结合
  • 在实现上,可采用传统开发方法来为ECS准备数据与进行调度
  • 这种调度可能是单向的,也就是从传统方法过渡到面向数据方法后,不宜再返回到传统方法(过程而非函数)


8、native实现

  • 采用c++来实现ECS,感觉可能会更纯粹,比如内存拷贝或许更少,有机会应该试一试,不过缺少burst编译器,simd指令就需要自己来写了
  • rust是否可以用来实现ECS?rust语言的所有权概念似乎能有效的减少内存拷贝。

本帖子中包含更多资源

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

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

本版积分规则

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

GMT+8, 2024-9-22 21:22 , Processed in 0.090967 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

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