开发实践:Darkwind Media用遮挡剔除带来更高性能Oculus Go游戏

映维网 2019-06-10
Darkwind Media为Gear VR和Oculus Go用户带来了开发团队的《Republique》。为提高游戏的性能,团队探索了每一条可能的途径,而他们指出最好用的方法是遮挡剔除。Darkwind Media日前撰文介绍他们开发的定制遮挡剔除解决方案,同时解释了在这一过程中所学习到的经验教训。




1.扩展系统

我们一开始是从单点进行捕获,所以我们必须考虑camera移动时的情况。我们需要一个能够有效从一个可见集合转换到另一集合的系统。在《Republique》最后的一个场景中,玩家可以通过一架沿着固定轨道移动的无人机来感知世界,而camera运动基本是1D而非2D或3D。这使得我们能够扩展遮挡剔除并支持一定的camera运动。




对于支持一个移动camera,第一种同时是最天真的方法是沿着1D路径选择几个点,并根据这些点捕获遮挡。但如果camera最终停留于这两个点之间呢?通常来说,捕获之间的距离越短,潜在可见集合发生变化的可能性越小。为了缩短它们之间的距离,有人可能会在1D路径中包含大量的捕获点。遗憾的是,这最终会占用更多的内存,并且每次camera移动时都需要遍历整个list的渲染器。

如果我们将捕获点整合到单个卷积中呢?考虑到两个相邻的捕获形成一个线段,如果没有进行另一次捕获,我们无法确切地知道渲染器被遮挡的位置,但如果我们为每个线段执行这项操作,我们最终是进行了无限次的捕获。

最安全的假设是,只要camera位于这两个点之间,任何一个捕获所看到的渲染器都可能属于可见。我们对下一个线段和下下一个线段执行相同操作,依此类推。请注意,单个捕获与它所连接的两个线段共用,因此当camera正好位于捕获位置时,我们可以选择使用任一线段进行剔除,并保证启用该点捕获的每个渲染器。




…因为我们追求的正是通过这些卷积的运动,所以如果我们只存储前一个单元格的变化,而不是说为每个卷积储存整个list呢?我们需要两个list:一个用于打开渲染器,一个用于渲染渲染器关闭。当向相反方向移动时,则反过来解释list。关闭list中的渲染器应该打开,打开list中的渲染器应该关闭。



当从单元格A越过单元格B越时,渲染器打开list属于B的可见性集合中的所有渲染器集合,但不是A的集合。这被称为B中A的相对补集。

你可以看到,这种开关差异list的编码方式可能比整个list小很多,特别是在具有数百个或数千个渲染器和多于四个单元的真实场景中。它同时可以大大减少因进行大量捕获而造成的内存损失。捕获越接近,它们就越有可能看到同一组对象,因此这种差异list越有可能只是很小,甚至为空。

也许更重要的是,如果我们记住我们占用了前一帧的那个单元格,即便camera移出该帧内的所述单元格,它离所述单元格的距离都不会太远,而我们只需要迭代数个差异list来更新遮挡剔除即可。构建一个简单的1D遮挡系统就是这么简单。



现在我们已经有了一个有效的1D遮挡剔除系统,所以我们不难看到系统可以扩展到2D,甚至3D。要从1D扩展到2D,你可以从捕获点网格开始,并将其中的四个整合成一个矩形单元格。每个2D单元将具有四个邻居,因此具有四组差异list。要扩展到3D,你可以从捕获点的3D网格开始,并将其中的八个组合成矩形棱柱单元格。每个3D单元将具有六个邻居,因此具有六组差异list。



尽管其他版本的《Republique》都没有采用这样的系统,但如果你的游戏是针对六自由度头显,你可能需要2D或3D遮挡剔除。

2.经验教训

每个解决方案都存在一定的权衡折中,我们的解决方案也不例外。在考虑是否应该采用我们的解决方案时,下面是你必须注意的问题:

2.1捕获分辨率

我们为游戏的大部分场景选择了512px的捕获大小,因为我们发现这是精度和计算时间之间可接受的权衡。理论上,为了获得完美的精度,你应该以接近于屏幕显示捕获的分辨率来捕获游戏世界。Gear VR和Go的默认眼睛缓冲区大小为1024px,视场大约为90度。另一方面,如果512px丢失了一定的渲染器,则最终图像中的宽度必须仅为1到4像素,并且在所述大小下,它们容易产生锯齿。如果你的渲染器不是太小,或者你只是想要剔除小对象,选择512px这样的低分辨率可能也没有太大问题。

2.2静态集合和复杂世界状态

在我们的系统中,我们只能遮挡在捕获过程中不会移动的静态网格对象。同样,我们只是遮挡了一个世界状态。如果你的世界有多个具有不同渲染器的不同状态,你将不得不进行更多的捕获,从而遮挡其他状态。

2.3与其他可见性系统的兼容性问题

游戏系统控制部分网格的可见性。在这种情况下,你要么通过剔除排除这些渲染器,要么实现其他逻辑来组合两种形式的可见性。例如,LODGroup控制渲染器的可见性,而你可以设置成仅LOD0能够遮挡(如Unity)或将每个LOD层次视为单独的世界状态。

2.4更高的内存消耗

将这个遮挡数据存储在内存中,特别是以上面最为天真的方式,这确实占用了内存空间和加载时间。所以请确保你有额外的内存。

2.5分层剔除

在《Republique》中,这种精细的剔除仅仅是较粗糙房间和区域分区之上的最后一层。这加快了应用程序在camera转换期间的剔除数据,因为没有触及所述区域中的每一个渲染器,只是当前camera所需的渲染器。即使从绝对意义上来说这样的节省很少,但如果没有它们,在游戏过程中快速连续地出现camera切换可能会令情况更加糟糕。

2.6重新读写遮挡数据

当静态渲染器以任何方式发生改变时,遮挡数据将会变得过时并可能导致视觉错误。因此,需要在修改场景时重新计算遮挡,并且根据你的自动化程度,它可能会减慢你的工作流程。

2.7实时阴影投射

如果你有任何类型的实时阴影,请注意:本系统剔除的对象无法投射实时阴影。所以请使用诸如烘焙这样的替代方案。

2.8优化读写过程

GPU渲染彩色场景的速度非常快,但CPU一次性读取所有6×512×512像素要慢得多。下面是你可以采取的措施示例:

将任务拆分为线程

使用计算成本更低的hashcode

缓存数据结构并以合理的大小初始化它们

……

例如,《Republique》可以在不到25秒的时间内处理发电厂区域(需要385个立方体贴图)。

2.9三自由度头部运动

我们只计算了单点的可见性。三自由度VR不允许用户在虚拟世界中进行物理移动,但Oculus Go和Gear VR会尝试根据头显方向预测用户的头部和颈部移动了多少,这确实给游戏camera一点点的运动。我们之前说过,在几厘米内没有太大影响,但如果camera非常接近角落,倾斜头部可能会产生非常大的影响。



我们可以将camera的位置稍微移离角落,或者掠过角落的边缘,这样捕获就可以看到周围,并且对象永远不会被剔除。



感谢你的阅读。当你优化游戏的性能时,我们希望本文能够给你带来启发。祝你好运。


来源:映维网
原地址:https://yivian.com/news/62116.html


最新评论
暂无评论
参与评论

商务合作 查看更多

编辑推荐 查看更多