Diatribe: You should be trying to figure this out yourself - I was myself in the exact same position as you a year ago; and now I am doing soft-edged water etc. without copying code because I figured it out myself. I will try to explain the thought process you should be using - but you won't get one complete snippet. Furthermore, he uses a
Texture1D - which we don't have in XNA; so my answer will vary slightly.
To start you should first search on how to use
Effects, and how to use custom ones with a
SpriteBatch (if that is what you are using).
Firstly, if you look at the video you will notice that the waves are moving outwards from the center - in order for a shader to perform any form of animation over time you need to provide it with knowledge of time. Therefore provide it as a uniform parameter (this means that it will retain its value over an entire frame):
uniform float time; // Set this to the current total elapsed game time each frame.
Now we would like it to move outwards from the center; that means we need to define 'center':
uniform float2 center; // The center of the ship in local texture coordinates (most probably 0.5f, 0.5f)
Note that this center is local to the texture - in other words don't pass the coordinate in in terms of screen space. Also, remember that you perform Texture lookups on the GPU using 0 -> 1 (not 0 ->
size of texture in pixels). In most cases you could probably just set center to
Finally we need to access the texture - to read colors from a texture you use a sampler - this will contain the graphic for the ship.
sampler BaseTexture : register(s0); // According to how sprite batch works.
And one for the shield - which we will repeat over the entire area of the ship (you will need to see this).
sampler ShieldTexture : register(s1);
A pixel shader automatically 'loops' over every pixel (it's not actually what happens, but you can see it this way), so we will get some information from the GPU.
float4 ShieldPixelShader(float2 inTex : TEXCOORD0) : COLOR
/* ... */
What this means is that we have a function that takes the current texture coordinate and returns the resulting color. The GPU will fill in the value of inTex for you (because of the TEXCOORD0 semantic).
The first thing we need to do is figure out how far the current pixel is from the center of the ship:
float dist = length(inTex - center);
Now we need to figure out how opaque to make the second texture based on that distance and the time. The distance will be in the range 0->1 (because of how texture coordinates work); and we want the 'bright spot' to move from 0->1, reset and repeat - this sounds mightily like a modular problem. The
% returns the remainder of division - and it conveniently restricts a value to a range (in a repeating fashion) - so for example
i % 5 will do this:
0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, ...
What's also great is that it also works on real numbers (things like 0.5) - so if we just take
time % 1 it will get us our repeating expanding circle:
float targetDist = time % 1;
Now all we do is figure out how close we are to targetDist, so we can see how opaque we want to make the second texture:
float distDiff = 1 - min(0, abs(targetDist - dist) - 0.5);
That subtraction and
min is so that we can contract the size of the gradient (remember it occurs in a small space around the current desired distance, not all the way from
Now we can finally get to the bit where we mix the two textures, remember that I said we are going to repeat the shield texture. Another nifty the thing the GPU can do for us is wrap textures, that is, if you ask for a pixel at 1.1 it will actually grab it from 0.1 (if you think about it you will see that they are also just using
%/mod for this). So in order to repeat a texture we can just multiply it by the number of times we want it repeated:
float2 shieldCoord = inTex * 20; // Repeat it 20 times.
Finally we grab the colors for each texture:
float4 shipColor = tex2D(BaseTexture, inTex);
float4 shieldColor = tex2D(ShieldTexture, shieldCoord);
Finally we perform the simplistic alpha mix:
float4 finalColor = (shipColor * (1 - distDiff)) + (shieldColor * distDiff);
finalColor.a = shipColor.a; // Use the ships alpha (transparency).
And return it to the graphics card:
Side note: You will need to turn off premultiplied alpha blending for this shader to work - search around to find out how to do this.