Arctic Angler
A fishing game with a detailed water simulation.
Key Features
- GPU accelerated water simulation
- Reflective/refractive water surface shader
Description
This was my group's submission for the final class project in CSCI 5611: Animation & Planning in Games. The goal of this project was to create a small game using any of the simulation techniques we'd discussed throughout the semester. My group decided to develop a fishing game with realistic water and fish flocking simulations. My contribution to this project was creating a GPU-based 3D water simulation, along with a shader to render the reflective/refractive properties of the water surface.
Discussion
Water Simulation
The water simulation went through numerous iterations before reaching its final state which, amusingly enough, ended up being the first and simplest water simulation tried regardless.
What I Did
Specifically, I used the approach proposed by Matthias Müller-Fischer in this GDC talk which involves using a simple 2D height field to determine how water should propagate. What makes my version slightly improved is that it runs on the GPU via a compute shader, followed by an additional compute shader that calculates an interpolated normal map based on the height field every frame. These textures are sent directly to a custom water shader allowing for lighting-fast vertex displacements and normal vector adjustments to the water's surface, all without touching the CPU.
What I Tried
It's worth touching on another of the water simulations I attempted, as it certainly gave some interesting results!
With a GPU implementation of 2D Stable Fluids up and running as discussed here, I thought it would be a fun experiment to see if I could translate the 2D fluid motion it simulated into 3D, without actually fully simulating it in 3D. Inspired by this reddit post, I computed a height map using the pressure field from the Stable Fluids simulation, and ran it through the kernel that computes normals and passes that data to the water shader. The results were interesting with the right tuning, but when it came down to the simple fishing mechanics we were working with, the ripples provided by this approach simply weren't as good of a fit.
Water Shading
As it turns out, rendering a convincing water surface was significantly more challenging than simulating the water itself — especially once we realized that we were interested in water with true reflections.
In short, by using the normals our GPU compute shader so kindly provides, some slight fluctuations can be applied to both the objects rendered below the surface of the water (refraction), and the objects reflected off the surface of the water (reflection) to create a convincing water surface effect.
More specifically, I used a grab pass to get a texture copy of everything rendered before the water surface, and blended that with a water color based on the camera depth texture. The uv coordinates used to sample these textures were given an offset based on the normal vector of the surface at each fragment, giving the illusion of refraction.
For reflection, I positioned a second camera below the water surface mirroring the main camera, and sampled from its render texture (with uvs distorted by the normal of the water surface) in the water shader as well.
To simulate a basic Fresnel effect, the angle between the camera's view direction and each fragment on the surface of the water is used to control the blend between the refracted and reflected images (where a direct viewing angle straight into the water sees little reflection compared to an angle mostly parallel with the surface).
Even though these reflections and refractions aren't quite physically accurate, since all we're actually attempting to simulate here is the motion of water, it does more than enough to add some oomph to the believability of that simulation.
Demo
Credit
Group Members: Kevin Bradt (Flocking Simulation), Clara Huang (Character)
Assets: Character + Animation, Fish Bones
Tools Used
Languages: C#, HLSL
Software: Unity, Blender, Git