HowTo:Use radiosity
Radiosity, also known as global illumination (GI), is one of the two methods POV-ray supports of simulating the inter-reflections of light that occur in the real world.
What radiosity does
We can see objects because light from a light source (such as the sun) is reflected from the surface of the object and picked up by our eyes. However, not all of this light goes into our eyes, but also strikes the other objects around us, likewise, not all of the light coming from an object is directly from a light source. The light we see may have been reflected many times by the surrounding objects. A good example of this is a shadow on a sunny day. The shadow is certainly darker than its surroundings, but will not be pure black because of the reflected light. POV-ray can simulate this in two ways:
- Via the ambient property in the finish block of a texture, which gives the color of the object when no light is shining on it.
- By using radiosity.
When to use it
Radiosity should be used when you want a realistic look of indirect lighting. Indoor scenes frequently use radiosity, but outdoor scenes can greatly benefit from it too. Since black or uniformly dark shadows are very unrealistic and almost never occur in the real world, radiosity can do a lot to make an image look good. Here are some images to help compare:
Scene source code: Simple_arch_demo.pov
Radiosity can also be used to make glowing objects in a scene cast light onto other objects:
(EXAMPLE IMAGES)
Basic Use of Radiosity
To use radiosity, include a radiosity block in the global_settings. If you are unfamiliar with the settings that control the look and performance of POV’s radiosity algorithm, the easiest way to get started is to use the Rad_Settings macro from rad_def.inc. A description of the parameters and how you can tune them is also covered in this tutorial.
Rad_Settings macro
The Rad_Settings macro allows a user to easily use any of the predefined quality settings from below:
- Radiosity_Default
- Radiosity_Debug
- Radiosity_Fast
- Radiosity_Normal
- Radiosity_2Bounce
- Radiosity_Final
- Radiosity_OutdoorLQ
- Radiosity_OutdoorHQ
- Radiosity_OutdoorLight
- Radiosity_IndoorLQ
- Radiosity_IndoorHQ
The macro expects the first parameter to be one of the above quality settings followed by two boolean parameters for normals and medias, respectively.
Example use of Rad_settings macro:
#include “rad_def.inc”
global_settings {
radiosity {
Rad_Settings(Radiosity_Normal,off,off)
}
}
#default {finish{ambient 0}}
That's it right there! We've just applied to our scene radiosity at a medium quality setting that will not take into account normals or media!
Developing a Better Understanding of Radiosity
The macro works well for most scenes and is very easy to use, but it may not always suit our purposes. What if we tried all of the quality settings, but our scene still isn't rendering correctly? We need a good understanding of the radiosity parameters so we can fine-tune the settings to our needs.
Radiosity Parameters
Below is a description of everything that can be in a radiosity block as defined by the documentation:
- pretrace_start
- pretrace_end
- To control the radiosity pre-trace gathering step, use the keywords pretrace_start and pretrace_end within the radiosity{} block. Each of these is followed by a decimal value between 0.0 and 1.0 which specifies the size of the blocks in the mosaic preview as a percentage of the image size. The defaults are 0.08 for pretrace_start and 0.04 for pretrace_end
- pretrace settings can help balance speed vs. quality. Since pretrace helps POVray determine where more radiosity samples are needed, it can help to have a pretrace_start setting around default, but a much smaller than default pretrace_end setting, such as 0.005 for your final trace.
- count
- The integer number of rays that are sent out whenever a new radiosity value has to be calculated is given by count. A value of 35 is the default, the maximum is 1600
- count is probably the main speed/quality parameters. A higher count gives more accurate results, but significantly increases your render times. count needs to be balanced with the error_bound parameter, as smaller error_bound values generally need a higher count.
- nearest_count
- The nearest_count integer value is the minimum number of old ambient values blended together to create a new interpolated value. The total number blended will vary depending on error_bound. All previous values that fit within the specified error_bound will be used in the average. The default is 5, and the maximum is 20.
- Raising nearest_count can significantly reduce or smooth out splotchiness, since more nearby values will be averaged. As always, there is a cooresponding speed penalty, but using higher values like 10 or even 20 for the final trace may help remove artifacts (some artifacts can also be removed by adjusting count also).
- error_bound
- The error_bound float value is one of the two main speed/quality tuning values (the other is count, the number of rays shot). 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.
- The default value of 1.8 is good for a smooth general lighting effect, but may render corners or smaller shadows incorrectly. Using lower values is more accurate, but it will strongly increase the danger of artifacts and therefore require higher count. You can use values even lower than 0.1 but both render time and memory use can become extremely high then.
- recursion_limit
- The recursion_limit is an integer value which determines how many recursion levels are used to calculate the diffuse inter-reflection. The default value is 3, the upper limit is 20
- This represents the number of times light bounces off of objects before reaching your eye. In the real world, this could be a very high number. In POV-ray, higher is not always better! Values between 2 and 4 tend to give very good results for most scenes. Higher values can have a significant speed penalty. It is recommended that you use the lowest value that gets the look you want in your scene. Note that the number of recursions can affect both the brightness and contrast of your indirectly lit objects, which means that test tuning with a significantly different recursion level than what you intend to do the final trace with may have unexpected results.
- 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, controlled by pretrace: 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.5.
- 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 cannot afford to compute this, if we only do one bounce, 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 desaturates the colored light a little to make your scene more visually correct. 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.
- minimum_reuse
- brightness
- The brightness keyword specifies a float value that is the degree to which objects are brightened before being returned upwards to the rest of the system. The default value is 1.0
- Brightness should be balanced with your ambient and diffuse values as well as your light_source intensity. Remember that brightness doesn't refer directly to the overall scene brightness, it refers to the radiosity calculation which affects the overall scene brightness. This distinction is important, because we can use it to change the contrast of some indirectly lit areas.
- adc_bailout
- normal
- Radiosity estimation can be affected by normals. To enable this feature, add normal on to the radiosity{} block. The default is off
- media
- Radiosity estimation can be affected by media. To enable this feature, add media on to the radiosity{} block. The default is off
- save_file
- load_file
- You can save the radiosity data using save_file "file_name" and load the same data later using load_file "file_name". In general, it is not a good idea to save and load radiosity data if scene objects are moving. Even if data are loaded, more samples may be taken during rendering (which produces a better approximation). You can disable samples from being taken during the final rendering phase by specifying always_sample off.
- always_sample
- You can force POV-Ray to only use the data from the pretrace step and not gather any new samples during the final radiosity pass. This may reduce splotchiness. To do this, set always_sample to off (the default value is on). It can also be usefully when reusing previously saved radiosity data.
- max_sample
- Sometimes there can be problems with splotchiness that is caused by objects that are very bright. This can be sometimes avoided by using the max_sample keyword. max_sample takes a float parameter which specifies the brightest that any gathered sample is allowed to be. Any samples brighter than this will have their brightness decreased (without affecting color). Specifying a non-positive value for max_sample will allow any brightness of samples (which is the default).
Tuning Radiosity
Tuning radiosity for your scene is the longest and arguably the most important part of the process. While we can often apply radiosity settings that worked well in another scene and have good results, the different lighting conditions and geometry means that the perfect settings for your scene will not be found in any guide. Fear not! There are ways to find the right settings for your scene:
Step 1: Prepare Your Source
When tuning radiosity, it is very convenient to have variables and conditional blocks of code that allow you to easily turn off and on light sources, adjust some or all of your textures' ambient values at once, etc. Keep this in mind as you work on your scene.
Step 2: Complete the Scene
Since radiosity is calculated using all of the objects in a scene, it is best to finish placing everything first. You want the lowest (i.e. fastest) quality settings you can possibly use for your scene, so try to have most (if not all) objects in their final locations.
If your scene is very complex and contains a lot of objects, try to place the ones that you think the indirect lighting will really be affected by - what is casting the shadow? What objects will be in shadow?
Other speed or memory saving techniques like using lower polygon-count meshes during tuning might also be a good idea. The bottom line is that the fewer changes to your objects in between the tuning phase and the final trace, the better.
Step 3: Decide What Will Be Casting the Light
When working with radiosity, any object with a non-zero ambient value casts light. This behavior allows all of the light in your scene to be cast using objects (no light_source required).
I typically use a light_source for outdoor scenes, and objects with a high ambient for indoor scenes. This can work very well for artificial light sources; for instance, if you wanted to represent a fluorescent light with a high ambient cylinder, then you wouldn't have to worry about the gaps in between light sources in an area light.
This decision doesn't need to be set in stone. In many scenes you can use either one, or even some combination of both. If you are new to radiosity, I recommend using scene objects to cast light for indoor portions of your scene, and a single light_source (may be area light also) for the outdoor portions.
If you are doing a scene with a cloud-covered sky, you could even use your sky_sphere as the scene light source to get the soft, diffuse, directionless sort of light you would have on an overcast day.
Step 4: Set the ambient Values for Other Objects
Objects that are not intended to be luminous should have a very low ambient. Some people let all of their objects have a small amount of ambient and adjust the radiosity brightness accordingly. I recommend starting with zero because it gives maximum contrast for the indirectly lit areas. We can add more later if we want to reduce the contrast.
Step 5: Find Your Error Bound
As mentioned above, lower error_bound values produce more accurate lighting, but require a higher count, more memoery, and significantly increased render times. Therefore, we want to find the lowest value that will work for our scene. The scene being used for this example can be found here: btuning_00.pov This is the radiosity block we will use in the scene to determine an appropriate error bound:
#local p_start = 64/image_width;
#local p_end_tune = 8/image_width;
#local p_end_final = 4/image_width;
radiosity
{
pretrace_start p_start // Use a pretrace_end value close to what you
pretrace_end p_end_tune // intend to use for your final trace
count 1 // Note the very low count!
nearest_count 10 // 10 will be ok for now
error_bound 1.0 // Start with 1.0
recursion_limit 3 // Recursion should be near what you want it to be
// If you aren't sure, start with 3 or 4
}
This will produce an image with very low quality radiosity and lots of errors... which is exactly what we need! We need to see the size of the smaller shadows in comparison to the area averaged in our radiosity samples. What we are looking for is where the shadows are completely missing.
Note the area circled in red. There is light "shining through" at the base of the object because the error_bound is too large for this scene. We drop it to 0.5 and render it again.
It seems like most of the shadows are now showing up, but just be sure we aren't missing any, we'll try 0.25 and see.
A side by side comparison shows that we picked up some more shadows in the most distant part of the scene. Anytime you pick up shadows, it is generally a good idea to try the image again, with a lower error bound.
The error_bound of 0.125 added more details to the shadows we saw before, and a test render at 0.0625 doesn't seem to pick up any more details. This allows us to establish a tentative range for our error_bound: no greater than 0.25 due to errors, and no less than 0.125 due to diminishing returns.
We could continue the bracketing method above, but because the numeric difference between 0.25 and 0.125 is small, we'll use 0.1875, the mean average of our upper and lower range. If the ranges we'd found had a greater differences, then it would be preferable to test and bracket again to keep the range narrow.
That's it, we now have an error_bound value that should work with our final trace!
Step 6: Determining an Appropriate Value for count
The count must be balanced with the error_bound parameter. A higher error_bound can produce very smooth results with a low count. Because our error_bound is to be 0.1875, we will need a count much higher than the default. To figure out an appropriate count value, we need to go back to one of our previous, too large settings from bracketing. We want to see what count will produce smooth results for a given error_bound:
#local p_start = 64/image_width;
#local p_end_tune = 8/image_width;
#local p_end_final = 4/image_width;
radiosity
{
pretrace_start p_start // Use a pretrace_end value close to what you
pretrace_end p_end_tune // intend to use for your final trace
count 25 // try 25 or so
nearest_count 10 // 10 will be ok for now
error_bound 0.375 // since 0.5 was too large, we use 0.375,
// halfway between 0.25 and 0.5
recursion_limit 3 // Recursion should be near what you want it to be
// If you aren't sure, start with 3 or 4
}
Remember, we want to see what produces smooth blending of the shadows, we aren't worried about errors or shadows not showing up right now. A count of 25 and even 50 are too blocky, but 75 seems to blend smoothly for this scene. Experimentation has shown me that count and error_bound can be roughly related once you find values that result in smooth shadows, and we can use this relation in our scene:
#local smooth_eb = 0.50;
#local smooth_count = 75;
#local final_eb = 0.1875;
#local final_count = smooth_count * smooth_eb * smooth_eb / (final_eb * final_eb);
radiosity
{
pretrace_start p_start // Use a pretrace_end value close to what you
pretrace_end p_end_tune // intend to use for your final trace
count final_count // as calculated above
nearest_count 10 // 10 will be ok for now
error_bound final_eb // from what we determined before, defined above
// halfway between 0.25 and 0.5
recursion_limit 3 // Recursion should be near what you want it to be
// If you aren't sure, start with 3 or 4
}
We now have a count that will be correct for any error_bound we specify. At this point, if we render the scene, we should have decent looking results.
Step 7: Correcting for Corners and Colors
Pitfalls and Work-arounds
Artifacts
Sometimes radiosity can cause artifacts, one of the most common causes of artifacts is infinite radiosity rays. A good rule is to place any radiosity scene inside a large inverse sphere to avoid any ray colliding with the background or sky_sphere. Another potential cause of artifacts is coincident surfaces, sometimes a radiosity ray leaks through the corners of a box or between CSG seams, one work-around seems to be using a round box with a small radius instead of a box. Non-zero ambient values in textures emit light when radiosity is on. This may be intended, but it makes textures look wrong in test renders without radiosity. Using declared variables to adjust the ambient and diffuse values or turn on/off lights and/or radiosity is recommended
Partial Output
Partial image output will affect radiosity! Partial image output can be a good way of splitting up slow renders across different machines; unfortunately, the radiosity calculations will be adversely affected. If you render a scene with radiosity with full image output, then do a series of re-renders of the same scene using partial output and stitch the pieces together, there will be a visible difference in the two images. A possible workaround is to let a single machine calculate the radiosity on a lower resolution render without anti-aliasing, and use the save_file command to store the radiosity data. When the final version is run, ensure that the radiosity data is available to all machines or processes that need it, set always_sample to off, and both pretrace_start and pretrace_end to 1. This ensures that no radiosity calculations are performed and only the loaded data is used.
Using radiosity with sky_sphere
The sky_sphere is always the exact color you specify as it isn't subject to lighting calculations, therefore it can be thought of as having a finish of ambient 1 diffuse 0. Since radiosity is affected by any luminous object in the scene, the sky will be a light source in your scene.
Notes
- Radiosity is slow and requires lots of calculations. Using it requires a lot of patience, but the results are very rewarding.
- Radiosity usage will vary from scene to scene and taste of the artist using it.
- Radiosity isn't that haaaaaaard...