Jump to content
Search In
  • More options...
Find results that contain...
Find results in...




One of those things I wanted to make - and a big reason I think many people get involved in shaders - is water.  If you've been following along and grabbing these shaders you have now almost all the parts you need to make a basic water plane. If you understand these parts then you can manipulate them to customize your water as you see fit. I'm going to spend a little time in explanation here.

In making this shader I start with the base shader and add a texture scroll effect on the normals (02_texture scroll). I then duplicate this texture and scroll it in the opposite direction to give the impression of rippling water. I then add a creek direction so they both flow together down river as they criss-cross each other and that gives  the impression of flowing water.

I add a refraction effect to further the illusion and use the normal.z to adjust the refraction amount. Normal.z sort of intensifies the drama of your normals in terms of depth. Using it with refraction warps the pixels behind the plane to a greater degree. With the refraction effect added you get a nice creek base.

Here I've added a noobalyzed Leadwerks refraction shader, cutting some of the fat, so to speak , so that it is a bit more palatable to those wanting to learn shaders. Thank God Leadwerks includes a refraction shader because I think that process of working it out would have been ridiculous:




However, the Leadwerks refraction shader multiplies a camerainversenormalmatrix to the normals, which causes problems when you start trying to add things to it. So I came up with a solution that makes refraction work on the top of a box plane, but not necessarily on any of the sides. If you're making a water plane then that works perfectly, and it's a lot simpler than the above shader. I call it 19_creek base:


19_creek base.zip


In developing a creek from this, the first thing I did was find the refraction line and multiply it by some color. And then I multiply that by some float to give me control over the brightness of the water color:

    vec4 refraction = texture(texture10, screencoord);
    vec3 water_color = vec3(0.8,1.0,1.0);
    refraction *= vec4(water_color,1.0);
    refraction *= 0.8;


I then add a Phong effect to get a light reflection off the normals. Phong is very similar to Blinn-Phong but is half the size and is eerily similar to a fresnel effect. The difference is that in Blinn-Phong the light moves a bit with the eye. We don't really want that since we're simulating a distant sun lighting the plane.  Under the refraction section I add this:

    vec3 lightvec = normalize(lightposition - projectionmatrix[3].xyz);
    float phong = dot(normal,lightvec);
    phong = pow(phong, 2000);


... and change the output line to this so I can see what's going on:

   ... fragData0 = mix(vec4(vec3(phong),1.0),refraction,0.5);


You can see above I subtracted the projectionmatrix (ex_vertexposition.xyz also works) from the light position, got the dot product of this light direction and the normals, and multiplied the phong by some power. I use a ridiculously high number to sharpen up the effect. Increase the light position.y to about 8.0 or 10.0 to shine better on the top of the plane and you've got this effect (honestly it looks better in motion):



Next I want to get a reflection so I add a cubemap (14_cubemap reflection) for that:

    vec3 eyevec = normalize(ex_vertexposition.xyz - cameraposition);
    vec3 reflection = normalize(reflect(eyevec,normal));
    vec4 cube = texture(texture7,reflection);


The cubemap seemed a little dull to me so I use this trick to quickly increase the contrast in the texture, and you may see this around in some of my shaders:

    float contrast = dot(cube.xyz,vec3(1.0))-0.5;
    cube.xyz *= contrast;


After I have done this I mix the Phong and the Cubemap together so that I can adjust them together. Multiply each by some number to increase their brightnesses and I have a nice - albeit metallic-looking, creek:

    cube = mix(cube*1.5,vec4(vec3(phong),1)*2,0.5);

   ...fragData0 = mix(cube,refraction,0.5);



To resolve this metallic issue I use a fresnel (09_fresnel) to mix the cubemap reflection and the refraction to produce a smooth gradient falloff of transparency to reflectivity according to the camera view of the water. That sounds more complex than it is:

    float ndotv = dot(eyevec,normal);
    ndotv = pow(ndotv, 0.55)

    ...fragData0 = mix(cube,refraction,ndotv);


Note that I didn't establish an eyevec in the fresnel because I can reuse the eyevec established in the cubemap reflection. End result:




(The above pictures show the Leadwerks cubemap being used in place of the one I provided and it looks a lot better because there is more going on in the sky).

Lastly, you can take some of these numbers you've added and make variables of them at the top so they're all together. The water_color, for instance, feels nicer to me when I can put it at the top, open the shader and adjust it right away without having to go find it in the shader.

So there's a creek, or a basic water. Not that much at all once you're familiar with each of the parts. And if you can understand these parts and how to fit them together you are a true noob shader...er.

Happy shading!


Next: Masks and Texture Blending...

  • Like 5


Recommended Comments

There are no comments to display.

Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...