【问题标题】:ECS / CES shared and dependent components and cache localityECS/CES 共享和依赖组件以及缓存局部性
【发布时间】:2018-04-26 21:30:35
【问题描述】:

当存在共享或依赖的组件时,我一直在尝试了解 ECS 的工作原理。我已经阅读了很多关于 ECS 的文章,但似乎无法找到明确的答案。

假设以下场景:

我有一个实体,它有一个 ModelComponent(或 MeshComponent)、一个 PositionComponent 和一个 ParticlesComponent(或 EmitterComponent)。

ModelRenderSystem 需要 ModelComponent 和 PositionComponent。

ParticleRenderSystem 需要 ParticlesComponent 和 PositionComponent。

在 ModelRenderSystem 中,为了缓存效率/局部性,我想遍历紧凑数组中的所有 ModelComponents 并渲染它们,但是对于每个模型,我需要拉出 PositionComponent。我什至还没有开始考虑如何处理每个模型的纹理、着色器等(这肯定会破坏缓存)。

与 ParticleRenderSystem 类似的问题。我需要 ParticlesComponent 和 PositionComponent,并且我希望能够以缓存高效/友好的方式运行所有 ParticlesComponent。

我考虑过让 ModelComponent 和 ParticlesComponent 各有自己的位置,但是每次模型位置发生变化时都需要同步它们(想象一个角色上的粒子效果)。这会添加另一个需要跟踪和同步组件或值的实体或组件(并可能抵消任何缓存效率)。

其他人如何处理这些依赖问题?

【问题讨论】:

  • 我已经开始着手实施 ECS,并立即提出了与此相同的问题(有些奇怪的是,(现在)只有一个答案(现在)有 3 个赞成票)。从最初的问题过去了 2 年,您提出了令人满意的解决方案吗?您似乎需要在冗余重复数据(和同步问题)或更差的 CPU 缓存性能之间做出选择。

标签: game-engine entity-system


【解决方案1】:

降低复杂性的一种方法是反转数据流。

考虑您的ModelRenderSystem 有一个侦听器回调,允许实体框架通知它已将实体添加到包含位置和模型组件的模拟中。在此回调期间,系统可以在位置组件或拥有该组件的系统上注册回调,以便在该位置对象更改时通知ModelRenderSystem

随着位置变化的变化事件的到来,ModelRenderSystem 可以将它必须在更新阶段复制的修改列表排队,然后在更新期间,它实际上是一个简单的查找每个修改模型并将位置设置为事件中的值。

这样做的好处是,每帧,您只需要复制在该帧期间实际发生变化的位置变化,并且可以最大限度地减少复制数据所需的查找。虽然位置更新传播到各种感兴趣的系统可能不那么缓存友好,但您观察到的收益超过了这一点。

最后,不要忘记系统不一定需要迭代组件。实体系统中的组件允许您轻松切换可插入行为。系统始终可以管理对缓存更友好的数据结构,并使用上述回调方法,允许您以最小的耦合超级轻松地做到这一点并管理数据复制。

【讨论】:

  • 谢谢。一些很棒的建议。
  • 我很好奇。在消息传递技术中,有两个链接Position component -> message -> Render componentposition 的连续索引不太可能以与 render 相同的顺序放置,例如position[0]->message->render[1234]position[1]->message->render[98]。因此,在每个消息实现中,不可能使两个链接都缓存友好,对吧?我相信消息传递比 OP 更快,但它可以更好吗?
  • 这不是不可能的。我可以看到有一个基于实体 ID 升序排序的消息队列,并且以相同方式排序的渲染组件数组可能对缓存非常友好,因为您可以在迭代两个数组时利用内存预取。但同样,消息传递方法背后的想法是每帧,您正在处理一个很小的子集条目来更新,因此与您可能为其他非-message-isk 类型循环。
猜你喜欢
  • 1970-01-01
  • 2012-01-21
  • 1970-01-01
  • 2016-05-09
  • 2016-02-18
  • 1970-01-01
  • 2011-02-23
  • 2011-10-01
  • 2012-02-24
相关资源
最近更新 更多