我正在编写一个物理引擎,并且很难找到设计数据存储的好方法。
我想要的功能:
- 有一个代表 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/