Filtering for Specific Events

Each time a light ray interacts with something in a scene, this is called an "event". This can be when a light ray bounces off the surface of an object, refracts into or out of a transparent/translucent object, or undergoes scattering within an object. An LPE describes a specific sequence, or set of sequences, of these events between the light and the eye.

We will look at how to use the LPE grammar to filter light paths down into very specific subsets of events. Followed by a worked example to show a potential use case.

Example Scene

We will use the sample scene shown below to demonstrate LPE filtering:

To begin, we can filter by the event type - reflection (R), transmission (T), or volumetric (V). The following LPE will show reflection events only:

L .* R E

The .* term allows any number of arbitrary events between the light source and the final two events in the LPE (see the Isolating Specific Lights article). The final two terms (R E) will then capture only those rays which undergo a reflection event immediately before hitting the eye. It may be more intuitive to reverse the LPE and think of it in terms of camera rays. The resulting image looks like this:

As you can see, the glass cube becomes entirely opaque in this image as we only see the light rays which reflect from its surface and none of the rays which pass through direct to the camera. However, note that rays which pass through the glass and then reflect off other surfaces before hitting the camera are still captured, such the caustic pattern to the right of the cube resulting from the point light on the left. Note also that the cone and the tube look subtly different. We still see the diffuse reflection from the surfaces of these objects, but none of the light that is filtering through them. We can see all this transmitted light by instead filtering for transmission events in the same way:

L .* T E

In this case we get the following image:

The wax material applied to the tube uses subsurface scattering (SSS) to simulate light being bounced around and scattered within the body of the material. This is a volumetric effect, but note that the equivalent LPE for volumetric events (L .* V E) will actually generate an entirely black image. This is because no volumetric events can happen immediately before the eye event in this scene. Light rays must first leave the body of the tube, which is a transmission event. In order for this LPE to capture any rays, the camera would need to be placed within the scattering volume itself. However, we can capture the scattered light from the wax material by specifying a volumetric event followed by a transmission event like this:

L .* V T E

This will give the following image:

NOTE: L .* V T E is a subset of L .* T E in that the latter captures all of the same light paths that the former captures. Concurrently rendering multiple LPEs that contain overlapping paths can lead to performance issues and increased memory usage. You should try to construct LPEs that do not overlap if they are to be rendered concurrently. If you require several different images that contain repeated light paths it may be better to composite these together in post production from more restricted component LPEs.

It is also possible to filter by scattering mode. This describes if the scattering is a perfectly specular/mirror event (S), an entirely diffuse/Lambertian event (D), or a "glossy" event which is somewhere inbetween (G). We can use this LPE to filter for diffuse events:

L .* D E

Which gives this image:

The equivalent "specular" LPE will generate this image:

Notice that this captures both the reflection and transmission events from the glass cube, as both are specular. Also we can see that the transmission rays leaving the body of the wax tube are also specular in nature, despite the fact that surface reflections are not. The "glossy" LPE produces this image:

This captures the glossy reflections from the surface of the teapot, but also the "velvet" ground plane which is not entirely diffuse.

NOTE: The previous three "mode" LPEs are exactly equivalent to using the Diffuse, Specular, and Glossy Render Elements.

As well as filtering by the type or mode of the event, you can also add limits to the number of events the LPE will capture. This can be useful for capturing "direct" and "indirect" lighting for example. The following LPE will capture "direct" lighting only:

L . E

This will capture rays which undergo a single event (of any type) between the light and the eye, i.e. light rays that reflect directly off some surface into the camera. This gives the following image:

Note that the LPE specifies exactly one interaction between the light and the eye. This means that if there are any visible light sources in the scene then the rays which travel directly from the light to the eye will not be captured. In order to capture these rays as well, use the following LPE:

L .? E

Where the ? operator denotes "0 or 1 of the previous interaction".

To capture "indirect" light only, you can use the following LPE:

L .{2} E

This specifies that there must be exactly two interactions between the light and the eye. This will exclude the "direct" rays that the previous LPE captured, but will now show rays which bounce off one surface and onto another, before then bouncing into the eye. This is the resulting image:

This LPE will only capture one "bounce" of light and it may be preferable to capture indirect light that results from any arbitrary number of bounces. To do this, you can replace the {2} term with {2, n}, where 2 is the minimum number of bounces and n is the maximum number. If there is no upper limit (i.e. "two or more"), then you can omit the second number and instead use {2,}. The following LPE will capture all rays with 2 or more events between the light and the eye:

L .{2,} E

Note that ^(L .? E) is an equivalent way of writing this LPE. Either will give this image:

A potentially unexpected effect of this LPE is the transmission we are now seeing through the cube, cone and tube which may not be wanted for an "indirect" render. To remove this, the LPE can be filtered further by specifying that the final event before the eye must not be a transmission event:

L .{1,} [^T] E

Note that the arbitrary interactions has been dropped from "2 or more" to "1 or more". This is because the [^T] term is not optional and specifies an extra event in the light path. If we did not do this, the overall LPE would require 3 or more events between the light and the eye and would not capture one bounce indirect light. As there is a specific operator for "one or more" (+), we can write the LPE like this:

L .+ [^T] E

Either LPE will give us this image:

Glass Cube Worked Example

This worked example shows how we can use LPEs to generate the required layers so that we can add a colored tint to the glass cube in post production. This example also makes use of handles to isolate the cube geometry, which you can read more about in the Isolating Specific Geometry article. In that article, there is a similar example about recoloring a teapot. In that case we needed only two layers: a "teapot" and an "everything else" layer. We will start by trying the same thing here, using this LPE to generate the cube layer:

L .* 'Cube' E

And the negation of this to generate everything else:

^(L .* 'Cube' E)

These LPEs will generate the following two images respectively:

However, as we are now dealing with a transparent object, this case is a little more complicated than we saw with the teapot and these two images alone will not be sufficient. First of all, if we apply a color tint to the "cube only" layer then this will color everything in the image, including the surface reflections on the cube. If you look at real life tinted glass then you will see that the color of the glass only affects the transmitted light through the glass, while the reflections from the surface of the glass will remain uncolored. Therefore we will need to split this layer into two more layers, showing only the reflected and only the transmitted light, using these two LPEs:

L .* <R.'Cube'> E

L .* <T.'Cube'> E

Which will give the following two images:

There is also a problem with the "everything else" layer. This is showing caustic patterns on the ground plane caused by light that is refracted through the glass cube. If the glass is tinted then these caustics would also be tinted the same color, so we also need to separate these out into their own layer. The following LPE will do this:

L .* <T.'Cube'> .* [^<T.'Cube'>] E

With this LPE we are capturing all rays which pass through the cube at least once, with the caveat that the final event before the eye cannot be a transmission event associated with the cube. This prevents us recapturing the direct transmitted light, already captured in one of the above layers. This is the resulting image:

The final step is to generate an "everything else" layer which will omit these caustic patterns as well as any direct rays from the cube. The following LPE will do this:

^(L .* <T.'Cube'> .* E) & ^(L .* 'Cube' E)

This LPE is essentially a negation of the LPE used to generate the caustic patterns, and (&) an extra filter to remove any direct reflections or transmissions from the cube to the camera. Note that we can remove the [^<T.'Cube'>] term from the first part of the LPE as the second part of the LPE is already taking care of these rays, though there is no harm in leaving the term in place. The image generated by this LPE looks like this:

So we now have the final four layers we will need, generated with these LPEs:

Reflections from the surface of the cube: L .* <R.'Cube'> E
Direct transmitted light through the cube: L .* <T.'Cube'> E
Caustics from light transmitted through the cube:   L .* <T.'Cube'> .* [^<T.'Cube'>] E
Everything else: ^(L .* <T.'Cube'> .* E) & ^(L .* 'Cube' E)

The elements that do not need to be recolored (reflections and "everything else") can be composited together into one layer:

The elements that need to be recolored (transmission and caustics) can also be composited together:

NOTE: Breaking the render down into four layers is useful for illustrating the considerations we need to take into account, but now that we have gone through the process and determined the final two layers we need, we can craft LPEs to generate these layers directly; in both cases it simplifies the LPE considerably. For the "transmission + caustics" layer we can just remove the final [^<T.'Cube'>] term from the caustics LPE to capture the direct transmission as well:

L .* <T.'Cube'> .* E

For the "everything else + reflections" layer, we can remove the final ^(L .* 'Cube' E) term from the "everything else" LPE to also capture the surface reflections (we will not capture the direct transmission because the first term already disallows this) :

^(L .* <T.'Cube'> .* E)

The tint can now be applied to the transmission and caustics layer, and the final composite will show realistic colored glass:

The color of the glass can then be changed easily without needing to re-render:

Page Last Edited: