紧密物理和碰撞循环中的高速缓存友好存储器访问

Nix*_*ixt 6 c++ performance memory-management game-physics data-oriented-design

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

我想要的功能:

  • 有一个代表PhysicsBody的类
  • 有一个表示碰撞体积的类(让我们说一个盒子)
  • 每个物理主体可以再附加一个碰撞体积
  • 可能没有碰撞体积的物理体
  • 可选:没有物理实体的CollisionVolume.(想想Trigger Volumes)

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

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

std::vector<PhysicsBody> m_bodies;
std::vector<CollisionVolume> m_colliders;
Run Code Online (Sandbox Code Playgroud)

我用这种方法发现的问题:

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

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

std::vector<PhysicsBody*> m_bodies;
std::vector<CollisionVolume*> m_colliders;
Run Code Online (Sandbox Code Playgroud)

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

还有其他更好的解决方案吗?显然,表现是关键.

Kal*_*anS 2

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

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

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

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

当您进入向量时,您就失去了对管理位置的直接控制。您可以通过使用内存池来取回其中的一部分。尽管如此,您仍然必须应对与调整大小操作相关的重定位问题。

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

vector<T> myVec;
myVec.reserve(NUM_ELEMS);
Run Code Online (Sandbox Code Playgroud)

接下来是来自连续内存区域的每个对象的就地 new。

myvec[i] = ...
Run Code Online (Sandbox Code Playgroud)

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