XNA Shader Programming – Tutorial 5, Deform shader

XNA Shader Programming
Tutorial 5 – Deform shader

Welcome back to the XNA Shader Programming series. Since the start of tutorial 1, we have been looking at different lighting algorithms. Todays tutorial will be quite short and different, compared to those others, a pure vertex shader effect for deforming objects.
Before we start
In this tutorial, you will need some basic knowledge of shaderprogramming, a understanding of geometry, vector math and matrix math.

Deforming objects
Since vertex shaders can be used to process and transform vertices on a per vertex basis, it’s quite ideal to use them to deform objects/meshes. Vertex shaders make it really easy to deform objects, let’s take an example. Say you have a game that will make it possible to create your own character. This includes changing skin color, eye color, hair, clothes and so on. We can in this example create a vertex shader to create a weight property for our character, where say 0 means that our character will be very slim, and 1 that says that our character will be fat.

Fat/Slim
To do this, we need a vertex shader that simply moves a vertex along it’s normal:

If we move all the vertices along their normals, the object will be bigger, or smaller.

Ocean waves
Instead of making a big bone animated mesh to create a realistic looking ocean in your game, you could use a vertex shader to produce waves.
To do this, you will need a big flat mesh that will represent your ocean without any waves. You could either do this in 3Ds, or produce it with code. It will need many vertexes, as the shader will move them up and down according to a sine/cos function.

As we can see in this picture, we got a plane defined by alot of vertexes. We can here use a Vertex Shader to move all vertexes by its Y-axis with a sine function, say
f(y)=sin(y). Say vertex X is moved with pos.Y = sin(X.pos+time);
This will produce waves on the ocean. Ofcourse, this is really simple and pretty ugly. There is alot of differen Ocean algorithms out there, so if you want to look more closely on this subject, just do a google on the topic.

To make the ocean look better, you could apply a normal map to create small bumps on the surface, in addition to huge waves. You can also mix sine and cos functions to make more realistic waves.

"Fake Spherical harmonics"
This is what I’m going to implement today. Its pretty much a combination of the slim/fat algorithm and the ocean algorithm. The example will use a sphere object, and apply a pretty advanced sin/cos function to move vertexes along their normal in order to deform it, based on time.

Implementing the shader
The shader is just a Vertex Shader. The pixel shader will only do some basic lighting to make it look more real. You can add normal-mapping here and so on to create really cool looking effects( refer to my last tutorial, 4 ).
In this shader, we will need a time variable, so we can move our vertexes along with a timer to make it look animated, and then we only make a huge mess of sine and cos functions to make it look cool. Feel free to play with these values.
Here is the Vertex Shader for this effect:

float4 g_fTime;

OUT VS(float4 Pos : POSITION, float3 N : NORMAL)
{

OUT Out = (OUT)0;

float angle=(g_fTime%360)*2;
float freqx = 1.0f+sin(g_fTime)*4.0f;
float freqy = 1.0f+sin(g_fTime*1.3f)*4.0f;
float freqz = 1.0f+sin(g_fTime*1.1f)*4.0f;
float amp = 1.0f+sin(g_fTime*1.4)*30.0f;

float f = sin(N.x*freqx + g_fTime) * sin(N.y*freqy + g_fTime) * sin(N.z*freqz + g_fTime);
Pos.z += N.z * amp * f;
Pos.x += N.x * amp * f;
Pos.y += N.y * amp * f;

Out.Pos = mul(Pos, matWorldViewProj);
Out.N = mul(N, matWorld);

float4 PosWorld = mul(Pos, matWorld);

Out.L = vecLightDir;
Out.V = vecEye – PosWorld;

return Out;
}

This shader calculates an amplitude and a frequency in order to find a smooth value that the vertex can be moved to, based on its vertex.

Using the shader
Nothing new here. We only pass a variable time to our shader trough the g_fTime parameter defined in our shader file.

NOTE:
You might have noticed that I have not used effect.commitChanges(); in this code. If you are rendering many objects using this shader, you should add this code in the pass.Begin() part so the changed will get affected in the current pass, and not in the next pass. This should be done if you set any shader paramteres inside the pass.

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

6 Responses to XNA Shader Programming – Tutorial 5, Deform shader

1. WILEz says:

You cant delete the spam message? Are damned annoying.Compliments for the tutorial.

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