Imitating the Canvas Engine (12): Applying the Shadow Fill Effect

Previous Post:
Imitating the Canvas Engine (11): Directional and Gaussian Blur - Memories of Melon Pan

We're down to the last and final step!

Right now, our rendered scene has a canvas texture on it, it's framed like it was drawn in a sketchbook, and we've drawn the edges on it.

We've got a shadow map for this scene.

And we've got a shadow fill texture. We're only using the blue channel in particular texture we're using.

If we take the color in the shadow map for the intensity of the shadows at that pixel, we can blend the shadow fill texture into the rendered scene and get our shadowing done that way.

The last thing we have to remember is that we're rotating the shadow fill texture so that the streaks we get line up with the direction of the light. We can pass in the 2D rotation matrix we figured out earlier when we read the color of the shadow fill texture to blend into the scene.

float4 ShadowFillColor = tex2D(ShadowFillSampler, mul(TexCoord, SceneLightRotation));


For the variables:

  • ShadowFillSampler, an HLSL sampler that reads from the shadow fill texture
  • TexCoord, the texture coordinates of the input pixel
  • SceneLightRotation, a 2D rotation matrix

This gets us the intensity of the shadow at our pixel, but we're actually going to something like cel shading. If the shadow amount is below some threshold, don't blend the shadow fill texture in at all. If it's between 0.125 and 0.25 (for example), then lightly shade the pixel. You get the picture.

Once again, I just fiddled around with numbers until I got something I thought looked good. I'm not doing any gradient smoothing, though.

  • ShadowAmount [0.0, 0.125] → ShadowFillIntensity 0.0
  • ShadowAmount [0.125, 0.25] → ShadowFillIntensity 0.125
  • ShadowAmount [0.25, 0.375] → ShadowFillIntensity 0.33
  • ShadowAmount [0.375, 1.0] → ShadowFillIntensity 0.5

From there, we can calculate the shadow mask we use to blend with the rendered scene.

float ShadowColor = 1 - (ShadowFillIntensity * ShadowFillColor.b);

That gives us all the shadows we have in the scene. The last thing we have to do is add them to the scene.

return SceneColor * ShadowColor;

And after an enormous amount of text, we're finally done!

Next Post:
Imitating the Canvas Engine (13): Conclusion - Memories of Melon Pan