XNA 4.0 Shader Programming #6–Simple Ocean


Welcome back to my tutorial. Today, we are not going to learn anything new (almost), but instead put together a scene that uses some different shaders in order to see how powerful shaders can be.

The island

The island is a 3D model created by a friend of mine, Espen Nordahl. The island use a normal map and the same shader covered in tutorial 4, to make the model look more detailed.

The ocean

The ocean is a plane built up by many vertexes. We use the technique described in tutorial 5 (Deform shader) to create the ocean waves, and using normal map from tutorial 4 to make tinier waves on top of this. I used one normal maps, but sampling in in two different locations and moving each in different directions to make small detail waves ripple on the waves:

Normal = (Normal + Normal2)/2;

Here I take the two normals, adding them together and using the avg. of these normals when calculating lighting, diffuse and specular( Tutorial 3 ).

I also move the texture coordinates on the color map, making it look like there is some stream in the water.

Implementing the shader

Shouldn’t be anything new. The ocean is very large so I started the shader by multiplying the texture-coordinate with 20, making the texture repeat 20 times in both the X and Y direction. I then sample the color for the given pixel.

Next I move the texture-coordinate a bit before sampling a normal, and store it in normalMap. I do the same again after sampling in the other direction and store it in normalMap2.

Then I take the average normal and use that as the normal when calculating the rest of the lighting.

I also hacked a bit with the specular-calculations so it will be visible on small waves.

Remember, this is a quick and dirty way to create ocean. It’s quite cheap and easy to implement and looks OK when water is not in focus. In a later tutorial I will show how you can create a much better, but a lot more expensive water/ocean shader.

Let’s look at the code..

// The Pixel Shader
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
	input.TexCoord.x = input.TexCoord.x*20.0f + sin(TotalTime*3+10)/256;
	input.TexCoord.y = input.TexCoord.y*20.0f;

	float4 color = tex2D(ColorMapSampler, input.TexCoord);

	input.TexCoord.y += (sin(TotalTime*3+10)/256)+(TotalTime/16);
	float3 normalMap = 2.0 *(tex2D(NormalMapSampler, input.TexCoord)) - 1.0;

	input.TexCoord.y -= ((sin(TotalTime*3+10)/256)+(TotalTime/16))*2;
    float3 normalMap2 =(2 * (tex2D(NormalMapSampler, input.TexCoord))) - 1.0; 

	normalMap = (normalMap + normalMap2) / 2;

	normalMap = normalize(mul(normalMap, input.WorldToTangentSpace));
	float4 normal = float4(normalMap,1.0);

	float4 diffuse = saturate(dot(-LightDirection,normal));
	float4 reflect = normalize(2*diffuse*normal-float4(LightDirection,1.0));
	float4 specular = pow(saturate(dot(reflect,input.View)),28);

    float4 finalColor =  color * AmbientIntensity + 
			color * DiffuseIntensity * diffuse + 

	finalColor.a = 0.3f;
	return finalColor;


download Download Source (XNA 4.0)

This entry was posted in Tutorial, XNA, XNA Shader Tutorial. Bookmark the permalink.

5 Responses to XNA 4.0 Shader Programming #6–Simple Ocean

  1. emsleyan says:

    nice example 😀

  2. Looks like from an old game, but still cool!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.