ray tracing soft shadows

Started by
6 comments, last by Lotuspec 17 years, 7 months ago
Hi, I implement soft shadows for a simple rectangular area light. The screenshot below shows the soft shadow for casing 256 rays per pixel, but I can still see noise artifacts. For my shadow ray, I pick a random point on the area light as the target. What am I doing wrong? http://img388.imageshack.us/img388/2702/shadowyz0.jpg
-----Quat
Advertisement
Actually, with 256 samples the standard deviation will be about 8 samples, so your getting about as much noise as would be expected (look up the binomial distribution).

The standard deviation goes like sqrt(n), so the relative standard deviation goes like 1/sqrt(n), so in order to get down to an accuracy of 1/256 (for 24-bit colour), you'll need about 16384 samples per pixel. If you want to get around this you're just going to have to use a different method like photon mapping or nonrandom sampling.
Looks about normal... as ZQJ noted, you'll need quite a few more samples to get good noise-free results. In practice it can take anywhere from 2000 to 20000 depending on the geometry and surface textures involved.

There are some hacks that can approximate soft shadowing, but they are a tremendous amount of work and usually are highly inaccurate.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

The fact that you pick a random point on the area light gives you the noise. For any point on the floor, there is a percentage of the area light that is visible. Since you pick a random point on the light as the target, your shadowing is probabilistic, i.e. the percentage area of the light visible becomes the probability that you pick a visible point as the ray cast target. When you cast N rays, the amount of lighting for a particular pixel is Nhit/N. Probability theory says that as the number of rays you cast goes to infinity, Nhit/N will approach the percentage of light visible (which is perfect shadowing). You can't cast an infinite number of rays, so to eliminate noise you cast more and more rays until you get an acceptable result. You could also turn your light into discrete lexels to make the shadowing non-probabilistic, but then the quality of your shadowing depends on the resolution of the lexels.
Just to mention it - there are some interesting adaptive techniques you can use to mitigate sample count if needed. For instance, divide your light source into 16 discrete, roughly equal (in terms of luminance output) parts. For your first 16 shadow samples, test each part. Then, bias your remaining random samples towards boundary regions. For instance, suppose you get the following results, where an X indicates a shadowed sample:

[X] [ ] [ ] [ ]
[ ] [ ] [ ] [ ]
[ ] [ ] [X] [X]
[ ] [X] [X] [X]

Generate the bulk of your samples in the boundary boxes, namely:

[-] [-] [ ] [ ]
[-] [-] [-] [-]
[ ] [-] [-] [-]
[-] [-] [ ] [ ]

Be sure to still fire a few into the other boxes to ensure accuracy. Obviously the finer resolution your bias-grid the less likely you are to end up with inaccurate results. This should give you a reliable 30-40% decrease in needed samples to achieve equivalent levels of noise.

You can also forego the presampling (for instance if your light source is extremely hard to subdivide, as in the case of emissive nontrivial geometry) and simply adapt your random samples towards regions of inflection to get similar results. Which one yields better performance depends largely on the light source geometry and shadowing geometry in your scene.

In extreme cases, you can nest these techniques - e.g. use a high-level discrete sampling gridspace and then re-divide each cell, and so on. This can be beneficial when working with sample counts on the order of 10000 or higher.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

As a simple improvement, you can sample the light many times from each point on the floor and take the mean value for the shadow test. This isn't really radiometrically correct, but it is closer and should eliminate some of the noise.

And, of course, you should also up the rays per pixel as noted.
Thanks for the replies everyone. I changed from purely random sampling to a jittered grid technique, so it is only semi random now. 256 rays per pixel is now giving me good results so far.

I was just surprised I guess. I got good antialiasing with 16 rays per pixel, but for soft shadowing, I apparently need much more.
-----Quat
Using stratified (or lating hypercube) sampling gives a decent improvement but things (usually) get a lot better when using Quasi-random sequences (for example a (scrambled) Halton sequence) as they make it possible to get a good sample distribution w.r.t. the neighbouring pixels.

This topic is closed to new replies.

Advertisement