0
\$\begingroup\$

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.
\$\endgroup\$
  • \$\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
0
\$\begingroup\$

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:
   PERTURB THE SURFACE NORMAL TO CREATE WAVE
   ...
}
else
{
   // 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.

\$\endgroup\$

Your Answer

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