The First Attempt: Shader
The most defining aspect of the water, as I understood it from the concept art and pre-production documents, is the foam. Foam around objects is an easy enough effect to achieve inside the shader, the problem with this however, is that the outline is only drawn over the object’s mesh, meaning its visibility depends exclusively on the angle of the camera. This is no good because we need something that’s visible from a top down perspective.
The Second Attempt: Mesh
After spending some time studying shaders and trying to figure out if the effect I had in mind was possible with them, I had the idea to try a mesh based approach: this came down to calculating the intersection points between the segments of the mesh and the water plane, and here is what it looked like.
As you can see the shape of the mesh affects the shape of the foam, meaning sharper objects have more jagged looking foam. I decided this wasn’t a deal-breaker yet, so I continued fleshing out this approach. Here it is in motion:
The next problem was that the water plane isn’t exactly a plane: waves move and deform the entire mesh. My intersection solution worked fine with a simple plane, but once I started using individual triangles instead, the framerate dropped considerably because the calculations were too many to carry out every frame. I decided to continue working on it, figuring it would be better to get something working inefficiently and then optimize it, than having something fast and generic looking. This is what that looked like:
Still happy with this approach, I decided it was time to improve the look of the foam, so I began looking into UV solutions and texturing to give the artists more control over everything. Here is what it looked like with a simple texture with different blues.
I also looked into smoothing the foam mesh, which I succeeded in doing by calculating the angle between every three points, and adding another vertex in between if the angle was below a certain threshold. At this point I decided to take a step back and re-evaluate my options because a lot of intensive calculations were happening every frame for an effect that ended up being quite rough. Also after trying in the current build, calculating intersections ended up proving not to be practical, so it was time to try something else.
The Third Attempt: Particles
I started experimenting with particle emitters attached to the objects, trying to avoid having to calculate the intersection points. The results with just a simple sharp circle as the particle shape looked like this:
The advantage of a particle based approach, is that I could rely on the fact that emitters simulated in world space would react to their environment. More specifically, the foam would linger slightly behind objects as they bob through the water making everything look much more organic. Additionally, being a particle system, the artists can really play around with all the settings and tweak everything until it’s just right. The downsides however, are that every object would need its own particle system that reflects its shape: a long plank would need a different setup than a round buoy for example.
Simple round particles weren’t gonna cut it though, so I started thinking about how to make the effect more interesting. I decided I would revisit an effect that has been around since the early 1980s, called metaballs. Metaballs are organic looking blobs that seemed like they would fit the feel of the foam properly. This is essentially how metaballs behave:
This effect can be obtained by overlapping two sprites with a soft blurry edge, and flooring the value to a certain intensity. I thought this would give the foam a nice blobbiness, and the foam of nearby objects would mesh together nicely.
The first way I thought of creating this effect was to use multiple cameras, one that renders everything but the particles, and one that only renders the particles and applies the metaball image effect. While this worked in theory, compositing together multiple cameras gave me a lot of problems, mainly with depth. The way I ended up doing it made use of the stencil buffer available inside the shader. Basically I mark all the pixels rendered by the particle system, and only apply the image effect on those pixels, effectively removing the need for a second camera. This also allows me to do things like not render the water inside the boat without needing a shader mask and a separate plane. Here is what the first tests looked like:
At this point it started being time to implement my solution in the current build of the game. I struggled with creating a particle emitter in code for every object, because a lot of the options don’t seem to be accessible anywhere but the inspector itself. So in the end I made a prefab of the foam that I am instantiating as a child at the position of every object.
After various tests and succeeding technically in doing what I wanted, it turned out that the effect didn’t end up looking like what I had in mind:
Between not being subtle enough and the fact that particles linger behind and sometimes hover in the air when the waves move objects down, we decided yet again to try something else.
The Fourth Attempt: Animated Textures
This is the last approach I’ll be detailing today. It revolves around using textures like spritesheets, to get an animation within the texture. I decided that working as much as possible within the texture will help avoid a lot of problems that stem from the fact that the water moves. A texture moves with the water, so my gut tells me there is something worth exploring there. Here is an early picture of my experiment:
The idea is to make the water more interesting with textures as opposed to simulated foam, and perhaps use the initial depth shader solution in combination with this approach.
The perfect approach has yet to be discovered, and it is more than probable that it will end up being a combination of the above attempts. The water is a very important aspect of the game so it’s likely that it will take some more time to settle on something that is to everyone’s liking while still being performant enough and viable for the game. That’s it for this week, stay tuned for the next post about the water. I’ll detail how I achieved the effect in the header image and the gif below, which is what the water currently looks like. Thanks for reading!