Parallax!

Mountains should be big and vertical, and now they are!

Posted by on

Before saying anything, it's much more fun to just show:

I've added parallax occlusion mapping to Victoria II! Now when you're looking at mountainous areas, they won't just be flat textures. Well, technically they still are flat, but it won't look flat, which is the important part. I've released two versions - one with the terrain visible while zoomed out and one opaque when zoomed out. They're down in the files section now, version 0.3!

A little bit on how this was done - I first tried to physically alter the vertices of the map in the shaders, but it turns out there aren't enough vertices to really get any sort of attractive terrain features - mountain ranges became just a bunch of mangled polygons. But in pursuit of this, I had already developed a very useful thing: a heightmap, seen below:

This isn't the final version that went into the game - that's got some minor filters and enhancements to minimize artifacts while maintaining enough detail. But having this made me wonder - could parallax be used in Victoria II? I wouldn't need to worry about vertex density with that method. It would certainly require either some creative work to get around the instruction limit for the game's pixel shaders, or more easily, what if Victoria II's fx files could be compiled with pixel shader 3.0? Turns out, they can be! That opened the door to making some serious changes to the shader pipeline, so I got to work. Thanks to a wonderful tutorial I've linked below, I was able to get started on implementing a parallax mapping shader, starting with the simplest version and slowly working my way up to the final, parallax occlusion mapping version. One snag was in the mathematical side of things - to properly do parallax shaders, one needs to use what's called the TBN matrix, or Tangent, Bitangent, Normal matrix. It's simply a 3x3 matrix made up of these three vectors, relative to the surface you are trying to use parallax mapping on:

You'll notice I've linked the most simple possible example - a flat surface. The fact that it's flat is important because so is the Victoria II map, and this is what makes parallax mapping in Victoria II possible even with the limited information Paradox passes into the shader pipeline. The map is flat, always flat, and always orientied in the same, predictable way. This meant the TBN was just the three unit vectors, {1, 0, 0}, {0, 1, 0}, and {0, 0, 1} (not necessarily in that order). I don't even have to do any math to get this - it's just the ground truth! But what DOES need math is the next part - comparing the position of a pixel to be parallax mapped with our view point. Getting our view position requires a matrix inversion, an expensive and involved process that I don't remember how to do despite my past courses in linear algebra, so that's where the second helpful link comes up, also linked below. Paradox could have supplied the shader with the inverse view matrix, but they did not, so for accurate parallax I need to do the calculation every time in the pixel shader... any performance loss from this mod almost certainly comes in the majority from that step. I am running the game with a pretty beefy rig so it isn't an issue, but for those who aren't and experience issues, I am working on the next version of the mod already which will approximate the needed position with the transpose of the view matrix! So far it's promising, but there are some little issues that are impossible for me to ignore given how much I've been looking at the mod myself, so I want to keep drilling away at that.

Other future items I want to work on are more heightmaps for different terrain types (only mountains and large hills really have any height to them now, but I want to add a gentle rolling effect later on for flatter areas) and perhaps even parallax water visuals. I could certainly improve my heightmaps as well. But I'm really happy with how it turned out for now, and I am eager to see how far I can take the shaders to give Victoria II a fresh coat of paint going forward!

Before signing off, here's a video of the effect in action, in the HPM mod:

Credits:

LearnOpenGL - Parallax Mapping

Inverse matrix code for HLSL came from here:

Matrix operations for HLSL · GitHub