# Rendering top down water on a 2D surface (OpenGL)

i'm looking for suggestions on how i could use shaders to create a water effect on the surface in the picture (below):

I am using noise to create heightmap and normalmap textures that is uploaded to GPU. I am the rendering a plane of vertices using Triangle strips. Each vertex then samples the those textures to get normals and Y-value (height). The Y value (0-1) is just used to sample a "palette" texture (with the color shown in the picture), the vertex Y value remains 0 across the entire terrain. So it has a 3D look but it's just a flat plane.

Now, if it were 3D i could render a quad at Y = 0 (water level), and use this to create a water effect like this tutorial: OpenGL Water Tutorial

But i am unsure how to do something simular in 2D. All vertices are mixed in the same mesh. Before i have used tiles. And then i could single out and render the "water-tiles" to an fbo and do some effects.

So does anyone have any suggestions on how to identify the water, and only do the effect on the "blue" and not the rest of the terrain? I'm not sure if the question is any good, but i can provide more details if needed.

(The picture shows below 0 terrain as blue, ideally it would be something like brown with a semi-transparent "water layer" on top of it)

Maybe i could render a quad and discard all the fragments above the water level or something like that?

EDIT After applying a shader: (The colors are not final, and i need to blend the shorelines. But a good start :))

• Could you not just use the same height value you use to choose the blue value to choose whether to apply the water effect in the same shader, or to modulate the opacity / clip non-water pixels in a separate water shader? It doesn't have to be literal 3D height in the depth buffer for you to use the value to do math and make decisions. Commented Apr 12, 2022 at 17:18
• I guess i could. So pass the height value to the fragment shader, then: if (height < 0) do water effects on the fragment. If that was what you meant. From what i read about how shaders work in paralell, my understanding is that per-fragment divergence (if statements where some frags does A and other B, is not something you want) that it would be better if all frags goes through the same calculations at the same time is better. (But i really don't know what i am talking about) I might test it. I would ideally simulate rising / lowering water levels. That might be hard with doing it like that.
– Dahl
Commented Apr 12, 2022 at 17:40
• hmm. no i guess i wouldn't be too hard when i think about it. if i have a uniform (some sine-function value or something) that adds to the water-level. if (height + uniform < 0). So yeah. I think i will try it out. :)
– Dahl
Commented Apr 12, 2022 at 17:59
• Fortunately, most of your water/land is in contiguous areas, so any divergence is limited to a narrow band right along the shoreline, where it's unlikely to hurt you badly. Also, as a 2D game, you're unlikely to saturate the GPU's capacity, so even an inefficient shader should still give you good performance. Commented Apr 12, 2022 at 18:16
• I tried to just paint everything below water-level red, and it works just fine. So now i just need to find some simple water algorithm. Looking for something that just alters the surface normals in a watery way. :) think your answer suits my purposes. My maps are pretty big, 4096 * 4096. But i am using quadtree culling with LOD etc. But i don't think any divergence would affect performance in my case either. Thanks!
– Dahl
Commented Apr 12, 2022 at 18:27

The solution to my problem was to pass the height value sampled from the heightmap texture in the vertex-shader, on to the fragment-shader. Then query that height per-fragment to see if it's below "water-level" or not. If it is then I do water-effect calculation on it.

It's kind of obvious when I think of it. But in my mind I had to do water calculations in a separate shader-program. :)

If you are here about HOW you could do the calculations. @DmGregory mentioned these past Q&A: here , here and here

2D can be implemented as 3D from a fixed view & projection, so you could still use the approach in the tutorial. If you like how the tutorial effect looks, I'd start with that.

The angle will be different than shown in the video, so you may need to tweak the parameters. With respect to that, keep in mind that it's your game and how it looks can take precedence over the 'simulation truth' (that is to say, things like where the light source is located, camera angle & so forth). Often times shadows in 2D games aren't realistic, but still provide useful visual cues about depth. You can do the same thing with your water effect - if it looks watery, it is doing its job.

• I fully agree with you. I am not really looking for realism, just some a simple shader for the water. No reflection or anything like that :) Just a way to separate the water from the landmass so to speak. Apply the effects to one part of the mesh, but not to others. Not quite sure on how i could do that. In the tutorial he use a quad that is hidden below the terrain in 3D. But when the mesh is a flat plane that wouldn't quite work. I am not sure i got the first part of your answer. In my game, you could still pivot the camera etc, it won't not be entirely "top-down"
– Dahl
Commented Apr 12, 2022 at 16:17