Imitating Reflective Caustics in POV-Ray

Every now and then there is a question on comp.graphics.rendering.raytracing about light beams not reflecting from mirrors. So why don't light beams reflect off mirrors and what to do to make them appear as if they did?

Note: This page describes one workaround for a special case when using the official distribution of POV-Ray. For a more complete solution, try photon mapping by Nathan Kopp in MegaPov.

Reflected spotlight

No reflectionWhen a spotlight is aimed at a nonreflective surface, everything looks correct. (Note: Strong media scattering used to make the light visible.)

Light not reflectingWhen the floor is turned reflective, mirror images of the objects and media above the floor plane become visible. However the light emitted by the spotlight doesn't reflect up from the floor and illuminate the wall.

This occurs because of the way POV works. If the direct (not reflected or refracted) lighting needs to be calculated at a given point, the ray tracer can check whether there are any obstacles on the segments of lines connecting the point and each of the light sources in the scene. If a ray of light doesn't get reflected or refracted, its passage from the light source to the lit surface is a segment of line.

Discovering the possible paths of reflected or refracted rays from a light source to a given point is not as straigthforward and is not implemented in POV, although POV provides a simplified implementation of refractive caustics that occur in the shadow cast by a refractive object. (See section 4.6.5 of the POV-Ray 3.1 documentation.)

Light coming through the floorThere is a way to work around this problem if the reflecting surface is planar and there is plenty of space behind it.

A ray of light doesn't carry information of its origin. When a ray of light reflected from a planar mirror is perceived, it appears as if it had come from a source behind the mirror. The unreal light source from where the rays appear to be coming is on the same normal line of the planar mirror as the real light source. Both are at the same distance from the mirror, but on different sides of the mirror.

So the solution is to place another light source at the point from where the reflected rays should come. The easiest way to do this is to place the mirroring surface on a plane refined by two of the coordinate axes. In this example the floor is on the xz-plane. Then making the secondary light source is only a matter of scaling the coordinates of the third axis by -1. In this case scale <1,-1,1>. (The picture shows only the mirrored light.)

Usually the mirror would block the light coming behind it. To let the light through the mirror object modifier no_shadow needs to be added to the definition of the object. The modifier no_shadow does not affect the object's ability of being lit or having shadows cast onto it. The modifier only prevents the object from blocking lighting rays. (Note: The light coming from below the floor does not illuminate visible side the floor plane.)

Both lightsNow the result looks like the light was reflected from the floor. The secondary light can be made less bright when the mirror is not supposed to be perfect. (Here the primary light is color rgb 1 and the secondary light is color rgb .5.)

Blocking the primary lightBut something is still wrong. If the primary light is blocked, the reflect light is unaffected.

Final The solution is make mirrored copies of the objects that may possibly block the light. It is easier to make copies of all the objects than to select only the ones that are needed. The copies of opaque objects don't need to have any texturing. They can be just as well have pigment{color rgb 0} to reduce parsing time.

What's really thereHere you can see how the scene works. As stated above, the easiest way is placing the mirror on a plane defined by two of the coordinate axes. If the mirror is located elsewhere objects can be rotated and translated so that the can be mirrored about such plane and then translated and rotated back. Alternatively a matrix can be used. (Matrices are out of the scope of this document.)

Here is an animation of the result (in the WebM format):

Related files

See also for answers to other very frequently asked POV related questions