You can choose!
Read the article or watch the movie.
Both contain (almost) the same content.

If your game demands for having boats swimming in water you might get interesting problems to solve. Since boat-water-interaction is pretty expensive to simulate, normally the water-plane just cuts through the boat-geometry like in this example:

Today we’ll look at some smart solutions how to hide that artifact from the players eye.

Big boats usually don’t have this problem – at least if you’re standing on deck or the camera shows the ship from the outside. In these cases you can’t see into the ships “belly” and wouldn’t notice the water-plane.

But one day I saw this funny bug-video recorded from Back Flag which shows really obvious, that the developers actually pushing the water away below the boat!

So I got the game to investigate this issue and even if the effect is way less drastic, if you look closely you can see how the ships interacts with the water:

Unfortunately I couldn’t find too much detail about this. This is one of the few quotes I got (note that this is from about Assassins Creed III [not Blag Flag!]):

Full detailed collision detection with fluid dynamics and rigid body interactions would be impossible in realtime, but it is effectively simulated by the use of multiple partitioned boxes or ‘buoyancy spheres’.
Assassin’s Creed III: The tech behind (or beneath) the action

The article came with this picture. But by looking at the bug video and the accurate ship-shaped hole in the water I can’t believe, that the job would be done by only these spheres…

After releasing this article someone (he/she wanted to stay anonymous) brought light into the dark:

“The buoyancy spheres are probes used to measure the velocity of the ship entering the water at that location, it tells the particle splashes when and how big to spawn.
The water is pushed downwards based on a small displacement mask that’s projected onto the water. You’re right about the clipping plane on the small boats.”
– A nice but anonymous developer

Anyway, the engine does an impressive job with that simulation – but something else catched my attention during the investigation. It was the small boats in the game.

Like explained above, big boats can hide the water-plane by not showing the insides of their “belly” to the player. Smaller boats often don’t have this luxury but as you can see in this evidence-video, somehow the water-plane is not visible even the boat “sticks” in the water:

Before I present my theories about the solution, here is how it looks in some games where this problem wasn’t a big priority:

Source: Sacred 2

Sure, if your boats are damaged anyway they are allowed to be filled with water like below. Bot let’s look at solutions to this issue without having to physically simulate all the water!

Source: Fallout 4

If your game-camera always looks from above (like for example in most action-rpgs) a common workaround might be to let the boat just float a bit which shouldn’t be that visible (except the boat drops a shadow on the water). It’s a dirty hack but Mr. Pirate doesn’t care as long as his feet are dry. :D

Inspired by the big boats you can add some geometry to the boat to hide the inside of the “belly”. So the water actually is in the boat but as long as it is not higher than the added geometry nobody will notice. Job done. Arrrr!

Here you can see exactly that done in Fallout 4:

Source: Fallout 4

Now back to the boat in Black Flag. Clearly the water-plane is high enough so than we should see the water in the boat.

The magic seems to be coming from an invisible geometry which is covering the top of the boat like a lid:

At first I thought this plane might be used as a mask/stencil buffer so that the game just would not render any water in front of this plane but this would be problematic if you would have a big wave like this looking at the boat from the other side:

If you would not draw any water, the wave would have a “hole” where the lid-geometry of the boat sits seen from the pirates point of view.
Then Attila mentioned a technique called “DepthMask” (read more about it here) and this seems to be the key:

You first render your terrain, pirate, boat, etc. and then – and this is the secret weapon here – you draw the invisible plane but you draw it only into the depth buffer!

If you don’t know what a depth buffer is, I tried to visualize it here. Basically it’s used to store the distance to the camera (per pixel) and is used for sorting. With that you can (but don’t have to) discard pixels behind other pixels before executing the pixel shader:

Now you can render the water-plane which will only be visible in those areas which aren’t already obstructed (based on the information in the depth buffer).

Here you can see this in action:

What’s happening?

  1. There’s no water and no invisible plane (you can see then inside of the boat in the depth buffer).
  2. Invisible plane is rendered into depth buffer. Now you can’t see the inside of the boat in the depth buffer. No new pixel below the invisible plane will be rendered anymore.
  3. Water is rendered where no other pixels of the depth buffer obstruct it.

And here comes some evidence for all this:

1. Sometimes you see artifacts like in the example from the beginning of this article. When the waves are higher than the lid-geometry you can see this:

2. Sometimes you can see foam inside the boat which leads to the suspicion that the water-plane is still there (even if we can’t see it) and the logic reacts the to player spawning foam.

3. When we disable the draw call, which draws the magic lid-geometry, it looks like below. Look at this, I guess we’ve found the water!

Isn’t that beautiful?
By the way, while working on this article I remembered another game which might be worth a look:

In Battlefield 2 you could have these amphibian vehicles where players could sit in the “belly” of the car.

Source: Battlefield 2

So I wondered how they would cut away the water-plane for those players to avoid that:

This is how it looks when you’re sitting inside this car. As you can see, there’s no water inside which surely makes the soldiers happy.

Source: Battlefield 2

I tried to investigate this so here’s what I found out. Just to recap, this is our result:

To get there, very early (in my case it was the 13th drawcall of ~280) the geometry of the windows is rendered (here he lower left corner):

Just for better understanding, here’s how this geometry looks like from further away:

Note: Nothing is visible yet! I suspect that this just serves as a mask to know what needs to be rendered so that you can discard everthing in the black area:

Then the terrain and water is rendered and the mask seems to keep the water out.

Just a side-node: If you disable the drawcall for the windows-geometry right now, it looks like this:

You may think that everything is fine but wait until they render the foam on the water:

Luckily they render the window-geometry again! This time we even see the geometry (i increased the contrat a bit to make the geometry better visible):

Basically that’s it. Of course the UI is rendered next but this isn’t really important right now. :)

So the truth is that the soldiers having a bath all the time but this is basically done to them:

I really hope you like the new article/video and I would love to hear your opinion, tips, ideas, theories and whatever else you want to tell me. Have a nice day!

Links & Resources

[a01] Assassin’s Creed III: The tech behind (or beneath) the action
[a02] Assassin’s Creed IV: Black Flag Ocean Technology Talk
[a03] Assassin’s Creed IV: Black Flag Has The Most Beautiful Bug I’ve Seen
[a04] Interactive Water Surfaces
[a05] 5 things you need to know about the tech of AC4
[a06] AC4: Black Flag Graphics Tech Explained
[a07] Unity 3D Wiki: DepthMask
[a08] Wikipedia: Z-buffering/Depth Buffer
[a09] A trip through the Graphics Pipeline 2011, part 7

Update 1
GameDevIvan mentioned his very interesting video in the Youtube comments:
Update 2
Gil mentioned in his comment how this could be done with a stencil buffer and shows an example picture:

Update 3
Felix Jones wrote in his comment about the boat-history of Minecraft. And how his suggestion led to the implementation of a “real” solution instead of the “hidden belly”-approach.

Update 4
Max McGuire mentioned that they use “signed distance field to clip the water from inside the escape pod” in their project Subnautica.

6 thoughts on “Assassin’s Creed: Black Flag – Waterplane

  1. Gil

    Very nice article!
    About the masking of the water in the boat, another approach is the usage of a stencil buffer. Stencil buffer is basically a mask (generally 8bits) that you can read, write, increment and decrement that is often use to create portal effects, masking certain objects or even redner shadows, like in doom 3. If the hidden geometry is writing a value to the stencil buffer, let say 1, and the water is rendered after that everywhere except on the pixels that have a value of 1, then you’re good.
    Here is a screenshot of the stencil technique in action :

    1. VillyBarankin

      But, like in an example at article, in the situation with looking on a ship throught a very high wave wouldn’t you discard nessesary fragments and see a hole in wave?

  2. Felix Jones

    I made a rather terrible image gallery explaining this depth mask solution for the Minecraft 1.9;

    Prior to the 1.9 update, boats in Minecraft had a “hidden belly”, which solved the problem of them flooding, until they got too low and then the problem appeared again.

    During the 1.9 update, a preview version had lowered the belly of the boat – which resulted in them becoming permanently flooded. Mojang saw my image gallery and implemented the solution :)

    There is another technique as well; portals! A stencil buffer can be used in-place of the depth buffer for masking, however this comes with the limitation of the water needing to be a uniform level (no large waves in-front of the boat). The benefit is that the depth buffer is not modified, which may be important for other effects.


Leave a Reply

Your email address will not be published. Required fields are marked *