Shader: Lake with a gradient

Hello,

pheew. I’m close to giving up on that one.

Our artists asked me for a mobile shader for our rivers and lakes that would automatically turn the water brighter at the edges while the middle should get a darker tone. Like here…

Usually this problem is solved using the depth buffer making use of the ground below… though… our world is flat unfortunately.

What I already tried was some preprocessing at editor time where I was using the second UV channel to save for each vertex the distance to the closest edge.
Writing a shader which would make use of that to create the gradient was easy… though… while that worked for our rivers… it didn’t work for our lakes which are generated and have a non-suitable tesselation for this (see pic). D’oh!
(Whatever… that solution of modifying the mesh at editor time was a mess anyway)

I’m really running out of ideas…
…and I got the gut feeling that there’s just no reasonable solution for this.

Am I wrong?

You can send to frag shader vertex local position without iterpolation. And then get fragment local position in the mesh and calculate distance to vertex local position. Becouse all you vertex are on a mesh border. It will make uneven effect but i think it will be well for your case. You can fix mesh in the sprite editor as well

That wouldn’t work. You’d only get the first vertex of each triangle across the entire face, which wouldn’t give you a nice border but a distance to an essentially random vertex of the triangle (the first vertex of a triangle isn’t always what you would expect). The only way that would work is if you stored the position of the other triangle’s vertices in each vertex, which would also mean you couldn’t reuse vertices, which would make the mesh take a lot more memory and be slower to render.

I can think of two ways to do this.

One would be to use the extra UV set to mark the edge’s 2D “normal” (like the surface normal if the edge was extruded). You can then use the length of the interpolated vector to get something like a distance to edge. It won’t actually be a distance to edge as the gradient will change depending on the width of the same, and some geometry it’ll still fail on completely, but it’ll get you something.

The other way is just use a texture. Either make your artists do it, or in the editor render the shape to a render texture, blur it, and save it into an atlas and be done. That’ll be way cleaner to implement, and way cheaper to render.

1 Like

Thx, a3dline!
Would have been a really nice solution… if I’d always get the closest vertice at the edge. Grrr.

Thx, bgolus!
I see, I see… method 1 could work somewhat Fresnel-like.
I understand it that way that all these 2D “normals” at the edge would look away from it.
And right in the middle between to edge vertices we’d more or less get a normal with length zero due to interpolation.

Sounds good…
I just can’t wrap my mind around how to calculate the normals on the vertices INSIDE the mesh - e.g our rivers are tesselated like this…

The normals could be either like in the left or in the right picture… both variants would work for such a shader…

… but calculating the inner normals would require a rather complex solver, wouldn’t it?

These rivers unfortunately also ruin your 2nd solution. They are sometimes spanning across multiple screens… creating textures for those would require quite some space. Even if the resolution could be heavily reduced as we essentially just want a gradient.

Outer edge and the first vertex in would have their “normals” pointing away from the center vertex. The “first step in” normals would be scaled down rather than normalized. And the center vertex would be 0.0. This only really works if you want the center of the rivers to be the same color as the center of the lakes though.

You wouldn’t need a full texture for your rivers, just a single gradient strip that all rivers map to across the width of the river and stretch across the full length.

Really though, you probably either need to handle your rivers and lakes with different shaders, or you need to generate your lakes with the same kind of geometry as you do your rivers. There’s no solution that can work perfectly for both with the geometry you have that doesn’t otherwise require some amount of per water feature customization.