ray tracing - soft shadows

Started by
11 comments, last by timw 18 years, 6 months ago
Just me again with yet another annoying distribution question. Thanks to the simple advice of the friendly community here, I have been successful in my implementation of glossy reflections and my friend with the depth of field effect. Now I wish to implement soft shadowing, my current shadows are basic and thus hard! This is some information I already know: * Represent light source as area rather than point. * For each shadow calculation, send multiple rays aimed at different points on the light. * Points near the border of the shadow region will be partially lit. I currently have point source light support – which produces hard shadows due to the light being a humble point with no (surface) area. Can someone guide me through the process of allowing my point lights to have area? How do I represent my point light as an area light? And the whole soft shadowing algorithm for a simple ray tracer??? PS: Timw, Yes, ray tracer is simple and unaccelerated. This is to understand the basics from the ground up, before I hand over spec’s and other details to the hardware dept. of our university. Thanks in advance to all. And thanks to timw.
Advertisement
Point lights in real world also cause hard shadows. If you want to get rid of aliasing in the hard shadows for point lights, you have to use some kind of Antialiasing.

Now, if you want real soft shadows, then you must have a lightsource with an area. So you can model your lightsource as a square or sphere. To get the direct contribution of a light at any point, you need to see how much of the light is visible from that point. This can be approximated by the number of rays that intersect the light first, in the set of the sample shadow rays all of which intersect the light.
I haven't looked over it due to my general disinterest in raytracing, but this paper from SIGGRAPH 2005 might help out: http://graphics.cs.lth.se/research/papers/soft2005/

Edit: Whoops, I guess checking the HTML is a good idea

[Edited by - Cypher19 on October 23, 2005 10:10:51 AM]
Well, getting fast results is not so complex. Assuming you already support point lights, an easy way is to model your area light as n point lights on the same plane, each with a energy power of p/n (where p is the total power you want the light to have).
For each point you want to lit:
-generate the ray with origin in hit_point and direction light_sample-hit_point.
-Apply your preferred lighting equation.
-sum all the samples contribute. So a point that can see all the samples on the light surface is fully lit. Points than are completed covered by other objects and cannot see any samples are shadowed (shadow) and point that can see only some samples are partially lit (penumbra).

EDIT: just to be clear: hit_point is the point you want to light (i.e. intersection point between geometry and primary rays). light_sample is a sample of the light (intuitive, isn't it?): a square light can be subdivided into 4, 8, or 16 samples (actually you can choose the number of them). Only remember that each sample has p/num_samples power.
cignox1, thankyou for your reply. This the method you describe a distribution ray tracing alorithm, or is it the one which produces those visible and discrete bands?

"is to model your area light as n point lights on the same plane" - How do I do this? I only have a point remember? How should I turn my point into a plane?
you have support for spheres in your engine? if so, create spherical lights. remember, lightbulbs are (nearly) spherical as well, so it'll be great to have those anyways.

the trick is to not look at your lightsources as anything special. ANY geometrical object can emit light, so just use that knowledge: use models. your engine can handle spheres? use spheres as lights. your engine can handle planes? use planes as lights (will be quite big, though.. :D). your engine can handle polygons? great, use them (if you develop something with model support, your lights will gonna be polygonal one day anyways..).

just use a flag per mesh, wether it's a light, or not. and moving from a pointlight to a spherical light is a quite simple thing: add a radius to it.

and then yes, generate some random points on the sphere, trace towards them, and see if something is inbetween. and shade and shadow aaccordingly.
If that's not the help you're after then you're going to have to explain the problem better than what you have. - joanusdmentia

My Page davepermen.net | My Music on Bandcamp and on Soundcloud

there are a couple ways to do this. they're basically all the same idea, but differ in their physical interpretation of what the light geometry is.

1) area planer lights.
2) area spherical lights.

the planer light is a bit easier. it just depends on what you want. if you want the light to act like a point light with soft shadows, ie(a spherical light) or if you want the light to act like planer light, like the stuff in the cornell box.

I'm gonna assume you don't want to change your lighting model, that is to say, you wanna keep all the lighting equations as if everything is a point light. the general formula for the contribution of light from a diffuse planer surface is actully quite horrifying.

so I'm assuming you want just soft shadows. so to do this you need a way to see what percentage of the light is visible from a particular point. Say I pick 100 random positions on it(the plane light) and I trace the rays from the surface to the random point on the light and find out that only 20 of them hit the light before they hit anything else. that tells me that about 20/100 or 1/5th of the light is visible from that point. this is the basic concept. Now, for every ray that hits the light, you treat that point(the random point on the light) as a point light with 1/100th the power of the original light.

you can sample the light in 3 ways.

1) pick random positions on the plane
2) divide the plane to say 10x10 squares and pick the center of each square to send rays
3) use jittered sampling (1 + 2)

of the 3 only choice (2) will produce banding effects.

I strongly suggest using (3). it's so much better. stratification is necessary for fast convergance. If you care, (3) converges as 1/N, (1) converges as 1/sqrt(N). it's the difference between night and day.

now consider the spherical light.

If you're shading a point on a surface, from the points point of view(lol) the light looks like a circle. from any point of view, a spherical light looks like a circle with normal pointing to the surface point. that is to say:

from a point X.
the sphere centered at P, with radius r can be replaced by a circle centerd at P with radius r and normal X-P. does it make sense?

so instead of picking random points on a sphere, we only need to pick random points on a circle. sampling a circle is a little bit harder then sampling a plane. the way I do it is sample a circle centered at 0,0,0 with radius 1 and normal 0,0,1. this gives you a point (x,y,0) that you can transform with the appropriate matrix. or simply use some vector math. The point is, it's a little harder then sampling a plane light.

now, simply send n sample rays to the circle and determin visibility

VIS = #samples that hit sphere/n

and if the surface is reasonably far from the spherical light, the speherical light acts just like a point light. so simply shade it like one, just multiply the point lights contribution by VIS. note this is slightly different then the area light, in the area light, we considered each sample ray as a point light. that is to say, we modeled a plane light with n point lights, each point light has 1/nth of the total power of the light. here we consider the spherical light simply as one point light, we just multiply the point light's contribution by VIS. also, instead of sampling a circle, you could also sample a square if you think it's easier. just make sure the area of the square is approximitly the same as the area of the disk you're trying to approximate. you won't notice much difference in the shadow. what matters for shadows is not the so much the shape of the light as the size(unless of course the shape is something crazy)

Tim

[Edited by - timw on October 22, 2005 11:41:25 PM]
Before you posted, I did do this to create soft shadows:

void SoftLight::GetIllumination(vector3f p, vector3f& d, vector3f& c, float& distance_to_light) const{   vector3f random(((rand() / (float) RAND_MAX) - 0.5f), ((rand() / (float) RAND_MAX) - 0.5f), ((rand() / (float) RAND_MAX) - 0.5f));   d = (position + random) - p;/* Grab the length before the direction is normalized. */   distance_to_light = d.Length();    d.Normalize();   float attenuation = 1.0f / (attenuation_1 + attenuation_2 * distance_to_light + attenuation_3 * distance_to_light * distance_to_light);   if (attenuation < 0.0f) attenuation = 0.0f;   c = color * attenuation;   return;}


It works, but is this the best method? I will reread your posting!
I'm not sure exactly what you're doing. it doesnt' look correct. this thing may produce some sort of soft shadow, but it's not a plane light. it's more of a sphere light, but it's not a sphere either. it's biased, your randomness isn't constrained in any reasonable way as far as I can tell. it's not even a uniformly random direction. I can see how this could kinda give you soft shadows, if you're happy with the results then I guess it's cool. If you're gonna do this, may I suggest one simple modification?

pick random uniformly, remove the directional bias by doing this.

do{
X = rand[-1,1]
Y = rand[-1,1]
Z = rand[-1,1]

}while(X*X + Y*Y + Z*Z > 1)

random = (X, Y, Z)

random is now a uniform random direction, ie every direction has an equal chance of being picked. it basically picks random points from within the unit sphere. what you were doing before was picking random points within a unit cube, if you look at a cube the perpendicular distance from the center to a face is .5 units but the distance from the center to a corner is sqrt(.5^2 + .5^2) thus, it's based to the corners. more random vectors will be near the corners then near other directions. sampling within the unit sphere removes that bias. this technique for picking random directions is called rejection sampling, simple but inefficent. in any case, it's not the correct way to do it anyway, but I think it'll give you slightly better results if you want to stick with this implimentation.

Tim
come to think of it, the more I think about your solution the more reasonable I think it is. one thing tho, I'm sure using the above random procedure would produce better results, you might notice the bias when shading large shadows.
I have one more suggestion, since your're trying to simulate a spherical light, spherical lights behave like a point light centered at the center of the sphere. so when you calculate the distance for attenuation, just use the center of the sphere, and not the random point. I'm not sure how much it matters. One thing is certian though, it will take longer to converge if the attenuation is different for every sample. so id suggest it on that fact alone.

This topic is closed to new replies.

Advertisement