This guide details two possible workarounds for this issue, including their advantages and drawbacks.
Description of the bug
The cause for this issue is that the respective shaders do not take texture coordinate systems into account, what has not been a problem up to the June 16th update, which switched the rendering backend from Vulkan to OpenGL.
OpenGL places the (0,0) point for texture coordinates at the lower left corner of the texture, while Direct3D and older versions of Vulkan place the (0,0) point at the upper left corner.
With the switch from Vulkan to OpenGL, all manually computed texture coordinates therefore need their vertical coordinate inverted (V = 1-V).
The Unity Engine does this for almost all cases automatically, but it seems that for post-processing effects like the fog shown in the above image this still needs to be done manually (docs).
Workaround #1: Vulkan (beware, might crash)
The easiest way to get everything to look normal again is to use Vulkan instead of OpenGL. This can be done by adding the `-force-vulkan` command line option to the game, as shown in the screenshot.
This setting forces the game to run with Vulkan rendering, which (in Unity) uses the same texture coordinates as Direct3D.
I do not recommend this though.
The developers had a very good reason to switch away from Vulkan to OpenGL, namely that many Old World players reported stability issues with Vulkan rendering. A proper fix might come with a future game and engine update, but until then using Vulkan might crash for you.
Even if your GPU drivers are capable of working around the stability issues (afaik AMD Linux drivers will use sytem memory if VRAM is full), you might end up with relatively low performance.
In other words: Your mileage may vary, and if Workaround #2 is an option for you, it’s probably the way to go.
Workaround #2: Shader Replacement (use this, if it’s an option for you!)
The process is straightforward, but a little bit of work. I don’t dare to upload the patched shaders, as the code is part of the game, and just publishing it on the internet might be a copyright problem… So, best I can do is give you a step-by-step guide on how to patch them yourself.
- Export the shaders from Mesa.
You need to create a folder to which the shader files should be written first. Then you need to add the `MESA_SHADER_DUMP_PATH` environment variable to the game’s command line, as shown in the screenshot (adjust the path as needed). After that, launch the game, and load a savegame (so the respective shader gets loaded). The resulting folder will contain a lot of .glsl files with hex-numbers as name.
- The next step is to flip the V coordinate of the samplers for `_GlobalFogMaskLow` and `_GlobalFogMaskHigh`. You can use a text editor of your choice, or just run this `sed` search-and-replace command in the folder (beware: this command will overwrite the files without confirmation, so make absolutely sure you are in the correct folder!):
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’ *
What those edits do is that they search for `texture()` calls that sample either `_GlobalFogMaskHigh` or `_GlobalFogMaskLow`, and they replace the y-component of the coordinate parameter by `1.0-y`.
- Now that your files have been modified, you can add the `MESA_SHADER_READ_PATH` setting to your launch options for Old World.
- You might need to re-do these steps after game- or graphics driver updates, as those could lead to changed shader hashes, or worse, your locally saved shaders might not be compatible with the newer game version.
Shader Replacement sounds interesting. Can it do more?
The options are endless. You can tweak effects or materials in games however you want.
There’s one particular use case I’d like to highlight though: Unity game performance.
The regular workflow for Unity OpenGL games is to write all shaders in HLSL, and to let the engine convert them to GLSL. The results are typically quite OK, but some patterns are not properly recognized by Unity’s transpiler and end up in a less than ideal state. If you are lucky, the game devs notice and work around the problems, but sometimes you as a player need to add the final polish to the shaders output by Unity if you don’t want your performance to be memory-bound.
I won’t go into details here beyond giving some basic pointers though:
- Unity’s HLSL->GLSL transpiler does not like hardcoded matrices.
- In such cases the output contains global array variables named `ImmCB_X` where X is some auto-generated number.
- Those variables are global and mutable (as in: allocated in VRAM) even though they could be constants in the `main()` function instead.
- The values are written to and read from VRAM for each and every pixel, causing insane memory bandwidth use for values that should rather be in the instruction cache.
- If you instead just make a hardcoded matrix out of them, the shader’s speed will tremendously increase.
- When making such edits beware that HLSL and GLSL matrices are transposed wrt. each other.
That said: Happy Hacking.