Previous page Next page

Radiosity

Important notice: The radiosity features in POV-Ray are somewhat experimental. There is a high probability that the design and implementation of these features will be changed in future versions. We cannot guarantee that scenes using these features in this version will render identically in future releases or that full backwards compatibility of language syntax can be maintained.

Radiosity is an extra calculation that more realistically computes the diffuse interreflection of light. This diffuse interreflection can be seen if you place a white chair in a room full of blue carpet, blue walls and blue curtains. The chair will pick up a blue tint from light reflecting off of other parts of the room. Also notice that the shadowed areas of your surroundings are not totally dark even if no light source shines directly on the surface. Diffuse light reflecting off of other objects fills in the shadows. Typically ray-tracing uses a trick called ambient light to simulate such effects but it is not very accurate.

Radiosity is more accurate than simplistic ambient light but it takes much longer to compute. For this reason, POV-Ray does not use radiosity by default. Radiosity is turned on using the Radiosity INI file option or the +QR command line switch.

The following sections describes how radiosity works, how to control it with various global settings and tips on trading quality vs. speed.

How Radiosity Works

The problem of ray-tracing is to figure out what the light level is at each point that you can see in a scene. Traditionally, in ray tracing, this is broken into the sum of these components:

- Diffuse, the effect that makes the side of things facing the light brighter;

- Specular, the effect that makes shiny things have dings or sparkles on them;

- Reflection, the effect that mirrors give; and

- Ambient, the general all-over light level that any scene has, which keeps things in shadow from being pure black.

POV's radiosity system, based on a method by Greg Ward, provides a way to replace the last term - the constant ambient light value - with a light level which is based on what surfaces are nearby and how bright in turn they are.

The first thing you might notice about this definition is that it is circular: the light of everything is dependent on everything else and vice versa. This is true in real life but in the world of ray-tracing, we can make an approximation. The approximation that is used is: the objects you are looking at have their ambient values calculated for you by checking the other objects nearby. When those objects are checked during this process, however, a traditional constant ambient term is used.

How does POV-Ray calculate the ambient term for each point? By sending out more rays, in many different directions, and averaging the results. A typical point might use 200 or more rays to calculate its ambient light level correctly.

Now this sounds like it would make the ray-tracer 200 times slower. This is true, except that the software takes advantage of the fact that ambient light levels change quite slowly (remember, shadows are calculated separately, so sharp shadow edges are not a problem). Therefore, these extra rays are sent out only once in a while (about 1 time in 50), then these calculated values are saved and reused for nearby pixels in the image when possible.

This process of saving and reusing values is what causes the need for a variety of tuning parameters, so you can get the scene to look just the way you want.

Adjusting Radiosity

As described earlier, radiosity is turned on by using the Radiosity INI file option or the +QR command line switch. However radiosity has many parameters that are specified in a radiosity statement inside a global_settings statement as follows:

global_settings { radiosity { [RADIOSITY_ITEMS...] }}
RADIOSITY_ITEMS:
brightness Float | count Integer | distance_maximum Float |
error_bound Float | gray_threshold Float | low_error_factor Float |
minimum_reuse Float | nearest_count Integer | recursion_limit Integer

Each item is optional and may appear in and order. If an item is specified more than once the last setting overrides previous values. Details on each item is given in the following sections.

brightness

This brightness keyword specifies a float value that is the degree to which ambient values are brightened before being returned upwards to the rest of the system. If an object is red rgb<1,0 0>, with an ambient value of 0.3, in normal situations a red component of 0.3 will be added in. With radiosity on, assume it was surrounded by an object of gray color rgb<0.6,0.6,0.6>. The average color returned by the gathering process will be the same. This will be multiplied by the texture's ambient weight value of 0.3, returning rgb<0.18,0.18,0.18>. This is much darker than the 0.3 which would be added in normally. Therefore, all returned values are brightened by the inverse of the average of the calculated values, so the average ambient added in does not change. Some will be higher than specified (higher than 0.3 in this example) and some will be lower but the overall scene brightness will be unchanged. The default value is 3.3.

count

The integer number of rays that are sent out whenever a new radiosity value has to be calculated is given by count. Values of 100 to 150 make most scenes look good. Higher values might be needed for scenes with high contrast between light levels or small patches of light causing the illumination. This would be used only for a final rendering on an image because it is very compute intensive. Since most scenes calculate the ambient value at 1% to 2% of pixels, as a rough estimate, your rendering will take 1% to 2% of this number times as long. If you set it to 300 your rendering might take 3 to 6 times as long to complete (1% to 2% times 300).

When this value is too low, the light level will tend to look a little bit blotchy, as if the surfaces you're looking at were slightly warped. If this is not important to your scene (as in the case that you have a bump map or if you have a strong texture) then by all means use a lower number. The default value is 100.

distance_maximum

The distance_maximum float value is the only tuning value that depends upon the size of the objects in the scene. This one must be set for scenes to render properly... the rest can be ignored for a first try. It is difficult to describe the meaning simply but it sets the distance in model units from a sample at which the error is guaranteed to hit 100% (radiosity_error_bound >=1): no samples are reused at a distance larger than this from their original calculation point.

Imagine an apple at the left edge of a table. The goal is to make sure that samples on the surface of the table at the right are not used too close to the apple and definitely not underneath the apple. If you had enough rays there wouldn't be a problem since one of them would be guaranteed to hit the apple and set the reuse radius properly for you. In practice, you must limit this.

We use this technique: find the object in your scene which might have the following problem: a small object on a larger flatter surface that you want good ambient light near. Now, how far from this would you have to get to be sure that one of your rays had a good chance of hitting it? In the apple-on-the-table example, assuming I used one POV-Ray unit as one inch, I might use 30 inches. A theoretically sound way (when you are running lots of rays) is the distance at which this object's top is 5 degrees above the horizon of the sample point you are considering. This corresponds to about 11 times the height of the object. So, for a 3-inch apple, 33 inches makes some sense. For good behavior under and around a 1/3 inch pea, use 3 inches etc. Another VERY rough estimate is one third the distance from your eye position to the point you are looking at. The reasoning is that you are probably no more than 90 inches from the apple on the table, if you care about the shading underneath it. The default value is 0.

error_bound

The error_bound float value is one of the two main speed/quality tuning values (the other is of course the number of rays shot). In an ideal world, this would be the only value needed. It is intended to mean the fraction of error tolerated. For example, if it were set to 1 the algorithm would not calculate a new value until the error on the last one was estimated at as high as 100%. Ignoring the error introduced by rotation for the moment, on flat surfaces this is equal to the fraction of the reuse distance, which in turn is the distance to the closest item hit. If you have an old sample on the floor 10 inches from a wall, an error bound of 0.5 will get you a new sample at a distance of about 5 inches from the wall. 0.5 is a little rough and ready, 0.33 is good for final renderings. Values much lower than 0.3 take forever. The default value is 0.4.

gray_threshold

Diffusely interreflected light is a function of the objects around the point in question. Since this is recursively defined to millions of levels of recursion, in any real life scene, every point is illuminated at least in part by every other part of the scene. Since we can't afford to compute this, we only do one bounce and the calculated ambient light is very strongly affected by the colors of the objects near it. This is known as color bleed and it really happens but not as much as this calculation method would have you believe. The gray_threshold float value grays it down a little, to make your scene more believable. A value of .6 means to calculate the ambient value as 60% of the equivalent gray value calculated, plus 40% of the actual value calculated. At 0%, this feature does nothing. At 100%, you always get white/gray ambient light, with no hue. Note that this does not change the lightness/darkness, only the strength of hue/grayness (in HLS terms, it changes S only). The default value is 0.5

low_error_factor

If you calculate just enough samples, but no more, you will get an image which has slightly blotchy lighting. What you want is just a few extra interspersed, so that the blending will be nice and smooth. The solution to this is the mosaic preview: it goes over the image one or more times beforehand, calculating radiosity values. To ensure that you get a few extra, the radiosity algorithm lowers the error bound during the pre-final passes, then sets it back just before the final pass. The low_error_factor is a float tuning value which sets the amount that the error bound is dropped during the preliminary image passes. If your low error factor is 0.8 and your error bound is set to 0.4 it will really use an error bound of 0.32 during the first passes and 0.4 on the final pass. The default value is 0.8.

minimum_reuse

The minimum effective radius ratio is set by minimum_reuse float value. This is the fraction of the screen width which sets the minimum radius of reuse for each sample point (actually, it is the fraction of the distance from the eye but the two are roughly equal). For example, if the value is 0.02 the radius of maximum reuse for every sample is set to whatever ground distance corresponds to 2% of the width of the screen. Imagine you sent a ray off to the horizon and it hits the ground at a distance of 100 miles from your eyepoint. The reuse distance for that sample will be set to 2 miles. At a resolution of 300*400 this will correspond to (very roughly) 8 pixels. The theory is that you don't want to calculate values for every pixel into every crevice everywhere in the scene, it will take too long. This sets a minimum bound for the reuse. If this value is too low, (which it should be in theory) rendering gets slow, and inside corners can get a little grainy. If it is set too high, you don't get the natural darkening of illumination near inside edges, since it reuses. At values higher than 2% you start getting more just plain errors, like reusing the illumination of the open table underneath the apple. Remember that this is a unitless ratio. The default value is 0.015.

nearest_count

The nearest_count integer value is the maximum number of old ambient values blended together to create a new interpolated value. It will always be the n geometrically closest reusable points that get used. If you go lower than 4, things can get pretty patchy. This can be good for debugging, though. Must be no more than 10, since that is the size of the array allocated. The default value is 6.

recursion_limit

The recursion_limit is an integer value which determines how many recursion levels are used to calculate the diffuse inter-reflection. Valid values are one and two. The default value is 1.

Tips on Radiosity

If you want to see where your values are being calculated set radiosity count down to about 20, set radiosity nearest_count to 1 and set gray_threshold to 0. This will make everything maximally patchy, so you'll be able to see the borders between patches. There will have been a radiosity calculation at the center of most patches. As a bonus, this is quick to run. You can then change the error_bound up and down to see how it changes things. Likewise modify minimum_reuse and distance_maximum.

One way to get extra smooth results: crank up the sample count (we've gone as high as 1300) and drop the low_error_factor to something small like 0.6. Bump up the nearest_count to 7 or 8. This will get better values, and more of them, then interpolate among more of them on the last pass. This is not for people with a lack of patience since it is like a squared function. If your blotchiness is only in certain corners or near certain objects try tuning the error bound instead. Never drop it by more than a little at a time, since the run time will get very long.

If your scene looks good but right near some objects you get spots of the right (usually darker) color showing on a flat surface of the wrong color (same as far away from the object), then try dropping distance_maximum. If that still doesn't work well increase your ray count by 100 and drop the error bound just a bit. If you still have problems, drop nearest_count to about 4.

Previous page Next page