网络游戏之快照插值物理模拟

标签: 网络游戏
91人阅读 评论(0) 收藏 举报
分类:

笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。

CSDN视频网址:http://edu.csdn.net/lecturer/144

我们使用帧同步网络物理模拟 现在,在这篇文章中,我们将使用完全不同的技术对相同的仿真进行网络连接:快照插值。

随着玩家数量的增加,帧同步骤变得有问题:您无法模拟帧n,直到您从所有玩家接收到该帧的输入,所以玩家

最终等待最落后的玩家。 因此,我至多为2-4名玩家推荐帧同步技术,这也是帧同步广泛应用于竞技游戏的原因

所以如果你的模拟不是确定性的,或者你想要更高的玩家数量,那么你需要一种不同的技术。 快照插非常适合

在许多方面与帧同步相反:帧同步运行两个模拟,一个在左边和一个在右边,并使用同步输入保持它们同步,快照插值不运行任何模拟 右边一切!快照

插值不运行任何模拟右边一切!

相反,我们从左侧的仿真中捕获所有相关状态的快照,并将其传输到右侧,然后在右侧,我们使用这些快照重建模拟

的视觉近似,所有这些都不运行模拟本身。让我们发送渲染每个立方体所需的状态:

  struct CubeState
    {
        bool interacting;
        vec3f position;
        quat4f orientation;
    };
现在我已经确定,这项技术的成本增加了带宽使用。 大幅增加带宽使用率。 由于快照包含整个模拟的视觉状态,

有了一些数学,我们可以看到每个立方体可以串行化到225位或28.1字节。 由于在我们的模拟中有900个立方体,

这意味着每个快照大概是25千字节。

当我们以分组的形式发送快照数据时,我们在顶部包含一个16位序列号。 该序列号从零开始,并随着发送的每

个分组而增加。 我们在接收时使用此序列号来确定数据包中的快照是否比接收的最近快照更新或更早。 如果它更老,

那么它被丢弃。

我们只是渲染右边收到的最新快照:

仔细观察,即使我们尽快发送数据(每帧一个数据包),您仍然可以看到右侧的挂起。 这是因为互联网不能保证每秒发送60次

的数据包相当于1/60秒的间隔。 数据包抖动。 一些帧您收到两个快照数据包。 其他你没有收到。

这实际上是一个很常见的事情,当你第一次开始网络。 您开始在局域网上玩游戏,并注意到您可以快速地砰击包(60pps),

并且大部分时间您的游戏看起来很棒,因为在LAN上,这些数据包实际上往往以与他们发送的相同速率达到.

首先,我们来看看我们用这种天真的方法发送多少带宽。 每个数据包是25312.5字节加上28个字节的IP + UDP头和2个字节的

序列号。 每个数据包为25342.5字节,每秒60个数据包,总共每秒1520550字节或11.6兆比特/秒。 现在肯定有互联网连接,可以支

持这么多的流量...但是,老实说,我们并没有真正得到很多好处爆炸数据包每秒60秒,所有的抖动,让我们拉回来 每秒只发送10

个快照:

你可以看到 在右边没那么好,但是至少我们已经将带宽降低了6到2兆比特/秒。 我们肯定是朝着正确的

方向前进。

现在用快照的技巧。 我们所做的是,不是立即呈现接收的快照数据,就是我们在内插缓冲区中缓冲快照

时间短。 此插值缓冲区会持续快照一段时间,以便您不仅具有要呈现的快照,而且从统计学角度来看,您也

很可能拥有下一个快照。 然后,随着右侧时间的推移,我们在两个稍微延迟的快照之间插入位置和方向,提

供平滑运动的幻觉。 实际上,我们已经为平滑度交易了少量的延迟。

您可能会惊讶于使用线性插10pps看起来有多好:

现在我们要处理丢包了,我确定你可以看到为什么我们永远不会考虑通过TCP发送快照。

快照时间关键的,但不同于帧同步快照中的输入不需要可靠 如果快照丢失,我们可以跳过它,

并插入内插缓冲区中的更新的快照 我们不想停止,等待丢失的快照包被重新发送。 这就是为什么你应该始终

使用UDP发送快照。

上述的线性和高音插值画面不仅以每秒10包的发送速率记录,而且还记录在5%的分组丢失,+/- 2帧的抖动(60fps)。

如何处理这些视频的数据包丢失和抖动是通过简单地确保在插值之前在插值缓冲区中保存适当时间的快照。

我的经验法则是内插缓冲区应该有足够的延迟,这样我可以连续丢失两个数据包,并且仍然有一些插值。 实际上,

我发现在2-5%数据包丢失时效果最佳的延迟量是数据包发送速率的3倍。 每秒10个数据包,这是300ms。 我还需要一些

额外的延迟来处理抖动,在我的经验中,通常只有一个或两个帧(60fps),所以上面的插值视频以350ms的延迟被记录。

添加350毫秒延迟似乎很多 但是每次数据包丢失时,您最终会挂起1/10秒。 人们

经常用来隐藏内插缓冲区在其他区域(如FPS,飞行模拟器,赛车游戏等)中添加的延迟的一种技术是使用外推法。 但是

根据经验,外推对于刚体是不正常的,因为它们的动作是非线性的和不可预测的。 在这里,您可以看到200ms的外推,

将总时延从350 ms缩短到仅150ms:

外推对物理模拟不了解 外推不知道与地板的碰撞,所以立方体可以向下推出地板,然后弹回来纠正。

预测不知道弹簧力将玩家立方体放在空中,所以立方体最初向上移动比它应该更慢,并且必须抓住。 它也不知道

任何关于碰撞和碰撞反应如何工作,所以立方体滚动在地板和其他立方体也是错误的。 最后,如果你看到球,

你将会看到,外推可以预测所附立方体当它们与播放器立方体一起旋转时,沿其切线速度继续移动。

您可以想象,花费大量的时间来提高这种外推的质量,并使其了解立方体的各种运动模式。 您可以采取每个立方体,

并确保至少多维数据集不会通过地板。 您可以使用多边形之间的边界球添加一些近似碰撞检测或响应。 你甚至可以把这

个立方体放在卡塔马里的球中,使他们预测运动与玩家立方体一起旋转。

但是,即使你做了这一切,仍然会有错误的预测,因为你根本无法准确地匹配物理模拟和近似值。 如果您的模拟主要

是线性运动,例如。 快速移动的飞机,船只,太空船 - 你可能会发现一个简单的外推在短时间内(50-250ms左右)工作得很好,

但是根据经验,一旦物体开始与其他非固定物体碰撞,外推开始 分解。

我们如何减少内插的延迟量? 350ms仍然是不可接受的,我们不能使用外推来减少这种延迟,而不增加大量的不准确性。

解决方案很简单:增加发送速率! 如果我们每秒发送30个快照,我们可以获得相同数量的丢包保护,延迟150ms。 每秒60个

数据包只需85ms。


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:214202次
    • 积分:4152
    • 等级:
    • 排名:第7417名
    • 原创:189篇
    • 转载:1篇
    • 译文:0篇
    • 评论:142条
    著作书籍
    《Unity3D实战核心技术详解》电子工业出版社 《手把手教你架构3D游戏引擎》电子工业出版社 《Cocos2dx 3.x 图形学渲染技术讲解》电子工业出版社
    博客专栏
    最新评论