c++ - 紧密物理和碰撞循环中的缓存友好内存访问

标签 c++ performance memory-management game-physics data-oriented-design

我正在编写一个物理引擎,并且很难找到设计数据存储的好方法。

我想要的功能:

  • 有一个代表 PhysicsBody 的类
  • 有一个代表碰撞体积的类(比方说一个盒子)
  • 每个物理体都可以附加一个碰撞体
  • 可能有没有碰撞体的物理体
  • 可选:没有物理体的 CollisionVolume。 (想想触发音量)

现在我基本上有两个循环。 一个更新模拟中的物理体。它更新它们的位置/速度/旋转。 第二个循环对所有碰撞体执行碰撞检测。它只是一个嵌套的 for 循环,用于检查每对碰撞体积之间的碰撞。 (我知道它可以做得更好,但这是一个单独的主题)

我知道理想的方式是将对象存储在连续的数组中。

std::vector<PhysicsBody> m_bodies;
std::vector<CollisionVolume> m_colliders;

我发现这种方法存在的问题:

  • 很难维护 PhysicsBody -> CollisionVolume 关系。例如,如果我想从我的 vector 中删除一个 CollisionVolume,我会将它与最后一个交换并弹出。数据被移动,如果我将索引存储到 PhysicsBody 中的 CollisionVolume,它就不再有效。
  • 每当我销毁一个 PhysicsBody 时,析构函数都会检查它是否附加了任何碰撞体,并适本地将其从物理系统中移除。问题是 vector 会制作内部拷贝并销毁它们,当这种情况发生时,它将通过删除不应该删除的碰撞体积而造成严重破坏。
  • CollisionVolume 实际上是一个基类(不一定是),其他类从它派生,例如盒子/球体等等。我可能不使用继承并提出一些其他复杂的设计,但要记住这一点。

我努力寻找解决方法,但最终还是存储了指针:

std::vector<PhysicsBody*> m_bodies;
std::vector<CollisionVolume*> m_colliders;

我想出的最小化缓存未命中的最佳解决方案是重载新建/删除并将这些对象存储在专用于物理系统的内存池中。

有没有其他更好的解决方案?显然性能是关键。

最佳答案

一个基本问题:在没有线程运行和修改来自不同内核 (CPU) 的数据的情况下,您在哪里看到需要关心缓存一致性成本?

缓存一致性协议(protocol)仅当一行在与读取器核心不同的核心上变脏时才会触发,反之亦然。

看来您实际上是指缓存局部性?是吗?

与一致性对比。地方不碍事,这是我的看法:

在你进入 vector 的那一刻,你就失去了对管理局部性的直接控制。您可以通过使用内存池来取回其中的一部分。不过,您将不得不应对与调整大小操作相关的重定位。

你预先知道元素的数量吗?如果是,您可以这样做。

vector<T> myVec;
myVec.reserve(NUM_ELEMS);

接着是来自连续内存区域的每个对象的就地新建。

myvec[i] = ...

vector 和元素的内存也可以完全来自一个池。这可以通过在实例化 std::vector 时传入自定义分配器来实现。请看以下内容:

关于c++ - 紧密物理和碰撞循环中的缓存友好内存访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29960446/

相关文章:

java - 处理这个 "try - error - clean -retry"案例的最佳方法是什么?

c++ - C\C++开源PCM到Mp3转换器?

c++ - MSVC13 寻找错误的 boost 库版本

c++ - 二叉搜索树 - 制作字典

c++ - 如何提高多线程效率?

c - 你为什么用汇编编程?

linux - 是否可以在每个内核的基础上测量单个进程消耗的周期?

ios - 为了简单的操作而避免[弱 self ]?

c++ - 是否可以使用 Visual Studio 2013 Community Edition 创建静态库 C++?

docker - 为特定的Docker容器Debian设置max_map_count