In The Fall of Oriath, which we released in August of this year, we massively overhauled how water is rendered in Path of Exile. In today's news post, our graphics programmer Alex talks about how he implemented this significant change:
As Path of Exile's growth continued, we invested more and more resources in its rendering engine. However, some players judged the engine based on old assets that were created years ago, so as our original water effect (one of the first things you see when you start a new character). In reality, we have been constantly working on keeping this engine modern, fast and extensible, and we wanted our players to see that. When I was given the assignment of replacing the game's water, even though I had lots of ideas I could potentially try, I knew that some of them (potentially most of them) will have to be ditched due to performance reasons or simply for not being pretty enough. Replacing all the water in the game was a really tricky task because many game assets used it and new water had to be 100% backwards-compatible with them. Making just a patch of water that looked pretty was not enough, it had to adapt itself to any terrain and any environment conditions that we had. And of course performance was among my top priorities, because we have only so much GPU power to spare on environment. My work on water mostly consisted of writing a shader for it, which is a program that runs on the GPU and produces its image on screen. In cases such as this you have to first entirely break what currently works, then start re-building it from scratch little by little to make it better in the end. I started playing with our old water shader by just generating debug normals for it and added a screen space edge detection algorithm to potentially render foam in areas where objects intersect water. (Note that the HUD UI shown on these screenshots was a work-in-progress version of the 3.0.0 HUD, before it looked like how it does now.) Even though edge detection worked alright, I knew that it might potentially have an unnecessary impact on performance so I had to ditch it. The next step was to add some surface-waves, color to the water and basic reflections: The surface is actually rendered via a raytracing algorithm in screen space, which means that the water is actually flat, but looks 3d because of shader techniques similar to parallax occlusion mapping. At a point like this, I had to decide what's working well and deserves to go the next iteration of development and what has to be re-done from scratch. The funny thing about rendering water is that you don't actually see water color itself that much. You see stuff that it reflects from its surface and refracts, so I decided to work closer on that part, leave the raytracing part as it was and re-making everything else. For reasonably accurate reflections I even implemented a screen space algorithm that actually reflected stuff that's on screen. An example is this 100% reflective mercury-like "water": It's one of those things that you have to ditch no matter how much you like them, just because they don't justify their cost in the end. The most complicated parts of rendering water are probably the surface ripple generation algorithm and the foam rendering algorithm, because they require a lot of artistic intuition (that I'm not known for). Everything else is just physics, optics and programming that are significantly more straightforward. I knew that first experiments with foam were going to be rough, yet I started: Even though I knew I was on a right track, I had to precisely understand what makes real foam look real. For example, my noise had a very regular structure, and real foam is governed by very turbulent and irregular currents that twist it. At the same time, I made a simple app to study closely the way water particles move in a wave cross-section and when waves start cresting. After putting all that into my shader, partially fixing some lighting, it started to look like something: Countless reference videos were studied, lines of code re-written and professional surfers talked to in order to make this foam look as close to real one as possible and be as performant as possible. After implementing a physics engine for cloth, water rendering became my next biggest task - my mind was completely occupied by it. In our gym we have a great view of a swimming pool and I was constantly hassled by my mates for staring at girls there. Ugh, they just did not understand how I was actually captivated by studying surface wave patterns, caustics and double refraction effects. I saw clouds and thought how they would reflect in water. Saw a plant and couldn't stop thinking how it diffuses light from under the surface of its leaves, because same thing happens with ocean water. The next step of development was to ensure that this tech works with any areas we have and that it follows the shoreline in a hopefully natural way. Around this point a trailer that featured some of this water tech was made and people were rightfully concerned about swell going on a very unnatural angle. Crazy areas with very complex shore structure such as The Brine King's Reef were particularly bad and I decided to make another side-project to generate a smoothed shoreline in a controlled wave. This algorithm allowed us to smooth the shape of waves in a more natural way to any degree we wanted. Adding HDR environment maps helped improve overall perception of the water surface as well. What it means is that it allowed us to create really bright "sparkly" patterns that you see when the sun gets reflected from waves: From that point it was just a matter of optimizing the whole shader, and adding a bunch of other cosmetic effects. For example when sun rays get refracted by the surface, they create a bright pattern on sand caustics. Or when sun rays get reflected back from inside deep water, wave crests get a slightly brighter tint called subsurface scattering. Adding a physically interesting way of how foam dissipates on sand helped make the shoreline more interesting. All of those changes have brought us closer to the water we have today: The Twilight Strand is the first area every new player enters. Water is one the first things they see there. When creating this new water system, I really wanted them to like Path of Exile right from that point. |
|