A helping hand for bedroom coders throughout the land.
Brute Force 2D Shadows…well sort of…

Blogs

RandomChaos

Syndication

http://www.youtube.com/v/VGeC5HYN0k0 <p><a href="http://www.youtube.com/v/VGeC5HYN0k0">http://www.youtube.com/v/VGeC5HYN0k0</a></p>

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….

Here is the shader

 

//////////////////////////////////////////////
//                                            //
// 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);   
};



struct VertexShaderOutput
{
    float4 Position : POSITION0;
    float2 TexCoords: TEXCOORD0;
};


float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
    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..
        float Shadow = 1;
        int i = 0;

        for(float p = 0;p < 1;p+=.01f)
        {
            if(tex2D(mapSampler,float2(lerp(lightPos,texCoord,1 / (p+1)))).a != 0)
            {
                Shadow = 0;
                break;
            }
        }

        col = (tex2D(floorSampler,texCoord) * Shadow ) + float4(lightColor * 1-(dist*3),1) * Shadow;
    }
    
    
    return col;
}

technique Technique1
{
    pass Pass1
    {
        PixelShader = compile ps_3_0 PixelShaderFunction();
    }
}

 

Pretty simple stuff eh..


Posted Tue, Jun 29 2010 4:08 PM by Charles Humphrey