前言
当游戏开发使用传统的OPP(面向对象编程)面对大量的Game object时FPS会显著降低,而使用Dots(面向数据编程)性能依旧很好
计算机内存基础
CPU自身有三级高速缓存,L1,L2,L3,其中CPU访问(L1)缓存最快,容量最小,第三级(L3)缓存最慢,容量最大。
内存是指CPU拿取数据的起源点,CPU访问内存所需的时钟周期远大于访问高速缓存所需的时钟周期
CPU处理数据的速度非常快,因此需要高速缓存区避免CacheMiss高速缓存缺失,以确保CPU一直在运行(未休息)
CPU操作数据会先从一,二,三级缓存中取得数据,如果数据不在三级缓存,就需要寻址内存中的数据
Dots(Data Oriented Tech Stack) 面向数据的技术堆栈
是一系列的集合
Entity Component System(ECS) :实体组件系统
Burst Compiler :Burst编译器 ,也是LLVM编译器
Job System :任务系统
masmatic:数学库
ECS
ECS即实体(Entity),组件(Component),系统(System),其中Entity,Component皆为纯数据向的类,System负责操控他们,这种模式会一定程度上优化我们的代码速度。
- Entities:游戏中的事物,但在ECS中他只作为一个Id
- Components:与Entity相关的数据,但是这些数据应该由Component本身而不是Entity来组织。(这种组织上的差异正是面向对象和面向数据的设计之间的关键差异之一)。
- Systems:Systems是把Components的数据从当前状态转换为下一个状态的逻辑,但System本身应当是无状态的。例如,一个system可能会通过他们的速度乘以从前一帧到这一帧的时间间隔来更新所有的移动中的entities的位置。
为什么ECS架构会加快性能?
将传统游戏对象杂乱无序的组件归类,当读取数据时无法从L1中找到,先从这一堆杂乱无序的内中找到需要的内存,然后将它读取并且移动到L1缓存中,移除L1不需要的数据(因为内存容量小),这个过程就会造成CacheMiss
而当我们用ECS的架构组织数据,它会将相同组件Component 整齐排列在内存中,当我们开始遍历相同组件时并不需要一个个从内存中读取,可以指定一个长度一次性全读进来放入缓存中,因此避免了CacheMiss
因此ECS模式无疑更加适合现代CPU架构
Burst Complier
Burst是使用LLVM从IL/.NET字节码转换为高度优化的本机代码的编译器。它作为Unity package发布,并使用Unity Package Manager集成到Unity中。 它全盘接管了我们编写的新C#编译工作,可以让我们在特定模式下无痛写出高性能代码。
JobSystem
它可以让我们无痛写出多线程并行处理的代码,并且内部配合Burst Complier进行SIMD优化。 你可以把JobSystem和Unity的ECS一起用,两者配合可以让为所有平台生成高性能机器代码变得简单。
masmatic
一个C#数学库提供矢量类型和数学函数(类似Shader里的语法)。由Burst编译器用来将C#/IL编译为高效的本机代码。
DOTS配置
注意unity版本
要使用 Entities 包,必须安装 Unity 版本 2022.3.0f1 及更高版本
必须使用可编程渲染管线:
内置渲染管线(Built-in Render Pipeline)不是可编程渲染管线
URP (Universal Render Pipeline)通用渲染管线,可编程
(High Definition Render Pipeline)(HDRP)高清渲染管线。可编程
安装包
- com.unity.entities工具包:包括ECS,Burst,Job System,masmatic
- com.unity.entities.graphics渲染entity
- com.unity.physics:ECS物理
- 通过window->packageManager->'+'加号->install package by name->install搜索
- 注意所有包的版本要一致,如果无法安装指定版本通过:
- 工程文件Packages/manifest.json中手动修正版本,重启引擎
IDE
版本要更新
unity设置
Edit > Project Settings > Editor菜单,然后启用 Enter Play Mode Options 设置,但禁用 Reload Domain 和 Reload Scene
c#Attribute特性
反射:
如果让你在不修改源代码的情况下,通过一个函数(参数为类类型),运行时获取所有参数为空的公有成员方法,这是不可能的
但是如果可以修改类呢?
- 可以让每一个类继承Object基类,每个类都手写一个FuncData的表(所有MetaData元数据(FuncData,PropData)数据表)
- 每个类都重写基类的public FuncData[] getFuncData();方法
这样就可以运行时获取
Attribute:
比如我们通过反射可以快速查找一个类是否仅包含数据
那如果我想要对特定类控制?
Attribute是反射的扩充,目的是在不破坏原有代码的 情况下,在代码的元数据上附加一些信息
[……]本质上:调用一个继承Attribute类的派生类的构造,通过注解可以快速查找包含指定属性的类,或者间接实现类的构造而非直接调用new等
其他性能优化
Object Pooling对象池
用于减少对象Instantiate()创建和destroy()销毁的性能开销,减少创建销毁api的调用
维护一个list<>
创建-》如果pool中没有obj,那么就instantiate,如果有就从池内取出对象
销毁—》使用完成放回池内
组合设计模式
- MVC(Model-View-Controller)
- MVP(Model-View-Presenter)
- MVVM(Model-View-ViewModel)
实现低耦合
本站资源均来自互联网,仅供研究学习,禁止违法使用和商用,产生法律纠纷本站概不负责!如果侵犯了您的权益请与我们联系!
转载请注明出处: 免费源码网-免费的源码资源网站 » Unity性能优化
发表评论 取消回复