dj Profile picture
dj
gamedev tinkerer | graphics programmer @zenimax_online | 🏳️‍🌈 | they/them

May 13, 2018, 13 tweets

doing another vfx thread about my student project, @wildbrewgame
this time i'm breaking down my water shader!
#gamedev #indiedev #shaders #madewithunity

the starting point for this one is just a scrolling foam texture over a solid color alpha blended over the background.
there are lots of good stylized water tutorials out there, like this one by @minionsart : so i'm just going focus on what's different

next step is to add foam around the edges. i use a slightly different method here than others i've seen because instead of using the raw depth, i calculate the world-space position of the ground and then compare the water's height to that. if they are within a threshold it's foam

the code for reconstructing world-space coords from the depth buffer is just copied from what unity uses internally for deferred lighting, but i'll show it for posterity. the idea is to get a ray to the far plane which goes through the fragment and then scale it by the depth.

i also use the depth below to control the water's color. i take two colors as material parameters and smoothstep between them until it reaches some max depth

next up is to add normal maps and cubemap reflections.
the shader takes two scrolling normal maps and blends them together in a way that better preserves detail than just learping or adding them.
the reflection is code is just copied from unity's standard shader

now that we have normal maps, lets add some refraction to the background.
we can get a texture with everything that has already been drawn to the screen using a grab pass: docs.unity3d.com/Manual/SL-Grab…
now we can sample from this texture using distorded uvs based on our normals

the refraction is a cheap and dirty effect that doesn't factor in the depth of the water. to get the uv offset, transform the normals into view-space to get them relative to the camera, and then transform them into projection-space to correct for the aspect ratio distortion

we also need to match the distortion when sampling the depth texture or the water color won't match up with what's behind it. the huge gotcha here is that the depth and grab textures can both be upside-down for different reasons so you need to account for both as shown:

now for the fun part, waves! i'm using a lot of tessellation and then moving the verts around with Gerstner waves. developer.nvidia.com/gpugems/GPUGem…
more detail in there, but basically these are sine waves that are pinched towards the peaks so you get some nice undulation on the surface

the last piece of the effect (and my favorite to work on) are some procedural ripples made using a render-texture bump map

i use the same top-down camera technique as in my grass shader so you can just read about it in that thread:
here i just have particles write the ripple height into the blue channel and then use that heightmap to deform the verts and normals of the water

and that's just about it for this water shader. i'm planning on revisiting this at some point and toying ray-marched refraction/volumetric lighting/more realistic fluid simulation, but for now, here's another video showing off the procedural ripples:

Share this Scrolly Tale with your friends.

A Scrolly Tale is a new way to read Twitter threads with a more visually immersive experience.
Discover more beautiful Scrolly Tales like this.

Keep scrolling