Photons
Home Up UV Mapping Patterns Meshes Radiosity Photons Misc. Changes Media

 

Contents

Overview
Examples
Using Photon Mapping in Your Scene
FAQ
Tips
Advanced Techniques

 

Overview

My 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.
Photon mapping can slow down the render (but not much more than an additional light source).

Examples

photons1.jpg (11891 bytes) This image shows reflective caustics from a sphere and a cylinder.   Both use an index of refraction of 1.2.  Also visible is a small amount of reflective caustics from the metal sphere, and also from the clear cylinder and sphere.
photons2.jpg (20639 bytes) Here we have three lenses and three light sources.  The middle lens has photon mapping turned off.  You can also see some reflective caustics from the brass box (some light reflects and hits the blue box, other light bounces through the nearest lens and is focused in the lower left corner of the image).
photons3.jpg (7448 bytes) This shows what happens when you mix Daren's dispersion patch with photon mapping.  Interesting, huh?  The current release version will not currently render this scene exactly as shown, since I've made some changes (but I'm working on it).

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. Here’s 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 you’re 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 object’s 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 source’s definition. You can also turn off only reflection or only refraction for any light source.

Photons and Media

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:

  1. Change media_spacing_factor to affect all three dimensions
  2. Include a media_gather variable to specify the media gather radius

 

FAQ

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, don’t 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

If you are shooting photons at an infinite object (like a plane), then you should expect this. Either be patient or do not shoot photons at infinite objects.

Are you shooting objects at a CSG difference? Sometimes POV-Ray does a bad job creating bounding boxes for these objects. And since photons are shot at the bounding box, you could get bad results. Try manually bounding the object. You can also try the autostop feature (try "autostop 0"). See the docs for more info on autostop.

no

Does your scene have lots of glass? Glass is slow and you need to be patient.

Does the render slow down at in places that have lots of photons (bright caustics)? If so, you should decrease gather radius and/or use adaptive search radius.

 

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 don’t 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

If your object has a hole in the middle, do not use the autostop feature.

If your object does not have a hole in the middle, you can also try not using autostop, or you can bound your object manually.

Try decreasing the separation of photons.

yes

Where any photons stored (the number in parentheses in the status bar as POV shoots photons)?

no

Maybe they are getting shot

yes

The photons may be diverging more than you expect. They are probably there, but you can’t see them since they are spread out too much

 

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).

 

Tips

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 object’s definition.

Use ignore_photons in glass objects.

Use autostop unless your object has a hole in the middle.

Advanced Techniques

Autostop

shootph.jpg (12785 bytes)To understand the autostop option, you need to understand the way photons are shot from light sources. Photons are shot in a spiral pattern with uniform angular density. Imagine a sphere with a spiral starting at one of the poles and spiraling out in ever-increasing circles to the equator. Two angles are involved here. The first, phi, is the how far progress has been made in the current circle of the spiral. The second, theta, is how far we are from the pole to the equator. Now, imagine this sphere centered at the light source with the pole where the spiral starts pointed towards the center of the object receiving photons. Now, photons are shot out of the light in this spiral pattern.

Normally, POV does not stop shooting photons until the target object’s 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 Wilson’s 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 light’s 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. Wilson’s 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
    save_file "myfile.ph"
into the photons{ } block inside the global_settings section.

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.