Managed to get cube shadow mapping working today. I'm not completely happy with the result but it was certainly easy enough to set up in the end, once I figured my way around the inevitable issues and artifacts. I'm using a 1024x1024 cube map in the screenshot above, but it looks kind of acceptable with a 512x512, even without PCF, although I do intend to tackle that eventually.
But now I want to have multiple lights supported. I can't imagine being able to hold a coherent level together if only one light at a time can cast shadows.
I've been reading around the various approaches to this. The result I'm looking for is for a shadowed pixel to not be blended multiple times. I'd rather all the shadowed pixels are a constant darkness.
So what I think I'm going to try is first render the scene to the backbuffer with only ambient lighting as if every pixel was shadowed, then for each light source:
- Generate the cube map with the distances from the light source to pixel
- Do an additive lighting pass over the backbuffer, but skip pixels that are in shadow
Seems to be bewilderingly fast to generate the six faces of the cube map, so I think I can manage to render a few of these per frame. Three light sources should be sufficient to be able to link different rooms with different main lights together, then decorative, non-shadowing lights can be added in a single pass.
That's the theory anyway. Will see how it works out.
[EDIT Slightly later...]
Just wanted to update here as I've just added PCF to this, and the results are remarkably good for a simple effort.
Even right up close, the quality is far better than I expected:
I'm just doing a 3x3 sample around the original vector, using an arbitrary offset in the pixel shader:
#define am 0.1ffloat3 filter[] = { { -am, am, 0 }, { 0, am, 0 }, { am, am, 0 }, { -am, 0, 0 }, { 0, 0, 0 }, { am, 0, 0 }, { -am, -am, 0 }, { 0, -am, 0 }, { am, -am, 0 } };float shadowFac(float3 tolight, float3 normal){ float shadow = 0.0f; if(dot(tolight, normal) < 0) { for(int i = 0; i < 9; ++i) { float sampled = texCUBE(ds, tolight + filter).r; float actual = (length(tolight) - 0.5f) / 200; if(sampled < actual) shadow += 1.0f / 9.0f; } } return shadow;}
I guess the value of am would have to be changed depending on the resolution of the cube map, but I'm pretty pleased with the effect there.Just hanging out around a camp-fire
Thanks for stopping by.
[EDIT]
In response to IYP's comment below, I thought I should post another image showing how the PCF looks when the shadows are parallel to the world axes, as I think the lucky diagonal screenshot is giving a misleading impression of how good the PCF is here:
I think this can be improved by using a random sampling kernel, but this can wait until I have multiple light sources working.
can you please share some more implementation details I don't seem to do any thing even a little close to your PCF implementation.