I am looking at implementing a water surface on my spherical object and have created a texture with transparent pixels where the water should be. However, I am currently confused on how I can extrude only vertices where the texture is transparent. Do I have to test the texture at the appropriate position prior to assigning the vertex and just assign a Color.Transparent value to that vertex or am I thinking about this all wrong?

Special thanks to @Bram for helping me to answer some questions that could help clarify my specific situation.

  • What geometry do you extrude?
    • Individual vertices with a geometry, fragment, or hull shader.
  • What is the extrusion for?
    • To make waves in the water.

When I mention testing texels and then assigning colors to a vertex, I mean doing so beforehand when creating the Vertex[] object. This would be easy enough to do I suppose; I'd have to look into some samples of how to test the texture on the C# side, which is why I'd love to do it in a shader that has a similar flow as below:

  • Vertex Shader
    • Create the sphere.
  • Pixel Shader
    • Grab only vertices that have transparent pixels via TEXCOORD0.
  • Geometry/Fragment/Hull Shader
    • Extrude those vertices.
  • \$\begingroup\$ There is no 1:1 correspondence between vertices and texels. Also, what geometry do you extrude? And where? In a vertex shader? On the CPU? What is the extrusion for? To make land lay higher than the sea? To make waves? \$\endgroup\$ – Bram Nov 16 '18 at 18:56
  • \$\begingroup\$ @Bram I've edited my post and hopefully clarified some things. \$\endgroup\$ – user121635 Nov 16 '18 at 19:07
  • \$\begingroup\$ I updated my answer with a shadertoy implementation, as it seemed like a fun challenge. The waves still look a little fake, but can be a good starting point for you. \$\endgroup\$ – Bram Nov 16 '18 at 23:06
  • \$\begingroup\$ @Bram That’s actually really cool! I’ll have to play with it more on Monday! \$\endgroup\$ – user121635 Nov 17 '18 at 0:05

NOTE: the vertex shader would not create a sphere. It would consume the sphere vertices, and generate fragments. A fragment is kind of like a pixel on your screen, but may or may not be visible depending on fragments in front of it.

I see three possible ways of creating a globe with water and land, and have water show wave animation.

(1) Split land/water on CPU: Separate the sphere mesh into two parts: The land part, and the water part. Then use different shader programs to render them.

(2) Split land/water in vertex shader: Render the globe as a single mesh, and at render time, figure out if a vertex lies on land or water. If it is a water vertex you could perturb the vertex.

(3) Split land/water in fragment shader: In the fragment shader, you look up the texel to see if it is sea or land. If it is sea, you could apply an animated bump map, or better: procedural animation by just perturbing the surface normal a little bit.

Note that your globe geometry will have a much lower resolution than your land/sea texture. So doing a land/sea test per vertex (solution 1 and 2) will only roughly follow coast lines. Solution 3 would definitely look better.

When going for (3) you could even do something similar to "percentage-closer-filtering". Instead of a single texel lookup, you do 9 or so look-ups in its neighborhood. Then you count the number of land texels. If you see both land and sea textures, you know you are on the coast-line. And at coastlines, you can then render a white band to show the "surf" of waves breaking.

In pseudo code:

colour = texture_lookup( uv );
float delta_uv[9][2] =
  -e,-e,  0,-e,  e, e,
  -e, 0,  0, 0,  e, 0,
  -e, e,  0, e,  e,-e
int numland = 0;
for ( int i=0; i<9; ++i )
   samplecoord = uv + delta_uv[i];
   rgba = texture_lookup( samplecoord );
   if ( rgba.a >= 1 ) numland++;
if ( numland == 9 )
   // inland:
else if ( numland == 0 )
   // deep sea:
   // coast line: render as white.
   colour = surf_colour;
// Shade the fragment using the surface normal, light source, colour, etc.

Note that you could have the surf wash in/out the coast by replacing the ( numland == 0 ) test with something more dynamic: some frames you render more surf, some frames, you render less.

UPDATE: because it seemed like a fun challenge, I implemented it on shadertoy. You can see the results and code there.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy