Regular hardware shadow mapping (no filtering)

This is a simple sample of employing the “very regular” hardware shadow mapping, with no filtering at all.
In the shader, I scale the shadow color (shadowWeight) accordingly to the light intensity. All I want is lightweight shadows, so that the brighter the light, the brighter the shadow. It’s for achieving “global illumination” style lighting, but if you prefer dark shadows, it’s easy to adjust the value.
I keep the smooth shading applied too, so that it won’t look too flat. I’ve set the darkest surfaces (facing away from the light source) to have the same level of shadowWeight (not pure black), to keep visual rasionality.

I want it like this :

  • smooth shading original result varies from [-1] to [1] --> range=2
  • I want it varies from [shadowWeight] to [lightIntensity] --> range=lightIntensity-shadowWeight
    so I scaled it this way :
    smoothColor = shadowWeight + (lightIntensity-shadowWeight).5(DOTproduct + 1.0)

The smooth shading is applied also for covering the self-shadowing artifact on the side. It’s easy for dark shadows, but for lightweight shadows, it’s a little complicated.
The result, before and after :

download :
script & shader.
I’ve simplified the shadow offsetting to be done interactively, with some additional stuff.

Some screenshots :


Since the first time I did this correctly, it has kept me playing like a baby with his first toys.
Have funnn !

great work, but i cant get it to work with the provided scene. Could it be that it has to do with my graphics card? (ATI Mobility Radeon X1600 with 256mb ram). I would love to see this running.

I have found out something pretty interesting:
As soon as the shader calculates tex2D(k_Ldepthmap, shadowUV ); the smooth variable content seems to be lost…

Also the k_lightIntensity and the k_lightcolor variable are empty (black when set to o_color) after the above tex2D call…

Not to mention that trying to put the content to another variable first, clears the copy as well…


i have rewritten the shader so it works on my machine. However due to the above limitations it does not consider the light color. Maybe it is interesting to somebody with similar problems.

fixed the disortion mentioned in the following post.



void vshader(float4 vtx_position : POSITION,
             float2 vtx_texcoord0: TEXCOORD0,
             float3 vtx_normal: NORMAL,

             uniform float4 mspos_light,
             uniform float4x4 trans_model_to_clip_of_light,
             uniform float4x4 mat_modelproj,
             uniform float4 k_xOffset,
             uniform float4 k_yOffset,
             uniform float4 k_dOffset,

             out float4 l_position : POSITION,
             out float2 l_texcoord0 : TEXCOORD0,
             out float4 l_texcoord1 : TEXCOORD1,
             out float3 l_texcoord2 : TEXCOORD2,
             out float4 l_smooth)

  float OffsetX = .5 + k_xOffset.x;
  float OffsetY = .5 + k_yOffset.x;
  float OffsetDepth = .5 + k_dOffset.x;

  float4x4 biasMatrix = {
  0.5f,0.0f,0.0f, OffsetX,
  0.0f,0.5f,0.0f, OffsetY,
  0.0f,0.0f,0.5f, OffsetDepth,
  0.0f,0.0f,0.0f, 1.0f};

  // vertex position
  l_position = mul(mat_modelproj, vtx_position);

  // ------preserving smooth shading---------
  // vector from vertex to the light
  float4 lightvec = normalize(mspos_light - vtx_position);
  l_smooth = dot(vtx_normal, lightvec);

  // transformation to the light's clip space
  float4x4 textureMat = mul(biasMatrix, trans_model_to_clip_of_light);

  l_texcoord0 = vtx_texcoord0;
  l_texcoord1 = mul(textureMat, vtx_position);


             //uniform float4 k_lightcolor,
void fshader(float2 l_texcoord0 : TEXCOORD0,
             float4 l_texcoord1 : TEXCOORD1,

             float4 l_smooth,
             uniform sampler2D tex_0 : TEXUNIT0,
             in uniform float4 k_lightIntensity,
             in uniform float4 k_lightcolor,
             uniform sampler2D k_Ldepthmap,
             uniform sampler2D k_cutout,
             out float4 o_color:COLOR)

  float3 l_texcoord2 = / l_texcoord1.w;
  float4 shadow = tex2D(k_Ldepthmap, l_texcoord2 ); // shadows
  float4 light     = tex2Dproj(k_Ldepthmap, l_texcoord1); // lightning
  float4 cutout    = tex2D(k_cutout,l_texcoord2); //*lightContrast;    // // the light texture
  float4 baseColor = tex2D(tex_0, l_texcoord0); // object texture
  float4 lighted = (l_smooth * shadow * baseColor * cutout * 0.5);
  float4 shadowed = baseColor * l_smooth;
  if (l_texcoord2.x>0.0  &&  l_texcoord2.x<1.0  &&  l_texcoord2.y>0.0  &&  l_texcoord2.y<1.0) {
    o_color = lighted * 0.9 + shadowed * 0.1;
  } else {
    o_color = shadowed * 0.1;

One hard fact if you do perspective divide in vtx shader, it causes UV distortion :

Which version of Panda are you using ? I’m still using 1.2.2. Maybe it’s due to version changes ? When running this shader using arb profile, I even couldn’t pass the parameters correctly.
Or, maybe yes it is your GPU limitation. How does it behave with other shaders ?

I have seen this distortions in my code. However its better then nothing :slight_smile:

I havent really understood what i was doing while changing your code, i just worked my way up with trial and error.

Im using panda 1.3.1. All other shaders seem to work fine. Actually the graphics chip is one of the newer mobile ones and should support shaders 2.0 afaik.

I have fixed the disortions in the above code. (at least i think) Other things are still not as well as the original version. However at least i can see some shadows…

Congratulations, this is absolutely awesome! This will help lots of people who wish to implement shadows in their Panda games. I bet It can also be used as a starting point for implementing other shadow map techniques like VSM.

I’ve just updated the shader and the script. It now runs 50%+ faster. However, there are still calculation inefficiencies, if anyone interested to fix it up, post the changes please.

Oops, sorry, thanks to my stupidity, the old shader only runs half speed, now it’s 100% faster.


great work, ynjh_jo.
One thing: the file ‘misc/lilSmiley’ is missing, is that right?

No, it’s not. On Windows, it’s there. I don’t know on Linux.

Hello ynjh_jo,

thanks for the shader. It works really great. I have just two questions. Do you know if you can use two lights on one Model? If so, can you please give me a hint how do arrange it. And the other thing is how it is possible to use your shader with the fog from panda. I tried several possibilities but it is not working till now.

I would be very happy to get an answer from you,
Greets Freakup

sorry, it was terrible week.
download : 2 lights

About the fog, if you use shader, you have to create the fog yourself in the shader. I never do this before.

Hey, ynjh - I’m trying to prepare a new panda distribution, and I’d like to incorporate your shadow code into the sample programs repository. I’d also like to simplify it a little. Would that be okay?

Great job, ynjh_jo. It works well in my Panda3D1.3.2.

so 1.4 is ready 8) 8)
It’s all yours, and I believe it needs a lot of calculation simplification since it’s inefficient, as you said long time ago.