如何修复6月16日更新中Linux(可能还有Steam Deck)上的雾效倒置问题

0 点赞
旧世界 Old World
转载

6月16日更新在Linux系统上引入了一个bug,导致雾气渲染颠倒。雾气本应显示在远离镜头的屏幕上边缘位置,现在却被渲染在靠近镜头的屏幕下边缘。本指南详细介绍了针对此问题的两种可能解决方法,包括它们的优缺点。bug描述

如图片所示,雾气现在出现在屏幕错误的边缘,导致下边缘呈现灰白色。 此问题的原因是相关着色器未考虑纹理坐标系统,这在6月16日更新前并未构成问题,该更新将渲染后端从Vulkan切换为OpenGL。 OpenGL将纹理坐标的(0,0)点放置在纹理的左下角,而Direct3D和旧版本的Vulkan则将(0,0)点放置在左上角。 随着从Vulkan切换到OpenGL,所有手动计算的纹理坐标都需要将其垂直坐标反转(V=1-V)。Unity引擎几乎会自动处理所有情况,但对于如上图所示的雾等后期处理效果,似乎仍需手动操作。 解决方法一:Vulkan(注意,可能会崩溃) 警告:此设置存在已知的稳定性问题。请自行决定是否使用。

让一切恢复正常显示的最简单方法是使用Vulkan而非OpenGL。你可以通过为游戏添加-force-vulkan命令行参数来实现,具体操作可参考截图示例。 此设置会强制游戏使用Vulkan渲染,在Unity引擎中,Vulkan与Direct3D采用相同的纹理坐标。 不过我不推荐这种做法。 开发者从Vulkan切换到OpenGL是有充分理由的,即许多《旧世界》玩家反馈Vulkan渲染存在稳定性问题。未来的游戏及引擎更新可能会带来彻底修复,但在此之前,使用Vulkan可能会导致游戏崩溃。即使您的显卡驱动能够解决稳定性问题(据我所知,AMD Linux驱动在显存不足时会使用系统内存),您最终可能还是会遇到性能较低的情况。 换句话说:效果可能因人而异,如果方案2对您适用,那它可能是最佳选择。 方案2:着色器替换(如果适用,请使用此方案!) 这绝对是更好的选择,但它仅适用于开源图形驱动,因为它依赖于Mesa3D的着色器替换功能。 操作过程简单明了,但需要一些操作。我不敢上传经过修补的着色器,因为这些代码是游戏的一部分,将其发布到互联网上可能会涉及版权问题。那么,我能为你提供的最佳帮助就是一份关于如何自行打补丁的分步指南。

从Mesa导出着色器。 首先需要创建一个用于写入着色器文件的文件夹。然后需在游戏的命令行中添加MESA_SHADER_DUMP_PATH环境变量(可根据需要调整路径)。之后启动游戏,并加载一个存档(以便加载相应的着色器)。生成的文件夹将包含许多名称为十六进制数字的.glsl文件。

下一步是翻转“_GlobalFogMaskLow”和“_GlobalFogMaskHigh”采样器的V坐标。你可以使用任意文本编辑器,或者在文件夹中运行以下sed搜索替换命令(注意:此命令会直接覆盖文件且不进行确认,因此务必确保你处于正确的文件夹中!):sed -i -e 's/texture(_GlobalFogMaskHigh, (.* ))/texture(_GlobalFogMaskHigh, vec2(( 1).x,1.0-( 1).y))/g' -e 's/texture(_GlobalFogMaskLow, (.* ))/texture(_GlobalFogMaskLow, vec2(( 1).x,1.0-( 1).y))/g' *

这些编辑的作用是搜索采样【_GlobalFogMaskHigh】或【_GlobalFogMaskLow】的texture()调用,并将坐标参数的y分量替换为1.0-y。现在你的文件已修改,可以在《旧世界》的启动选项中添加MESA_SHADER_READ_PATH设置。

在游戏或显卡驱动更新后,你可能需要重新执行这些步骤,因为更新可能会导致着色器哈希值改变,更糟的是,你本地保存的着色器可能与新版本游戏不兼容。 着色器替换听起来很有趣。它还能做更多吗? 当然可以! 选择是无穷无尽的。你可以按照自己的意愿调整游戏中的效果或材质。 不过,我想特别强调一个使用场景:Unity游戏性能。 Unity OpenGL游戏的常规工作流程是用HLSL编写所有着色器,然后让引擎将它们转换为GLSL。结果通常还不错,但Unity的转译器无法正确识别某些模式,导致最终效果不太理想。如果你足够幸运,游戏开发者会注意到这些问题并加以解决,但有时候,作为玩家,如果你不想让性能受内存限制,就需要对Unity输出的着色器进行最后的优化。 不过在此我不会深入细节,只提供一些基本提示: Unity的HLSL转GLSL编译器不喜欢硬编码矩阵。 在这种情况下,输出会包含名为【ImmCB_X】的全局数组变量,其中X是某个自动生成的数字。 这些变量是全局且可变的,尽管它们本可以是【main()】函数中的常量。这意味着它们会占用GPU寄存器,如果矩阵较大(比如8x8元素),就会出现寄存器溢出。如果发生寄存器溢出,每个像素的值都会写入显存并从中读取,这会导致对于本应位于指令缓存中的值产生极高的内存带宽占用。 如果改为将它们硬编码为矩阵,着色器的速度将显著提升。 进行此类编辑时请注意,HLSL和GLSL矩阵是相互转置的。 话虽如此:祝你修改顺利。