快照插值
Snapshot Interpolation
发送端按固定频率拍下世界(或相关子集)的快照,接收端不跑权威模拟,而是把渲染时刻拨回一小段,在缓冲里的两份快照之间插值,用额外延迟换平滑,并扛住抖动与偶发丢包。Source 的实体插值与 cl_interp 是同一思想的产品化。
与锁步对照
无法保证确定性、或人数超过锁步舒适区时,改为传状态快照。接收端可以完全不跑物理,只做视觉重建;代价是带宽随对象增长。(Snapshot Interpolation)
抖动与缓冲
即使 60 pps,包到达间隔也不均匀:有的帧两包、有的帧零包。直接渲染「最新一份」会打嗝。做法:把快照在插值缓冲里多留一会儿,渲染时刻取「现在 − 缓冲延迟」,在 straddling 的两份快照间插值。(Snapshot Interpolation)
Source 默认约 20 快照/秒,默认插值期 100 ms(cl_interp 0.1),使得丢掉一份仍常有两份可用:
(Source Multiplayer Networking)
插值质量
- 位置线性插值:样本点处一阶不连续;绕父物体旋转的附着物可能沿弦「穿」过去。
- Hermite:再带线速度,端点位置与速度都匹配,低发送率下观感好得多。
- 朝向:对许多刚体,slerp 已够用,不必为角速率上更高阶。(Snapshot Interpolation)
Bernier 强调:更新间隔会随带宽 choke 变化,只跟「上一包→最新包」滑动的简单插值会扁掉弹跳轨迹;应保留位置历史,按目标时间搜索夹住它的两份样本。(Latency Compensating Methods in Client/Server In-game Protocol Design and Optimization)
传送/瞬移要用标志或距离阈值打断插值,否则会「平滑飞过地图」。
丢包与外推
快照时间关键但不要求可靠——绝不走 TCP。丢了就跳过,朝缓冲里更新的样本插。经验:2–5% 丢包时,缓冲约 3× 发送间隔 可扛连续丢两包,再加少量抖动裕量;10 pps 时约 350 ms。外推能减延迟,但对碰撞丰富的刚体很容易穿地、弹错;Source 仅在历史耗尽时线性外推,且限制约 0.25 s(cl_extrapolate_amount)。(Snapshot Interpolation;Source Multiplayer Networking)
延迟与发送率
插值延迟叠在网络延迟之上。降延迟的正经办法是提高快照率(并配合 快照压缩与增量编码):30 Hz 约 150 ms 级缓冲,60 Hz 可到约 85 ms 量级(Gaffer 经验数)。(Snapshot Interpolation)
插值造成的固定「看见别人在过去」必须纳入 延迟补偿,否则命中对不齐准星。
flowchart TD
R["收到快照:按序号插入缓冲"] --> T["渲染时刻 = 客户端时间 - 插值延迟"]
T --> F{"缓冲中有夹住 T 的两份快照?"}
F -- "有" --> I["在两份之间插值位姿/动画"]
F -- "没有" --> E["短时外推或停在最后样本"]
I --> D["绘制远程实体"]
E --> D上图:远程实体始终画在略过去的时刻;本地玩家预测不走这条路径。