Unity DOTS(一):ECS 初探:大规模实体管理与高性能
DOTS 的全称:Data-Oriented Technology Stack,常译为数据导向技术栈
Dots的好处,一句话:DOTS 用“数据优先”的方式 + 多线程 + 本地化编译,把 Unity 在大规模对象场景下的性能、稳定性和可扩展性拉满,是显著提升性能的重要方法。
小编使用的Unity版本是:Unity2022.3.54.f1c1,推荐大家使用URP/HDRP管线,因为Dots的渲染仅支持 URP/HDRP,内置渲染管线不支持
1.插件安装
因为Dots技术现在还是预览版本,需要打开预览包的选项,才能找到包体,需要安装Entities跟Entities Graphics两个包体
预览包里面找不到的童鞋,可以直接代码拉取
http://com.unity.entities
http://com.unity.entities.graphics
1.ECS(组件,系统,实体)
ECS:Entity / Component / System,是DOTS 里的核心框架
-
Entity(实体):本质是一个轻量 ID。它“长什么样”完全取决于拥有哪些组件
-
Component(组件,IComponentData):纯数据
-
System(系统,ISystem/SystemBase):逻辑
大家可以右键快速创建ESC的脚本,里面会自由继承对应的接口,重新对应的方法
2.Burst 编译器
Unity 的 高性能编译器:把贴了 [BurstCompile]
的代码(尤其是 Job)编成原生指令,自动做 SIMD/向量化、内联、去边界检查 等优化。
开启enable Compilation
3.SubScene
Dots也提供了SubScene,放在SubScene下的物体将被自动转为实体
3.Demo
传统生成一万个cube物体时的FPS,在45帧左右
制作ECS流程的1w+Cube
Dots流程:Authoring(Mono) → Baker(烘焙) → IComponentData(纯数据) → System(逻辑/Job) → 渲染(Entities Graphics/URP)
还记得刚刚讲的知识,组件只放数据,系统写逻辑
组件
using Unity.Entities;
using Unity.Mathematics;public struct MoveTargetData : IComponentData
{public Entity Prefab; // 预制体的实体(由 Baker 获取)public int CountX;public int CountY;public float Spacing;
}
系统
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;[BurstCompile]
partial struct PrintFirstEntityPosSystem : ISystem
{public void OnCreate(ref SystemState state){state.RequireForUpdate<MoveTargetData>(); // 没有配置就不跑}public void OnUpdate(ref SystemState state){var e = SystemAPI.GetSingletonEntity<MoveTargetData>();var cfg = SystemAPI.GetComponent<MoveTargetData>(e);var em = state.EntityManager;int total = math.max(1, cfg.CountX * cfg.CountY);// 一次性批量生成(性能最好)using var instances = em.Instantiate(cfg.Prefab, total, Allocator.Temp);// 逐个设定初始 LocalTransform(位置/旋转/缩放)int i = 0;for (int x = 0; x < cfg.CountX; x++)for (int y = 0; y < cfg.CountY; y++){float3 pos = new float3((x - cfg.CountX / 2f) * cfg.Spacing,(y - cfg.CountY / 2f) * cfg.Spacing,0);em.SetComponentData(instances[i++],LocalTransform.FromPositionRotationScale(pos, quaternion.identity, 1f));}// 只生成一次:移除配置或销毁该配置实体em.DestroyEntity(e);}
}
Authoring 组件(MonoBehaviour) + Baker(烘焙器)
using Unity.Entities;
using UnityEngine;public class EnsureRenderableAuthoring : MonoBehaviour
{public GameObject prefab; // 拖你的 Cube 预制体public int countX = 100;public int countY = 100;public float spacing = 1.1f;class Baker : Baker<EnsureRenderableAuthoring>{public override void Bake(EnsureRenderableAuthoring a){// 1) 把“Cube 预制体”转换成可渲染、可移动的实体(很关键)var prefabEntity = GetEntity(a.prefab,TransformUsageFlags.Renderable | TransformUsageFlags.Dynamic);// 2) 在“当前这个 Authoring 对应的实体”上挂一份生成配置// (也可以用 CreateAdditionalEntity 放到一个全新实体上)var spawner = GetEntity(TransformUsageFlags.None);AddComponent(spawner, new MoveTargetData{Prefab = prefabEntity,CountX = a.countX,CountY = a.countY,Spacing = a.spacing});}}
}
使用Dots+开启Burst的编辑器后的FPS,直接来到250帧网上
5.其他
实体是没法在Scene视图中查看的,因此Dots有专门的面板查看
这下面就是转为的实体,实体的组件也与物体不一样,物理系统也需要重新适配