https://www.youtube.com/watch?v=SecJibpoTYw
https://www.slideshare.net/unity3d/using-entity-command-buffers-unite-copenhagen-2019
https://docs.unity3d.com/Packages/[email protected]/api/Unity.Entities.EntityCommandBuffer.html
https://docs.unity3d.com/Packages/[email protected]/manual/entity_command_buffer.html
Using Entity Command Buffers – Unite Copenhagen 2019
并非所有游戏玩法都需要立即发生。 实际上,在许多情况下,延迟命令可能会提供更好的结果–改善用户体验,性能等。这些幻灯片探讨了在何处需要延迟命令的思考,并提供了有关如何充分利用实体命令缓冲区的示例。
Overview
— What are Entity Command Buffers?什么是实体命令缓冲区?
– Recording Commands记录命令
– Playback Order播放顺序
— Command Playback命令播放
– EntityCommandBufferSystems
– Immediate vs Deferred立即与延迟
— Traps to Avoid避免陷阱
— Possible Future Improvements未来可能的改进
Problem They Solve他们解决的问题
-Structural changes happen on the Main Thread主线程上发生结构更改
-Solution for recording changes in parallel through Jobs通过Jobs并行记录更改的解决方案
这些是什么?
–Chains of data transformations that are recorded记录的数据转换链
–Either from the Main Thread or within Jobs (Concurrent)从主线程中或在Jobs中(并发)
–Played back at a specific point in the future在将来的特定时间回放
–从EntityCommandBufferSystem
命令
–一些可用命令
–实例化,创建或销毁实体 Instantiate, Create, or Destroy an Entity
–添加,设置或删除组件数据Add, Set, or Remove Component Data
–向实体添加或设置IBufferElementData Add or Set IBufferElementData to an Entity
–添加或设置SharedComponent数据 Add or Set SharedComponent Data
–向EntityQuery中的每个实体添加或删除组件 Add or Remove Components to each Entity in an EntityQuery
– 主线程与并发命令 Main Thread vs Concurrent Commands
–主线程:托管数据正常 Main Thread: Managed Data OK
–并发:子集,不允许使用托管数据 Concurrent: Subset with No Managed Data Allowed
Main Thread Chain
— Single chain单链
— Played back in order of recording 按录制的顺序播放
Concurrent Chains并发链
— Multiple chains多个链
— Playback in order by JobIndex按JobIndex顺序播放
– JobIndex unique per batch of work 每批工作唯一的JobIndex
— Deterministic确定性
– JobIndex becomes a way to sort commandsJobIndex成为对命令进行排序的一种方式
– Large continuous chunks of monotonically increasing numbers连续大块单调递增的数字
Concurrent Chains Recording并发链记录
— Multiple threads recording from Concurrent EntityCommandBuffer to their own chain从并发EntityCommandBuffer记录到自己的链的多个线程
Concurrent Chains Playback (Today)并发链播放(今天)
— Find the batch with the lowest job index 查找job index最低的批次
— Start executing commands linearly until the end of the batch开始线性执行命令,直到批处理结束
— Repeat looking for the next smallest until done重复寻找下一个最小值,直到完成
Command Playback命令播放
Deferred vs Immediate Playback延迟与即时播放
— Deferred
– Scheduling Playback later in another EntityCommandBufferSystem稍后在另一个EntityCommandBufferSystem中安排播放
– Systems already there已经存在的系统
– Example: BeginInitializationEntityCommandBufferSystem示例
— Immediate
– Calling myCommandBuffer.Playback(…) right after recording录制后立即调用myCommandBuffer.Playback(…)
– PostUpdateCommands: Right after System’s Update() ||PostUpdateCommands:在系统的Update()之后
// Taken from SpawnFromEntity example BeginInitializationEntityCommandBufferSystem m_EntityCommandBufferSystem;
protected override void OnCreate()
{
// 1: Set your command buffer system
m_EntityCommandBufferSystem = World.GetOrCreateSystem();
}
protected override JobHandle OnUpdate(JobHandle inputDeps) {
// 2: Pass a Concurrent Command Buffer into the job
var job = new SpawnJob { CommandBuffer = m_EntityCommandBufferSystem.CreateCommandBuffer().ToConcurrent() }.Schedule(this, inputDeps);
// 3: Add the JobHandle to the Command Buffer System m_EntityCommandBufferSystem.AddJobHandleForProducer(job); return job;
}
示例 RPG 游戏,释放技能施毒,掉血伤害, DPS
Frame0的时候, 玩家对命中的Enemy
伤害, 技能, CD 三个系统
进入 Frame1 了
System Begin 的时候
Damage系统进行处理
Traps to Avoid 避免陷阱
Knowing When Data Is Available知道何时有数据
— Important to know when you will need that data to exist重要的是要知道何时需要该数据存在
— Tradeoff: Narrow window for playback vs longer deferment权衡:播放的窗口较窄,延迟时间更长
– Systems running between recording and playback will see the “old” data在录制和播放之间运行的系统将看到“旧”数据
Deferred Entities
— Instantiate(…) returns an Entity that’s deferred 实例化(...)返回一个延迟的实体
– It does not exist yet它尚不存在
– Has a negative Entity ID实体ID为负
— During Playback播放期间
– Entity gets a positive ID once it’s created实体创建后会获得一个肯定的ID
– Future references to that Entity in the chain are fixed up修复了链中对该实体的将来引用
Storing a Reference to a Deferred Entity ID存储对延迟实体ID的引用
— When your ComponentData stores a reference to some entity that will be created later当您的ComponentData存储对稍后将创建的某些实体的引用时
— That Entity will be invalid!该实体将无效!
Too Many Sync Points同步点太多
— Sync points can prevent a lot of work to be done in parallel同步点可能会阻止大量并行工作
— Playing back commands when you need that data在需要该数据时播放命令
— Consolidate those points to specific times in the frame将这些点合并到框架中的特定时间
– Use the pre-existing ECB Systems or create your own使用现有的ECB系统或创建自己的ECB系统
ECB Invalid After Playback播放后ECB无效
— Once it’s played back, can’t record to it again播放后,无法再次录制
— Error regarding a Native Container有关本机容器的错误
— Create a new ECB创建一个新的ECB
Possible Future Improvements 未来可能的改进
Bursted ECB
— Bursted Recording and Bursted Playback突发记录和突发播放
— Recording Available Soon! 即将提供录制!
Bursted ECB Code Example 突发ECB代码示例
// Taken from SpawnFromEntity example
[BurstCompile(CompileSynchronously = true)]
struct SpawnJob : IJobForEachWithEntity
{
public EntityCommandBuffer.Concurrent CommandBuffer;
public void Execute(Entity entity, int index, [ReadOnly] ref Spawner_FromEntity spawnerFromEntity, [ReadOnly] ref LocalToWorld location)
{
for (var x = 0; x < spawnerFromEntity.CountX; x++)
// CountX = 100 { for (var y = 0; y < spawnerFromEntity.CountY; y++)
// CountY = 100 { var instance = CommandBuffer.Instantiate(index, spawnerFromEntity.Prefab);
// Place the instantiated in a grid with some noise
var position = math.transform(location.Value, new float3(x * 1.3F, noise.cnoise(new float2(x, y) * 0.21F) * 2, y * 1.3F));
CommandBuffer.SetComponent(index, instance, new Translation {Value = position}); } } CommandBuffer.DestroyEntity(index, entity); } }
Without Burst (in ms) 0.64 With Burst (in ms)* *Average = 10x speedup 10kEntities
Batched Playback批量播放
— Processing certain commands in bulk for better performance批量处理某些命令以获得更好的性能
– Such as Instantiate or AddComponent如实例化或AddComponent
— All playback is still happening on the Main Thread所有回放仍在主线程上进行
Entity Manager Feature Parity实体管理器功能奇偶校验
— EntityManager has more options for each functionEntityManager为每个功能提供更多选项
– Such as AddComponent ( NativeArray
— Would like them to be unified希望它们被统一
Review评论
What To Remember要记住什么
— Chains of data transformations数据转换链
— Played back at a specific point in the future在将来的特定时间播放
— Think about the point when you need that data考虑一下何时需要该数据
— No managed data within jobs, therefore no commands with managed data within jobs作业中没有托管数据,因此作业中没有包含托管数据的命令
Thank you!