In the last previous tutorial we explored the depth shadow maps in all it’s aliasing glory.
I showed you ho to fix the steep angle artifacts by using the diffuse term, and the shadow poping by adding a bias to the shadows.
In this lesson we are going to implement something called Percentage Closer Filtering or PCF as it is more commonly called, the name doesn’t exactly reveal what it does.
It is in fact a way to multi sample the shadows and this is pretty simple, so simple that i am not going to supply you with anything other than the new shader file, the rest is exactly the same as tutorial 03a.
1. transform the texture coordinates first two values by a really small amount.
2.make a shadow test against those coordinates.
3. repeat 1 and 2 as many times as needed..
4. take the collective result from the shadow tests and divide it with the number if samples you just did.
Lets demonstrate this with some code.
First we set up some variables + load the other textures besides the shadows.
Since we are also going to do 25 samples we want to eliminate as much as possible from the loop, that is why i added the inverted bias to gl_TexCoord.z instead of the shadow value.
float blur_spread;blur_spread = -0.003;
blur_spread = -0.001;
blur_spread = 0.000;
blur_spread = 0.001;
blur_spread = 0.003;
gl_TexCoord = gl_TexCoord/gl_TexCoord.w;
next do the sampling, note that because a division is more problematic than a add, we pre divided the samples so instead of adding one for each sample we are adding 0.04, this saves us the trouble of having to divide at runtime.
shadow = texture2D(texunit2,gl_TexCoord.xy+vec2(blur_spread[x],blur_spread[y]));if(shadow > gl_TexCoord.z)
Great now all we have to do is include the rest and we are done
norm = normalize(gl_NormalMatrix * norm);
float fresnel =max((norm.z-0.6)*-1.0,0.0);
float diffuse = max(dot(lightVec, norm),0.0);
float specular = max(dot(reflect(lightVec,norm), viewVec), 0.0)*1.7;
shade*=diffuse;gl_FragColor = (base* shade)+(vec4(0.0,0.1,0.3,0.0)*fresnel)+
You can now begin to play around with the numbers, increasing the values in blur_spread will make it a bit more blurry, but then other artifacts show up, these can be fixed by fiddling with the bias parameters, but ultimately PCF is just a hack and won’t work every time.
I originally planned to include a version that changed the blurriness according to the distance from the shadow casting surface, it looked pretty good, unfortunately not good enough in all situations, it was done by getting the distance between the fragment and the shadow map depth value and with this manipulating the values in blur_spread.
It would have worked if it whereat for those meddling kids(read:artifacts).
Test and see if you can do it.