开放大世界的碰撞与物理

41 篇文章 3 订阅
9 篇文章 0 订阅

        众所周知,物理开销一直是 CPU 的一个大头,而且还很容易出问题。对于开放世界,该如何进行物理运算,以及采用什么方案计算碰撞。

        本文针对这个问题做了一些细微的研究,算是对 Unity 下的解决方案有了一个大致的方向。

1、现有物理方案

        目前 Unity 里可用的物理方案(现成的)有3种:

  • Unity 默认的 PhysicsX:默认的物理,大家用得最熟的就是这个;
  • Unity Dots Physics:在 Dots 系统中的物理;
  • Unity Havok Physics:基于 Havok 的物理系统;

        这里我们对三种方案都进行一个测试:

1、底部放置一个 Mesh (地形),尺寸约 2000*100*800,顶点数 1229,三角面 2171 :

2、之后在空中 100*100 区域的范围洒落 球/立方体 碰撞:

3、等方块/球落地后基本稳定、帧数不变之后,记录当前的实体数量;

4、记录帧数刚好在 60/45/30 时对应的实体数量;

       注:这里的测试方案我是选择了对于物理系统最不友好的方式(大量物体都积累在同一区域相互碰撞),如果物体均匀分散,性能压力会小很多。但进行压力测试时,都是考虑的最差情况。

        这里我在小米9上进行了真机测试,结果如下:

        三种物理系统的差别并不算大,Havok 的性能会好一些,而 Unity.Physics 和 默认的 PhysicsX 没有太大差异。究其原因,Unity 的默认碰撞 PhysicsX,其实也是多线程。

2、开放世界物理方案

        通过上文的测试,无论采用什么方案,如果数量到达了数千的地步,都是接受不了的。如果考虑到开放世界中的场景丰度:石头、树木、关卡交互等,数量可以非常庞大。考虑到 小米9 并不是支持的最低端手机,因此建议同时激活的带碰撞的物体要一直控制在 1000 以下。我后面也没有纠结物理系统了,就直接使用 Unity 的 PhysicsX 就行了(会的人多,实现起来简单),即便使用其他的方案也不会有质变

        之前看到一个方案,就是通过射线检测来替代物理碰撞(《腾讯游戏开发精粹Ⅱ》第10章 物理查询介绍及玩法应用、第11章 基于物理的角色翻越攀爬通用解决方案),也能大大降低性能消耗。我这里简单介绍下这个方案的思路:

        在玩家的移动方向上打射线(不一定只能从上往下打),越靠近玩家射线的精度越高。在计算时,先在最远处检测,如果检测到有障碍,便激活中距离的检测(精度更高、性能开销也越大);如果在中距离检测到了,便激活近处的射线检测(此时检测到的数据就与玩法相关,以实现爬墙、跳跃等规则)。
        这种分级射线检测的好处,在玩家处于空旷地块时,可大幅减少射线检测的频率。此外,使用射线代替碰撞,能减少大量物理开销,也能减少因为物理碰撞产生的各种飞天遁地等表现异常。

3、岛屿轮廓的碰撞

        我们的地形数据是生成的高度图,岛屿形状其实并不能在 CPU 中体现,自然也无法获取到类似于网格这种的碰撞数据。需求上,有需要船只会被岛屿边缘弹开(有类似推开的物理效果)的功能。针对海岛,我设计了基于有向距离场(Signed Distance Function,以下简称 SDF)的碰撞方案。

        关于 SDF,建议先参考以下文章:

Unity 手把手教你实现有向距离场(SDF)图像生成工具(1)【猴子都能学会】 - 哔哩哔哩本文将采用Dead Reckoning算法实现一个有向距离场的生成工具,并实现一个如下的简单变形效果,当然对于SDF应用远不止于此,诸如原神的脸部阴影之类的,这个网上很多就不在这里详细讲了。该算法的优势相较于遍历全局耗时更少,虽有一定的精度下降,但相较于近似方法消除了产生的棱角,毕竟对于一张1024*1024的图要遍历全局的时间都够下楼买杯奶茶再上来了,而采用该算法可以在2秒内计算完成。 首先先创建一个ComputeShader和一个脚本如何创建ComputeShader给ComputeShader命名为icon-default.png?t=N7T8https://www.bilibili.com/read/cv24786763/        在我们游戏中,其至少有以下2个功能:

  • 海水波浪计算:在岛屿靠近岛屿区域时,海浪高度(强度)减弱,且海浪不能漫过岛屿。

  • 行船碰撞计算:开船不能直接撞上岛屿,也不能直接生硬拦停,通过SDF图可以拟合渐变实现碰撞转向的效果。

        因为这个值需要在CPU、GPU都读取,在Unity2020+中可以使用 RawBuffer 辅助两边的数据共享。这里使用实时在线生成的方式生成SDF图,由GPU进行计算。

        动态生成的好处是能支持动态的阻挡物,而且全局唯一一份(只在船或相机附近生成)固定大小的图,更为节省内存。但缺点是生成的结果不能立即拿到,需要一定时间进行生成,可能在2s左右才能获得最终结果(由于海洋主题中,船只的行进都是较慢的,所以问题不大)。

        以玩家(相机)为中心,生成一张 1024*1024 的贴图,数据存储为 RGBA 32 bit,也就是每个像素4个字节。其中RG表示最近障碍物的距离,BA表示法线。整张图的重构逻辑依旧是AOI的九宫拆分:

        SDF图的重建逻辑:初始化时,以玩家(相机)为中心生成一张1024*1024的贴图。玩家从A点移动到C点:当玩家在B点(黄色区域时)仍使用当前数据。当玩家移动到C点(离开黄色区域)则开始按照C点为初始点构建新的图(重新构建时有4~6个格子的数据可以复用,但一般还是直接整张图重建)。
        在 ComputeShader 中,每帧进行一次迭代,每个像素计算周围8个格子,类似于流场的做法。虽然理论上,最坏情况需要 52 万次才能迭代完成,但实际应用中收敛次数不会这么多,具体需要测试。预测会在2~3s内完成收敛(迭代30~60次)。

        之后,CPU 和 GPU 都可以通过 SDF 图数据来计算了。

4、总结

        对于开放大世界的物理碰撞,根据现有解决方案,需要将带物理的物体控制在 1k 以下,就能很好地在手机上运行并支持玩法。

        对于特殊的需求(例如翻墙、攀岩)等,通过射线手段进行辅助检测,减少物理碰撞的开销。基于 GpuTerrain 实现的地形,则需要通过生成 SDF 图的方式来辅助碰撞,基本上能满足需求。

        对于一些对碰撞精度要求较高的需求,也可以通过取巧的方式来实现。(例如,如需要玩家在前进过程中自动绕开一些小型灌木。这种如果不能上物理和寻路、RVO,可以将灌木的数据记录在地块信息图中,在玩家经过时播放一个向左/向右的躲避的动画,在表现上与玩家绕开障碍就一般无异了)

  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
开放世界游戏开发制作需要使用各种工具、技术和插件来实现。以下是一些常用的工具、术和插件: 1. 游戏引擎:游戏引擎是开发开放世界游戏的核心工具。一些常用的游戏引擎包括Unity和Unreal Engine。这些引擎提供了丰富的功能和工具,可以加快游戏开发的进度。 2. 场景编辑器:开放世界游戏通常需要创建大量的场景和地形。场景编辑器可以帮助开发者创建和编辑游戏的地形、建筑、道路等元素。例如,Unity中的Terrain编辑器和Unreal Engine中的Landscape编辑器。 3. 编程语言:游戏开发中常用的编程语言包括C++、C#、Python等。不同的游戏引擎支持不同的编程语言,开发者可以根据自己的喜好和需求选择合适的语言。 4. 物理引擎:开放世界游戏中物理模拟是重要的一部分。物理引擎可以模拟物体之间的碰撞、重力、摩擦等物理效果。一些常用的物理引擎包括PhysX和Bullet。 5. AI插件:开放世界游戏中的NPC通常需要具备一定的人工智能来实现自主行动和与玩家的互动。一些AI插件,如Behavior Designer和NodeCanvas,可以帮助开发者实现复杂的NPC行为。 6. 游戏工具包:为了加快开发进度,开发者可以使用一些游戏工具包来实现特定功能。例如,音频工具包可以用来处理游戏中的音效和音乐,网络工具包可以用来实现多人游戏功能。 7. 图形设计工具:开放世界游戏需要大量的美术资源,如角色模型、场景贴图等。图形设计工具如Photoshop、Maya、Blender等可以用来创建和编辑这些美术资源。 需要注意的是,具体使用哪些工具、技术和插件取决于游戏开发团队的需求和技术栈。以上只是一些常用的选项,开发者可以根据自己的项目需求做出选择。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值