Alt-F4 #44 - 一个新视角 2021-07-30
翻译 Ph.X
你还记得今年的愚人节吗?已经过去相当长的一段时间了,但如果你在那一天访问了 subreddit,那很可能看过 arrow in my gluteus maximus 的视频。如果还没看过,本周的第 44 期 Alt-F4 将帮你补上这一课,然后再来看看这个黑魔法演示到底是如何实现的。
关于“异星工厂列车新视角”的新视角 arrow in my gluteus maximus
两个月前我发布了一个名为“异星工厂列车新视角”的视频。如果你还没看过,请在继续阅读本文之前观看,否则会无法理解这篇文章的内容。
有些人在观看该视频后声称自己出现了头痛等症状。你已经收到该健康提示了。
(译注:若无法打开上面的视频也可点击此链接观看搬运视频。)
那些下载了视频描述的 Mod 的人都知道这是一个愚人节玩笑。对于那些没搞清楚的人:我很抱歉。有不少人问我制作这个视频的细节,所以我决定写一个简介。请勿在家尝试。
我看到有些人猜测我以某种方式从游戏中提取了 3D 模型。根本不需要,这只是对屏幕上已经显示的东西做个简单旋转。虽然这个想法可能很简单,但执行起来就有点复杂了。你遇到的第一个问题是,屏幕不是圆的。当旋转时,图像的一部分会被截断,而其他部分如 GUI 则会缺失。
我最终采用了我在异星工厂录像问题上的一贯解决方案:截图。游戏内置的截图不受常规屏幕录制的限制。因此为了录制视频,我只需在比正常可见的更大的区域内每隔一段时间截取一张屏幕截图。这样一来,在旋转的时候,屏幕的所有部分都不会被截断。
下一个问题是,UI 也会旋转而我们不希望如此。截图也帮助解决这个问题。take_screenshot() 命令有一个 show_gui
的选项。诀窍是在每一个 Tick 拍两张屏幕截图,一张显示 UI,一张不显示。如果我们只截取差异的部分,就可以获得单独的 UI,然后我们可以把它叠加到没有 UI 的截图上。至少计划如此。各种各样的视频编辑问题使得这个计划不可行。例如,我的视频编辑器(我能找到的,试过一大堆)不支持无损格式。因此,编码导致的细微差异会出现在 UI 上。
不过,我发现在最新版的异星工厂中,UI 在截图中不再固定于玩家的位置。无论你对地图的哪个部分进行截图,它都是可见的。所以我找了一个远离游戏中出现的其他颜色的颜色。我最终选择了粉红色。而且我把一些混凝土的图像改成了纯粉色,并把云层关掉。我改变了我的 UI 截图的位置,所以只有粉红色的混凝土是可见的。这样我就可以使用一种绿幕来获得 UI,或者说粉幕。
不过这还有几个小问题。原先在 UI 中有一些透明的部分,即当你用鼠标悬停在事物上时显示详情的面板。它现在看起来是紫色的。我最后手动把它从 UI 中剪掉了,而且似乎没人注意到。
接下来,我创建制作了一个小 Mod,每当我开始录制屏幕截图时,就播放一个声音,这样我就可以将游戏中的声音与屏幕截图同步。类似于拍电影用的场记板。该 Mod 还将 game.players[1].vehicle.orientation 的值写进了一个文本文件。我用它来计算需要旋转多少角度,再用样条进行了平滑处理。
我担心这些步骤不足以令人信服。拍摄那么多截图会大大降低游戏的速度。我担心如果在游戏中看我的动作会明显感觉到镜头被加速了。所以我找了一个方法来使录像的速度加快。录制完截图后,我用 FFmpeg 将其编码为 mp4,那么为什么不砍掉中间环节,试试将 FFmpeg 直接连接到异星工厂。编码 png 和将其写入硬盘都是费时费力的操作。假使我可以跳过这些步骤的话能提速不少。
第一步是直接从异星工厂中提取原始图像数据(不要与 .raw
格式混淆),而不是将其编码为 png。我找不到一个简单的方法,但事实证明 .bmp
是非常接近需求的。它是将图像数据反转顺序,在前面加一个文件头。所以这应该是比 png 更快的编码。
接下来,我想在不保存到硬盘的情况下把它输入 FFmpeg。事实证明,FFmpeg 有内置的功能来处理图像,所以用一个带有 .bmp
扩展名的管道就可以解决这个问题。(命令示例:ffmpeg -f image2pipe -framerate 60 -i - -r 60 -c:v libx264 -vf format=yuv420p -crf 1 example.mp4 -y < pipe.bmp
)
不要忘了在截图之间用 sleep 命令保持管道开放:sleep 10000000 > pipe.bmp
,最后终止 sleep 命令,让 FFmpeg 完成录制。我在低帧率下进行了测试……等等有问题!这到底是怎么回事?
问题在于图像被混在一起了。异星工厂的渲染是多线程的。当一帧图像还在被写入管道时,下一帧可能已经开始了。结果把两帧的像素混在一起。解决方法是强迫异星工厂等待,直到前一帧渲染完毕后再开始下一帧。这可以通过在每帧调用 game.set_wait_for_screenshots_to_finish() 来实现。不过这将降低异星工厂的速度,以至于我们不能再称其为实时。虽然我仍然有一些想法来加快它,但我已经在这个项目上花了太多的时间,所以决定使用尝试过的真正的方法,即使用重放。
异星工厂有一个奇妙的功能,它不检查在录制和回放时使用的 Mod 代码是否相同。所以我首先以正常的速度录制了一个回放。然后我编辑了我的一个 Mod,让它每隔一段时间就进行截图。然后,当播放回放时,异星工厂会开始截图。以上假设你对 Mod 的修改没有改变游戏状态。
遗憾的是,由于使用了回放,我不得不删掉一些场景。我本来想展示从旋转的角度建造东西的感觉有多奇怪,但事实证明异星工厂在回放时并不保存你的鼠标位置。所以在回放中,UI 跟随你回放时的鼠标,而不是你录像时的鼠标位置。
总而言之,这是一个有趣的挑战,我很喜欢迷惑异星工厂的玩家。
征稿
一如既往的,我们正在召集任何想要为 Alt-F4 做出贡献的人,无论是提交文章还是帮助翻译都可以。如果您有些有趣的想法,并乐于与社区分享,这里就是一个好地方。如果您没有太大把握,我们会很乐意帮助您讨论内容创意和结构问题。如果您有意参与,从加入 Discord 开始吧!