Monday 9 July 2012

Brute Force 2D Shadows…well sort of…

A friend of mine was asking how to do some sort of 2D shadows for a game he is working on. We took a look at some images Catalin Zima put up on an implementation he is working on and I thought, “I can do that!” and I almost did, but in a far less elegant and probably less efficient way than him, also this technique gives the effect that the light is a degree higher than the objects in the scene, but seeing as I did it in about 3 hours and from a couple of screen shots, I don’t think it’s too bad an attempt…

So, am I doing it? Pretty simply really, just passing my shader the obstacle map, this would be a texture holding all the objects in your scene that will block the light, the light’s position, so this technique is only of real use for a single light, and a floor texture. Then in the shader, based on the current text coord I trace a line back to the light source and if it hits an area of the obstacle map that has an alpha > 0 the this pixel MUST be occluded…..and that’s it….

//////////////////////////////////////////////
// //
// Brute force 2D shadows //
// //
// By C.Humphrey //
// xna-uk.net/blogs/randomchaos //
// //
// 14/06/2010 //
//////////////////////////////////////////////
float2 lightPos;
float3 lightColor = float3(1,1,1);
texture map;
sampler mapSampler = sampler_state
{
Texture = (map);
};
texture floor;
sampler floorSampler = sampler_state
{
Texture = (floor);
};
{
float4 Position : POSITION0;
float2 TexCoords: TEXCOORD0;
};
{
float2 texCoord = input.TexCoords;
float4 col = tex2D(mapSampler,texCoord);
float dist = length(lightPos - texCoord);
if(col.a == 0)
{
// Cast a line from pos to light, if it hits somthing, render this one off..
int i = 0;
for(float p = 0;p < 1;p+=.01f)
{
if(tex2D(mapSampler,float2(lerp(lightPos,texCoord,1 / (p+1)))).a != 0)
{
break;
}
}
col = (tex2D(floorSampler,texCoord) * Shadow ) + float4(lightColor * 1-(dist*3),1) * Shadow;
}
return col;
}
technique Technique1
{
pass Pass1
{