H2O: Making the Water In Extrasolar
As a graphics programmer, Extrasolar has been one of the most fun projects that I’ve ever had the opportunity to work on. The game offers a huge amount of freedom and flexibility because it doesn’t render in realtime. Due to this, I could focus on visual quality and not have to worry too much about the performance. I’ve never worked on film before, but I imagine that it’s similar to working in that medium where it can take an hour or more to render a single frame.
One of the areas that shows off the extra visual quality and detail is the water. The player is island-bound for the entire first episode of the game, so it was important to make sure the water looked good:
I decided to use what’s called a “projected grid” for the rendering, and based it on Claes Johanson’s excellent masters thesis “Real-time water rendering - Introducing the projected grid concept” which can be found here: http://fileadmin.cs.lth.se/graphics/theses/projects/projgrid/projgrid-lq.pdf.
Rendering water as a projected grid is sort of like ray-tracing with vertices. You start with a grid of evenly spaced vertices from the perspective of the camera - like looking through a screen. Then each vertex in the grid is projected into the world and if it intersects the water plane, the intersection point (x/y) is found. Then the point is offset vertically (z axis) depending on how high the water is at the intersection point (ie wave height). Once the xyz point is found in 3D space, it is projected back into 2D post-projection space like any other 3D point.
This process is the reverse of how it is normally done, where you would create a giant mesh of points on the water plane and then render it like any other piece of geometry. When this is done, the vertices mostly end up in the distance on the horizon where the least amount of detail is needed. Like in this image, where you can see the vertices are much closer together in the distance than near the camera at the bottom of the screen.
To compensate for this and reduce the number of vertices in the distance, water renderers use lower Level-Of-Detail (LOD) meshes in the distance. This usually works well enough, but it requires more code and it can be a pain to swap meshes in and out of video memory among other things.
The projected grid concept is much simpler. It all runs in one shader, and since the points are evenly distributed in viewspace, there’s no need for LOD meshes and there is plenty of detail close to the viewer. Here’s a wireframe closeup of what the water mesh looks like in Extrasolar:
As you can see, the points are evenly distributed from the horizon where there is little offset from the waves, all the way to the shoreline on the bottom where the waves are at maximum offset. Since Extrasolar doesn’t need to render in realtime, we can use a dense grid to get very detailed water geometry.
Once the geometry was done, it was time to add surface properties to the shader. We added shallow-water refraction, deep water foam, shoreline foam, and finally reflections as can be seen in this sequence.
I hope you enjoyed reading this blog, and I hope you check out Extrasolar. There are a ton cool things to see and explore on Epsilon Prime!