这是【游戏开发那些事】的第21篇游戏技术文章

目录:

一. 载具同步的难点分析

二. 轨迹调试工具

三. 投影速度混合技术

四. 基于快照缓存的外插值和/或内插值‍

五. 混合物理模拟来处理碰撞

六. 未解决的同步问题

七. 未来的研究方向

八. 问答

在《网络同步在游戏历史上的发展变化(五)——物理同步》一文中,我们提到了游戏看门狗2物理同步策略,但是由于篇幅问题略过了不少技术细节。在这一篇文章中,我们会对该GDC演讲《Replicating Chaos: Vehicle Replication in Watch Dogs 2》做详细的翻译与梳理。

文章转自Funny David的知乎专栏(文末可点击原文链接查看),我根据自身理解对部分内容做了调整和优化。之前腾讯游戏团队也出过一篇讲物理载具的文章《手游中载具物理同步的实现方案》,基本的实现方式也是参考这个GDC分享。

▷▶下面是视频链接,长按图片识别二维码打开

以下是GDC演讲分享的具体内容:

这是在GDC 2017上的一篇关于《看门狗2》中车辆系统同步的分享。

上来先放了一段视频,描述Watch Dogs 2里“混乱”的车辆碰撞情况。(0:19)

然后讲了一下网络架构:没有中心服务器的P2P形式(状态同步),支持4个玩家,有很多实体要去同步,而且这些实体属于不同的分布式所有者。

‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍文章中本地(Master)和复制方(replica)都是针对某个对象而言的。

假如有两个客户端,玩家A控制小车1,玩家B控制小车2。小车1在玩家A的客户端上就是主控的,小车2在玩家A的客户端上就是模拟的。同理,小车2在B客户端上就是主控的,小车1在B客户端上就是模拟的。

一. 载具同步的难点分析

讲车辆同步的困难

  • 移动速度快,100ms的网络延迟就意味着2-3米的差异

  • 存在碰撞,看门狗2的开放世界中有大量的交通工具,不仅限于玩家之间

  • 人眼对于不规则的速度很敏感

涵盖内容:

  • 轨迹调试工具

  • 标准的技术:投影速度混合(有小调整)

  • 基于快照缓存的外插值和/或内插值

  • 混合物理模拟来处理碰撞

  • 未解决问题

  • 未来研究方向

二. 轨迹调试工具

轨迹调试工具是most important thing,所以放前面讲,通过调试工具可以看到物体移动的位置信息。

绿色的轨迹是车辆经过的真实路径,蓝色的是通过dead reckoning(外插值)预测的路径,红色的点是做同步的快照点(即从主控端Master同步过来的准确位置)。

三. 投影速度混合技术

接着讲最为标准的做法,就是投影速度混合(Projective Velocity Blending)。分享者说这个公式来自于wikipedia,追溯了下,最终来源是《Game Engine Gems 2》(游戏引擎精粹)这本书中的一篇文章《Believable Dead Reckoning for Networked Games 》。

首先大前提是使用航位推测(Dead reckoning)法来做位置的同步预测:

航位推测法(英语:Dead reckoning,缩写:DR)是一种利用现在物体位置及速度推定未来位置方向的航海技术,现已应用至许多交通技术层面,但容易受到误差累积的影响。英语中“Dead”是从“deduced(推导)”转化而来。这里就理解成位置预测就行。

然后一个运动学状态会(对应这里的快照)包含位置、速度、加速度、朝向和角速度。最简单的解决方案是基于线性物理的模拟:

这是高中物理的知识,但这里有一个问题就是我们有两个运动学状态,当前模拟的位置和最近收到的真实位置。一种解决方法是通过在这两个状态之间创建一条曲线来进行模拟,另外一个技术就是分享者选择的投影速度混合。

P0表示车辆所在位置,V0表示当前的速度,P0‘是上一个运动学状态的位置,V0'是上一个运行学状态的速度,Tt表示从T0开始经历过的时间长度,而头顶带个尖的T表示归一化之后的比例,即它是一个0-1之间的值。

这样这里的几个公式就比较清晰了,先对速度做融合,然后使用融合后的速度计算位置Pt,注意这里已经在使用A0'的加速了,接着计算根据收到的运动学状态预算一个位置,最后根据归一化之后的时间比例对两个位置做差值融合。

跑出来的结果是这样的:

可以看出,绿色的原始轨迹是一个圆形,而蓝色的根据快照数据预测的结果是带有比较强的锯齿状的,通过视频可以看出车呈现出了很强烈的抖动。(5:30)

接着就讲twist(转弯)的内容了:

  • 对正在转弯的车辆使用直线进行外插值是不理想的;

  • 添加了方向盘(或者说车轮)角度信息

    • 但是车辆的物理模拟很复杂

    • 无法依据方向盘的角度准确预测转向轨迹,因为虽然方向盘角度给出了车辆未来运行的方向,但是在物理世界中速度、地表材质等等因素都会影响结果。

  • 传输了车辆的位置、速度角速度

    • 使用角速度中的水平朝向(yaw)值来预测转向

    • 对于漂移的车辆不管用,但是对于Watch Dog 2来说并不是个问题(因为不是个赛车游戏=_=)

这样就很圆了……(7:45)

四. 基于快照缓存的外插值和/或内插值‍

接着说快照缓存的使用部分:(8:53)

  • 在最近的两个快照中做内插值的做法

  • 优势是轨迹精准(因为等待主控的权威数据到来后才插值模拟)

  • 劣势是渲染对象轨迹其实是在模拟一段时间之前的状态,比如图中渲染的就是晚了5帧之前的状态

这会带来“在不同客户端上因为位置不一致而导致结果不同”(A客户端上发生了碰撞,但是B客户端上没有发生碰撞),所以下面要解决这个问题。

外插值内插值的对比

  • 我们不是一定要完全使用内插值

    • 依然可以从上一个收到的快照进行外插值

  • 引入一个“时间偏移”(TimeOffset)

    • 我们渲染出来的这辆车在时间上晚了多久

    • 检查 当前时间 - 时间偏移

    • 如果这个插值落在了两个已经收到的快照时间之间的话,使用内插值

    • 如果比最后收到的一个快照还要晚的话,使用外插值

    • 快照要带时间戳

这里用视频讲解了具体效果,最好直接看视频更直观。(11:01)

时间偏移相关

  • 选择不是一件容易的事情

    • 太多内插值导致错误的碰撞

    • 太多外插值导致轨迹不连续

    • 要找平衡

  • 使用 平均度量延迟 + 常量值

    • 减震

    • 最多300ms

    • 常量值范围在100ms-200ms的区间

    • 根据车辆速度成比例改变,当车辆以较慢的速度运行的时候,错失碰撞的概率比较小,因此可以尽量使用内插值来做,这时候对应的就是增大时间偏移的值。

五. 混合物理模拟来处理碰撞

这样下来航位推测出来的轨迹就看着不错了,现在我们让车相撞看看

看视频,车辆在相撞的时候会互相向后退,这和我们预期的不太一样。(13:22)

相撞的车应当都停住,或者把对方推开的力量更小一些。但是游戏里面,两边的车辆都推到很远的位置。

借助网络工具帮助我们逐帧来看发生了什么。

这里是一段逐帧视频,白色的车在这里是第三方,它在黑车的客户端上发生碰撞之后,因为它自身没有开ragdoll(但其实有碰撞体),要等在它自己所在的客户端把碰撞之后的位置数据同步过来之后才会后退(这个时候还处于外插值的状态),于是它继续往前走,就把当前客户端用物理模拟(开了ragdoll)的那辆车给推到更远的位置去了。在白车自己的客户端上,黑车也有同样的行为,因此两辆车都产生了更大的碰撞后退效果,而实际上两个车相撞不应该产生如此大的位移(14:30)

如何解决?

  • 把你推开的复制方(replica)并不知道碰撞的发生

    • 他会保持前进的状态直到一个新的包到达

  • 这是一个无解的问题

    • 因为没有人有碰撞的完整决定权(因为网络框架是P2P的)

  • 这时候很希望有个权威服务器……

但是问题还是要处理,这时候就引入了物理模拟融合(Physics Simulation Blending),即在发生碰撞前打开其他车的物理模拟(打开ragdoll),然后在模拟位置与快照发送的位置之间进行blend

  • 无论我们是否喜欢,碰撞总会发生

  • 给本地物理一个机会来模拟碰撞

  • 然后融合回航位推测得出的轨迹

  • 需要调校两种速度之间的融合参数:

    • 一种速度来自刚体模拟

    • 一种速度要达到航位推测得到的位置

  • 表现本地可信的一些效果,然后将碰撞考虑在内的情况下融合进快照。

关于Blend方案的问题:文中提到的"Physics Simulation Blending"是用本地模拟的与服务器快照进行混合。而本地计算是先行的,收到的服务器快照皆是过去的位置,所以混合的并不是同一时刻的位置,所以理论上可能会有一些不正常的情况(而且无法预测)。这里的例子都是汽车相撞然后一段时间内趋于静止,所以通常情况下没什么问题。

融合参数调整(不同阶段调整物理模拟以及快照位置的权重)

  • 通过播放多次碰撞选择看上去表现好的融合参数,包括

    • 在碰撞发生时融合比例的最大值

    • 在结束之后以多快的速度回到完全的航位推测算法中

图中展现了对于自行车和汽车,恢复的时间长度是不同的,其中汽车较重,相对需要更长的时间。

效果已经不错了哦,这块要看视频。虽然不完美,还是会有一些推开的情况,但是没有之前那么远了。(19:10)

接下来说说进一步可能发生的问题——碰撞结果的不可预测性

  • 本地模拟的碰撞在不同的客户端上结果可能不同,比如两辆车相撞,在两个客户端上一个可能被撞到了左侧,一个被撞到了右侧。

  • 将复制品从本地碰撞模拟融合回航位推测轨迹的时候可能会比较“震撼”,来回抖动

  • 使用的优化方法是当碰撞开始的时候,尽量将车辆放置到他们主机所在的位置

    • 让它们更可能得到一致的碰撞结果

其实由于看门狗2采用的带有预测的状态同步,所以误差是无法避免的,在物理模拟的参与下更难保证一致性,只能通过快照来纠正错误信息

如何做到让在碰撞发生时将车辆放置到他们主机所在的位置呢?这里就要做碰撞预测了。

  • 在如下几种情况会预测即将发生的碰撞并做外插值(通过调小时间偏移那个值)

    • 不太能够避开的情况,车辆要转向毕竟是需要一个时间的,当两辆车距离太过接近的时候,通过射线检测之类的方式(我猜)来预测碰撞是否很可能要发生了。貌似这种效果并不是非常好,但是有任何一点可以改善的点都值得做。

    • 使用AI系统中已经存在的碰撞预测算法,这里没讲算法细节。

六. 未解决的同步问题

一些没解决的问题,其实有更多,这里只列举一部分。

  • 和静态网格的碰撞

  • 时间偏移差异

  • 恐怖谷效应

静态碰撞的问题:

这块看视频更直观,真正的快照目标点在树的左侧,而碰撞模拟到了右侧,由于中间有一颗树的遮挡,这时候需要融合过来就很奇怪。(视频中可以看到剧烈的抖动,火花四射,然后一点点滑过去)(22:35)

  • 静态物体不会让路

  • 树是最坏的一种情况

  • 一些选择:

    • 保持当前位置

    • 软物理碰撞

    • 最终直接传送,虽然效果不好,但是在一些特定情况下还是需要的。

  • 消除抖动是最为重要的部分

他们最终的做法是如果发现你被挡住了,但是又无法移动到目标位置,就让你保持当前位置的,等有之后新的位置同步之后再处理。

不同的时间偏移

  • 人物角色比较倾向于内插值(速度慢)

    • 不同的时间偏移导致了在不同客户端上的碰撞效果不同,左侧的图车完全没碰到人,右侧的把人撞飞了。分享者说这块可以基于前面碰撞预测的同样思路来解决或者优化

  • 对于可破坏物有同样的问题,但是对于玩法的影响比较小。

恐怖谷效应

  • 运动轨迹已经正确了,但是依然感觉不好

    • 轻微的摇摆效果在复制方(远端)丢失了

    • 车不能围着它们的重心旋转

    • 人眼对于甚至很微小的不连贯现象都很敏感

  • 应用一些后处理平滑

    • 平滑速度和角速度,而不是位置和旋转

    • 需要和投影速度融合共存,它在航位预测之上,因为航位预测法虽然希望给出一个平滑的曲线过渡,但是在实际结果中可能并不是这样,还是会有位置和速度上的突变。虽然加这个有点脏,但是效果好,管他呢。=_=

七. 未来的研究方向

  • 调参数太难了,希望用机器学习的方法让AI来调

  • 平滑算法

    • 卡尔曼滤波(Kalman filter)

    • 卡尔曼滤波(Kalman filter)是一种高效的自回归滤波器,它能在存在诸多不确定性情况的组合信息中估计动态系统的状态,是一种强大的、通用性极强的工具。

      https://zhuanlan.zhihu.com/p/39912633

最后强调调试器的重要性,然后说虽然在这个过程中做了很多数学工作,是科学性的,但是依然有很多内容是需要从艺术/美术的视角去思考和改进的,毕竟要做到的最终结果是让玩家feeling good。(其实这个调试器本质是一个回放工具,需要把每一帧当前所有的对象位置以及行为信息都记录下来,方便后面做调试)

八. 问答

  1. 问题:第一个问题关于timehop(跳时)的,如果某辆汽车在运行时切换了控制权(比如玩家A中途掉线,AI计算由客户端A切换到客户端B)如何处理这个跳时造成的问题?

    回答:这个时候一般你会知道当前的汽车运行情况,比如车是沿着直线开的时候,就减速等着新的控制端计算位置逐渐追上去。

  2. 问题:车辆在爬坡之类的情况下的颠簸在同步方怎么表现,会限制外插值在一个平面么?

    回答:一个解决方案是用物理模拟Z轴的变化,然后在车离地面比较近的情况下Z方向上不要外插值,但是比如飞跃到空中的时候还是需要切换到航位预测法来预测落点位置。

  3. 问题:似乎是在讨论是否有必要区分不同的物理对象,决定是否使用物理或者调整同步方式?

    回答:其实在游戏里面是有区分的,比如自行车和汽车的物理模拟融合时的权重计算曲线不同。

- 技术分享不易,希望大家点赞、分享支持一下 -

- 欢迎各位在评论区进行沟通与交流 -


 往期文章推荐 

虚幻引擎技术系列【使用虚幻引擎4年,我想再谈谈他的网络架构】

C++面试系列【史上最全的C++/游戏开发面试经验总结】

校招求职系列

游戏开发技术系列【想做游戏开发,我应该会点啥?】

游戏开发那些事

我是Jerish,网易游戏客户端开发工程师,

这里会定期输出技术干货和游戏科普的文章

回复"gamebook",获取游戏开发书籍

回复"C++面试",获取C++/游戏面试经验

回复"操作系统",获取操作系统经典书籍

回复"网络同步PDF",获取作者总结的同步技术合集

游戏开发交流群(875867499)

GDC演讲翻译——看门狗2的载具同步相关推荐

  1. STM32 你不知道的看门狗细节

    看门狗简介 你知道什么是看门狗吗?看门狗,实际上可以说就是一个简单的定时器功能,而这个定时器有一个输出端,可以输出复位信号.一般的情况下,看门狗这个定时器是给让一个比较大的初始值,然后从这个值开始递减 ...

  2. 嵌入式系统中看门狗的使用

    最近需要在板子上加上一块WatchDog,以确保在系统出错时自动重启,所以看了一些在嵌入式系统中使用看门狗的资料,现在总结如下: 一.看门狗原理     在产品化的嵌入式系统中,为了使系统在异常情况下 ...

  3. 翻译GDC演讲:《Procedurally Crafting Manhattan for ‘Marvel‘s Spider-Man‘》(在‘漫威蜘蛛侠’中使用程序化的方式精心制作曼哈顿)

    原文链接:GDC Vault - Procedurally Crafting Manhattan for 'Marvel's Spider-Man' 目录 简介 0. 开场 立项 演讲内容总览 1. ...

  4. 龙将加速浏览器_《看门狗:军团》即将开启预载,迅游加速器支持下载和联机加速 18183手机游戏网...

    来源:作者:阿姆斯特朗雷时间:2020-10-26分享到: <看门狗:军团>是<看门狗>系列的最新作品,将于10月29日正式上线亚洲地区,并且即将面向各平台开启预载,迅游加速器 ...

  5. 翻译GDC演讲《精心制作一个微小的开放世界:‘A Short Hike‘ 事后分析》(3):关卡设计

    译者前言 如果你没看过前一篇,请看:<翻译GDC演讲<精心制作一个微小的开放世界:'A Short Hike' 事后分析>(2):项目安排,制作捷径> 本篇包括: Lesson ...

  6. 在多任务(RTOS)环境中使用看门狗

    最近在SEGGER的博客上看到一篇有关在实时操作系统使用看门狗的文章.从一个失败的太空项目出发,分析了看门狗的作用及使用,自我感觉很有启发,特此翻译此文并推荐给各位同仁.为了阅读方便,有些航天领域名词 ...

  7. stm32看门狗_「正点原子NANO STM32开发板资料连载」第十一章 独立看门狗实验

    1)实验平台:ALIENTEK NANO STM32F411 V1开发板2)摘自<正点原子STM32F4 开发指南(HAL 库版>关注官方微信号公众号,获取更多资料:正点原子 第十一章 独 ...

  8. STM32F4 HAL库开发 -- 独立看门狗(IWDG)

    之前讲过看门狗,参看:STM32开发 – 看门狗详解 一.HAL库配置独立看门狗步骤 1.取消寄存器写保护,设置看门狗预分频系数和重装载值. 首先我们必须取消 IWDG_PR和 IWDG_RLR寄存器 ...

  9. 看门狗寄存器c语言代码_「正点原子NANO STM32F103开发板资料连载」第十一章 看门狗实验...

    1)实验平台:[正点原子] NANO STM32F103 开发板 2)摘自<正点原子STM32 F1 开发指南(NANO 板-HAL 库版)>关注官方微信号公众号,获取更多资料:正点原子 ...

  10. STM32之独立看门狗与窗口看门狗总结

    一.独立看门狗 STM32 的独立看门狗由内部专门的 40Khz 低速时钟驱动,即使主时钟发生故障,它也仍然有效. 看门狗的原理:单片机系统在外界的干扰下会出现程序跑飞的现象导致出现死循环,看门狗电路 ...

最新文章

  1. matlab getstart,matlab帮助文件(matlab get start.pdf)
  2. layui table 滚动 键盘
  3. python读取中文文件乱码-详解Python的json文件读取及中文乱码显示问题解决方法...
  4. hdu1.3.5 排列2
  5. 关于活动对像要注意的问题
  6. 这份网约车安全乘车指南,请务必收下!
  7. 图片热区map-area
  8. 20140617 数组和链表的区别
  9. Intel VT-x 处于禁用解决方法
  10. 解决easyExcel和poi版本冲突问题
  11. 通过的镜像源安装python包
  12. java hibernate的使用_java – 使用hibernate / JPA登录
  13. 学习之法 —— 套路
  14. hashcat字典攻击
  15. STM32CubeMX配置DCMI+DMA之OV2640
  16. 凡人修仙传jar_凡人的贝壳无法逃脱灵魂般的阴影
  17. vant 动态 粘性布局_Sticky 粘性布局
  18. Docker【部署 02】可视化工具DockerUI和Shipyard安装使用实例
  19. 程序哨兵----誓把流氓软件赶出我们的电脑!
  20. html怎么实现左右滚动,css实现左右滑动

热门文章

  1. 设置div背景颜色透明度,内部元素不透明
  2. 中端存储和高端存储的区别
  3. 运行Shell脚本的两种方法
  4. 彩虹表MD5破解分析
  5. 网站使用手机相机_谷歌相机安装教程,让你的手机拥有强大的夜拍能力
  6. 数据分析 - 预测模型(学习笔记)
  7. [C#][转载]Sqlite操作大全
  8. 攻防世界 logmein(重温,重点在于怎么写出脚本)
  9. 机器学习--sklearn(决策树)
  10. Postman中文版,竟如此简单,秒变中文