Faking ocean whitecaps in fragment-only shader

For my boardgame-style map I needed an extremely subtle effect for the ocean areas of the map. All of the amazing super-realistic ocean shaders out there would be very distracting. Since the map is composed of a fairly large stack of texture masks, my holy grail was also a fragment-only shader, so I had to experiment to come up with something myself. I’m happy with the look – it’s just a slow scroll of a static ocean texture mixed with a normal map to fake larger-scale waves or upwellings – it’s almost a subsurface type of effect.

I’m totally new to shaders, I started this one a little over a week ago. I have been struggling to add one final feature: wave-like whitecaps. I’ve tried quite a few variations of noise functions and noise maps but I just can’t get that fine, brief fade-in/fade-out of bright, wave-top highlights that would be appropriate to the scale of my water surface. I’m looking for tips about how I might accomplish the desired effect, and again, it must work as frag-only – no vertex or lighting input.

A short clip of the way it looks now (YouTube compression kind of mangles it but…)

Wow, that YouTube version is really bad. Or the Xbox screen-recorder is terrible, not sure which.

Anyway, I got close with a noise function but it gets that “plastic-wrap” look that I hate on so many water effects, and the code was vast and complicated and created compile-time temp register errors, and try as I might, I couldn’t dial it down to something more subtle.

I have been trying to use the much more lightweight 2D simplex noise from Ashima/Gustavson but I can’t seem to narrow down the bands more than what you see on the left, below (I dialed up the intensity here to make it obvious for the screen shot). If I filter for increasingly closer to 0.0 or 1.0 the connecting bands go away and the “clumps” just start getting smaller. I have seen filtered simplex output that looks like the wavetop whitecap patterns I want (as in the second image below) but I can’t seem to figure it out. It is claimed that second image is white = abs(noise)>0.1, but it sure doesn’t come out that way in my code…

2638195--185610--3.jpg

Got it… the answer is: caustics. Generated a couple of interference patterns by mixing eight trig calls, then cherry-picked the absolute highest values out of the refraction keyword, then mixed it with the base water texture. Probably hard to see here (I did want subtelty), but in motion, the white highlights in the water fan out and fade in and out in a pretty convincing fashion (far better than noise-driven effects), especially after I tweaked the scrolling to run at the right speed and counter to the water direction (which is how whitecaps form – window blowing against the waves). In places I get nice short-lived sharp short peaks, and other times I get softer wider effects as pictured.

Anyway, maybe the concepts will help somebody else, though “viewed from far overhead” doesn’t seem to be a common need.

2638439--185632--1.jpg

1 Like