|
Contents
OverviewMy latest fun addition to POV is the photon map. The basic goal of this implementation of the photon map is to render true reflective and refractive caustics. The photon map was first introduced by Henrik Wann Jensen. Photon mapping is a technique which uses a backwards ray-tracing pre-processing step to render refractive and reflective caustics realistically. This means that mirrors can reflect light rays and lenses can focus light. Photon mapping works by shooting packets of light (photons) from light sources into the scene. The photons are directed towards specific objects. When a photon hits an object after passing through (or bouncing off of) the target object, the ray intersection is stored in memory. This data is later used to estimate the amount of light contributed by reflective and refractive caustics. I wrote a paper about about this for my directed study. The paper is called Simulating Reflective and Refractive Caustics in POV-Ray Using a Photon Map, and you can download it in zipped postscript format here (size: 802 KB). Current Limitations Photon mapping can require a significant amount of memory. Examples
Using Photon Mapping in Your Scene To use photon mapping in your scene, you need to provide POV with two pieces of information. First, you need to specify details about photon gathering and storage. Second, you need to specify which objects receive photons, which lights shoot photons, and how close the photons should be spaced. Global Settings To specify photon gathering and storage options you need to add a photons block to the global_settings section of your scene. Heres an example: #declare phd=1; global_settings{ photons{ gather 20, 100 radius 0.1*phd, 2, 2, 0.1*phd autostop 0 jitter .4 expand_thresholds 0.2, 40 } } global_photon_block :== photons { gather <min_gather>, <max_gather> radius <gather_radius>, <gather_count> [, <expand_step>] [autostop <autostop_percent>] [jitter <jitter_amount>] [expand_thresholds <percent_increase>, <expand_min>] [max_trace_level <photon_trace_level>] [adc_bailout <photon_adc_bailout>] } The keyword gather allows you to specify how many photons are gathered at each point during the regular rendering step. The first number (20 in this example) is the minimum number to gather, while the second number (100 here) is the maximum number to gather. These are good values and you should only use different ones if you know what youre doing. See the advanced options section for more information. The keyword radius specifies the search radius for photons. When searching for photons, the system finds all photons within this search radius and has to sort through them to find only the closest ones. Thus, if the radius is too large, the render will be very slow, since the system has to sift through lots of photons to get the ones it needs. However, if the radius is to small, the system will not find enough photons and the image will look splotchy. The variable "phd" is used here to allow the user to quickly change the overall quality of the photon mapping used. More on this later. The other values following radius are explained later. jitter specifies the amount of jitter used in the sampling of light rays in the pre-processing step. The default value is good and usually does not need to be changed. Both autostop and expand_thresholds will be explained later. Shooting Photons at an Object To shoot photons at an object, you need to tell POV that the object receives photons. To do this, create a photons block within the object. Here is an example: object{ MyObject photons { separation 0.02*phd refraction on reflection on ignore_photons } } object_photon_block :== photons{ [separation <separation_distance>] [refraction on|off] [reflection on|off] [ignore_photons] } In this example, the object both reflects and refracts photons. Either of these options could be turned off (by specifying reflection off, for example). By using this, you can have an object with a reflective finish which does not reflect photons for speed and memory reasons. The density of the photons is specified using the separation keyword. The number after separation is the spacial separation of photons at the center of the objects bounding box. The photons are actually shot using a spiral pattern with uniform angular spacing, but this angular spacing is difficult to estimate, and therefore is computed internally from the spacial spacing specified by separation. The "phd" variable is used here again. As you can guess, the separation of photons and gather radius are directly related. As long as both are kept in proper proportion, they can be scaled up and down to quickly change the total number of photons used. This is very useful for creating test renders and also for determining the correct ratio of separation and gather radius. Note: Photons will not be shot at an object unless you specify a positive separation distance. Simply turning refraction on will not suffice. Photons and Light Sources Sometimes, you want photons to be shot from one light source and not another. In that case, you can turn photons on for an object, but specify "photons {reflection off refraction off}" in the light sources definition. You can also turn off only reflection or only refraction for any light source. Finally, starting with UVPov 6.1, photons interact fully with media. This means that volumetric photons are stored in scattering media. This is enabled by using a max_media_steps (explained below) greater than zero. To store photons in media, POV deposits photons as it steps through the media during the photon-tracing phase of the render. It will space photons based on the separation setting for the current object. However, if you want the spacing in this third dimension to be, for example, twice the spacing in the other two dimensions, you can put "media_spacing_factor 2" in the photons section of global_settings. Sometimes, however, if a section of media is very large, using these settings could create a large number of photons very fast and overload memory. Therefore, you can specify a max_media_steps value. This determines the maximum number of steps that POV will take through the media as it traces photons, and thus specifies the maximum number of photons that will be placed in the media for each photon ray that passes through the media. The default is zero, which disables photons in media. A setting of 100 will probably work for most scenes. You can put ignore_photons into media to make that media ignore photons. Photons will neither be deposited nor gathered in a media that is ignoring them. Photons will also not be gathered nor deposited in non-scattering media. However, if multiple medias exist in the same space, and at least one does not ignore photons and is scattering, then photons will be deposited in that interval and will be gathered for use with all media in that interval. Important! These options will probably change in the future. I will probably do the following:
I made an object with IOR 1.0 and the shadows look weird. Why? If the borders of your shadows look odd when using photon mapping, dont be alarmed. This is an unfortunate side-effect of the method. If you increase the density of photons (by decreasing spacing and gather radius) you will notice the problem diminish. I suggest not using photons if your object does not cause much refraction (such as with a window pane or other flat piece of glass or any objects with an IOR very close to 1.0).
My scene takes forever to render. Why? When POV-Ray builds the photon maps, it continually displays in the status bar the number of photons that have been shot. Is POV-Ray stuck in this step and does it keep shooting lots and lots of photons? yes
no
My scene has polka dots but renders really quickly. Why? You need to increase the density of the photons by decreasing the separation between them. If you already have plenty of photons (more than 50,000), try increasing the gather radius.
Adding photons slowed down my scene a lot, and I see polka dots. Why? This is usually caused by having both high- and low- density photons in the same scene. The low density ones cause polka dots, while the high density ones slow down the scene. It is usually best if the all photons are on the same order of magnitude for spacing and brightness. Be careful if you are shooting photons objects close to and far from a light source. The separation keyword specifies the separation at the target object, but the gathering step is concerned with separation at the photons final destinations. The target object usually focuses or diverges the photons, so their separation will change depending on distances in the scene.
I added photons, but I dont see any caustics. Why? When POV-Ray builds the photon maps, it continually displays in the status bar the number of photons that have been shot. Where any photons shot? no
yes
The base of my glass object is really bright. Why? Use ignore_photons with that object.
Will area lights work with photon mapping? Photons do work with area lights. However, normally photon mapping ignores all area light options and treats all light sources as point lights. If you would like photon mapping to use your area light options, you must specify the "area_light" keyword within the photons{} block in your light source's code. Doing this will not increase the number of photons shot by the light source, but it might cause regular patterns to show up in the rendered caustics (possibly splotchiness).
Use a variable to link the gather radius and photon separation, such as the variable "phd" used in the docs. Use ignore_photons in objects that photons do not hit. Just put "photons{ignore_photons}" in the objects definition. Use ignore_photons in glass objects. Use autostop unless your object has a hole in the middle. Advanced Techniques Autostop
Normally, POV does not stop shooting photons until the target objects entire bounding box has been thoroughly covered. Sometimes, however, an object is much smaller than its bounding box. At these times, we want to stop shooting if we do a complete circle in the spiral without hitting the object. Unfortunately, some objects (such as copper rings), have holes in the middle. Since we start shooting at the middle of the object, the photons just go through the hole in the middle, thus fooling the system into thinking that it is done. To avoid this, the autostop keyword lets you specify how far the system must go before this auto-stopping feature kicks in. The value specified is a percentage of the object's bounding box. Valid values are 0 through 100 (0% through 100%). POV will continue to shoot photons until the spiral has exceeded this value or the bounding box is completely covered. If a complete circle of photons fails to hit the target object after the spiral has passed the autostop threshold, POV will then stop shooting photons. Note: If the light source is within the object's bounding box, the photons are shot in all directions from the light source. Adaptive Search Radius Many scenes contain some areas with photons packed closely together and some areas where the photons are spaced far apart. This can cause problems, since you must specify a gather radius which always gathers enough, but not too many, photons. The solution is the adaptive search radius. The gather keyword controls both the minimum and maximum number of photons to be gathered. If the minimum number of photons is not found in the original search radius, we can expand that radius and search again. The radius keyword allows you to specify how many total times to search (gather_count) and how far to expand each time (expand_step). Using the adaptive search radius correctly can both decrease the amount of time it takes to render the image, and sharpen the borders in the caustic patterns. Usually, a gather_count of 2 is good (the initial search plus one expansion). Using too many expansions can slow down the render in areas with no photons, since the system searches, finds nothing, expands the radius, and searches again. For a good expand_step, simply use the initial gather radius, so that the radius is doubled for the expansion. Sometimes this adaptive search technique can create unwanted artifacts at borders (see "Simulating Reflective and Refractive Caustics in POV-Ray Using a Photon Map", Nathan Kopp, 1999). To remove these artifacts, a few thresholds are used, which can be specified by expand_thresholds. For example, if expanding the radius increases the estimated density of photons by too much (percent_increase, default is 20%, or 0.2), the expanded search is discarded and the old search is used instead. However, if too few photons are gathered in the expanded search (expand_min, default is 40), the new search will be used always, even if it means more than a 20% increase in photon density. Dispersion Daren Scott Wilsons dispersion patch has been incorporated into the photon mapping patch. To use it with photons, you need to specify a color_map in your light source. The color_map will override the lights color (although you still need to specify the color of the light). The color_map determines the color spectrum for that light source. I have created a macro, "create_spectrum", which creates a color_map for use with lights. This macro is based on Mr. Wilsons dispersion patch. See the demo scene "prism" for this macro. Saving and Loading Photon Maps It is possible to save and load photon maps to speed up rendering. The photon map itself is view-independent, so if you want to animate a scene that contains photons and you know the photon map will not change during the animation, you can save it on the first frame and then load it for all subsequent frames. To save the photon map, put the line Loading the photon map is the same, but with load_file instead of save_file. You cannot both load and save a photon map in the POV file. If you load the photon map, it will load all of the photons as well as the range_divider value. No photons will be shot if the map is loaded from a file. All other options (such as gather radius) must still be specified in the POV scene file and are not loaded with the photon map. This page was last updated November 05, 1999. If you have any comments, please email me. My email address is Nathan at Kopp dot Com. |