Sign in to follow this  

Writing A Basic Water Shader [GLSL / GLSL Beginner level]

This topic is 2397 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello I want to write a basic water shader that doesn't use anything fancy. I'm pretty much new to the world of GLSL so I don't understand everything yet. So I was hopping someone could help me write a shader as I go here?

Anyways I got a quad to blend two textures. The first one is the water texture, the second is the reflection and nothing really special is happening. I do want to expand on this of course and get a pretty good looking basic water shader.

For my first question; Whats the best way to get a simple reflection using a 2D texture? I want to achieve a very simple reflection of the sky just by using one image, but I'm not sure whats the best for the job without using a 3D cubemap texture.

Second question; How can I 'move' a texture around in GLSL? So I can get the water texture to move around to seem like it's real water.

Third question; How can I figure out how to change the color of the ocean using the water texture and a vec4 including the reflection in one fragment shader?

Thank you for reading and I hope to learn something new from the community! :)


Encase if your wondering what my fragment shader looks like:

Fragment
[code]


uniform sampler2D waveTextureId;
uniform sampler2D waveTextureIdRef;

uniform float waveTime;


void main()
{

vec4 color1 = texture2D(waveTextureId, vec2(gl_TexCoord[0]));
vec4 color2 = texture2D(waveTextureIdRef, vec2(gl_TexCoord[1]));


gl_FragColor = 0.6 * vec4(color1 + color2);
}
[/code]

Vertex
[code]


uniform float waveTime;

void main(void)
{

gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1] = gl_MultiTexCoord1;


gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

}

[/code]


Thanks, ajm

Share this post


Link to post
Share on other sites
Making the water texture move can easily be achieved by passing a (delta-)time constant to your shader each frame and by moving the UV-coordinates for your texture read accordingly
Depending on what kind of water you want to create, adding a moving bump map to simulate tiny ripples on the surface might be a good idea, and if you want larger waves you could use sinusoidal functions in your vertex shader to transform your vertex positions (your water plane needs a good amount of vertices for this to look right though)

I have never looked into single-texture reflections, I've only done cubemap and dual paraboloid reflections before so I'm not going to say it's impossible because maybe it is in some form (and if it is, I bet someone here could definitely explain it to you), although I think it's unlikely you'll get any good results

About your color question, you could use a grayscale water texture together with your own water color (or multiple colors) to be able to make quick changes to your final water color, although most ocean shaders use different colors depending on the depth of the actual water (but I assume this is too much for a really simple implementation)

To get a good water simulation you'll probably also need some form of refraction, although this could again be too much if this is just a very simple implementation


Hope I could be of help :)

Share this post


Link to post
Share on other sites
Single texture reflections (planar reflection) are definitely possible, and probably preferable in most cases. The technique is pretty simple (a while since I have done it though):
[list=1][*]Reflect your scene along the reflection surface (going to be a <0,1,0> plane for water).[*]Set up a clip plane to stop anything above the <0,1,0> plane from being drawn (i.e. in the reflected scene all geometry that was below the water surface is clipped away).[*]Reflect the camera in the plane again, to bring it back above the <0,1,0> plane (i.e. back to its original location).[*]Render the scene (remember to reverse your back face culling), this gives you your reflection texture.[*]Do your main render, pass in the reflection texture and access it using the screen coordinates, and use some technique to perturb the UVs slightly. You will have to do some fiddling to fix the edges of the texture as the perturbation will cause out of bounds UVs to be generated for which you haven't rendered anything. You could render a slightly wider FOV when creating the reflection texture, then scale back the UVs so that no perturbation will take the UVs out of bounds.[/list]
You can't use planar reflections on "proper" water where you have correct normals for which you wish to calculate a reflection vector, as they only contain a small subset of the geometry that can be visible from any location. But then a cube map reflection won't solve this problem correctly either as they only show the scene from a single location, and the further the pixel you are shading is from that location the less correct it will be. I guess when it comes down to is there is no way of doing physically correct water reflections.

Share this post


Link to post
Share on other sites
Thanks for the help! I have the basic reflection going and I'm able to change the waters color, but it's still kinda buggy.

[img]http://i51.tinypic.com/11tmwxe.png[/img]

That is what it looks like at the moment, I got everything from getting the water texture and reflection to move around and getting very basic reflection code in there, but the texcoords are out of wack for the reflection. Meaning the reflection image shows and moves around the camera, but it's stretched badly. D:

here is my shader now:

Vertex
[code]

uniform float waveTime;
varying vec3 vTexCoord;

void main(void)
{

//Get Multitexturing coords...
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1] = gl_MultiTexCoord1;


//Move the water...
gl_TexCoord[0].x += waveTime;
gl_TexCoord[0].y += waveTime-2.0; //Make the water move direction vary a little.


// Normal in Eye Space
vec3 vEyeNormal = gl_NormalMatrix * gl_Normal;
// Vertex position in Eye Space
vec4 vVert4 = gl_ModelViewMatrix * gl_Vertex;
vec3 vEyeVertex = normalize(vVert4.xyz / vVert4.w);
vec4 vCoords = vec4(reflect(vEyeVertex, vEyeNormal), 0.0);
// Rotate by flipped camera
vCoords = gl_ModelViewMatrixInverse * vCoords;
vTexCoord.xyz = normalize(vCoords.xyz);
// Don't forget to transform the geometry!



gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

}
[/code]

[code]


uniform sampler2D waveTextureId;
uniform sampler2D waveTextureIdRef;

uniform float waveTime;
varying vec3 vTexCoord;


void main()
{

vec4 color1 = texture2D(waveTextureId, vec2(gl_TexCoord[0]));
vec4 color2 = texture2D(waveTextureIdRef, vec2(vTexCoord));


gl_FragColor = 0.6 * vec4(color1 + color2) * vec4(0.0, 1.0, 1.0, 0.50);
}
[/code]

I'm finding GLSL very fun to play around with, but knowing what function is best for the job is a little beyond me.

Share this post


Link to post
Share on other sites

This topic is 2397 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this