Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: wikit macro-replace (build 4280ad5-2021.10.08.115947) run by cwalker

...

Info

Hand-authoring LPE can be a tedious process and for artists it's not always desired to do these manually. This document aims to improve the artist's understanding and usage of LPE.

Understanding these concepts and applying them will make you a hero to many pipelines given the power and flexibility of the feature.

Table of Contents

In production it often becomes necessary to create non-physical effects and art-directed changes to your shot. Light Path Expressions (LPE) are a powerful way to collect and output specific light paths for alteration later.

...

Info

An excellent primer with useful visuals can be found in a tutorial video from Lollipop Shaders. Begin at Class 6 for the LPE introduction.

...

Carousel Image Slider
stretchfalse
dotsfalse
infinitefalse
sliderHeight300
arrowsfalse
labelsFilterlperefl
gutterSize2
slidesToScroll01
captionstrue


Code Block
Diffuse Reflection: lpe:C<RD>*[<L.>O]
Specular Reflection: lpe:C<RS>*[<L.>O]

...

Carousel Image Slider
stretchfalse
dotsfalse
infinitefalse
sliderHeight300
arrowsfalse
labelsFilterlpetrans
gutterSize2
slidesToScroll01
captionstrue

Code Block
Diffuse Transmission: lpe:C<TD>*[<L.>O]
Specular Transmission: lpe:C<TS>*[<L.>O]

...

Carousel Image Slider
stretchfalse
dotsfalse
infinitefalse
sliderHeight300
arrowsfalse
labelsFilterlpediff
gutterSize2
slidesToScroll01
captionstrue

A specular scene using iridescence and transmission (glass).

Carousel Image Slider
stretchfalse
dotsfalse
infinitefalse
sliderHeight300
arrowsfalse
labelsFilterlpespec
gutterSize2
slidesToScroll01
captionstrue

 

Now that we have some understanding of the main components, let's begin by looking at the parts used to organize an LPE

...

The caret ^ is used to exclude something. Sometimes your light path may have an event you want to avoid. In many cases this could even be an LPE group (explained later) you wish to omit. Let's say you want all the light paths exceptf or a couch except for a couch in a diffuse reflection pass, C<RD[^'couch']>*[<L.>O] will return everything except for the couch.

Shorthand

Above we are explicitly stating what we want using the tokens. We can use shorthand and some following examples will use it. I can substitute a . (period) for the events and types.

...

Carousel Image Slider
stretchfalse
dotsfalse
infinitefalse
sliderHeight300
arrowsfalse
labelsFilterlpebounce
gutterSize2
slidesToScroll01
captionstrue

The curly brackets can also take a range of values to render a set of bounces. Maybe you're only interested in collecting the effects of the 4th through 8th bounce? Or maybe you know where to begin or end but want the renderer to decide where that is.

...

Carousel Image Slider
stretchfalse
dotsfalse
infinitefalse
sliderHeight300
arrowsfalse
labelsFilterlpespefbounce
gutterSize2
slidesToScroll01
captionstrue

 

The Beauty Render

...

Code Block
lpe:C<[RT][DS]>*[<L.>O]

Camera to <[reflection OR transmission] OF [diffuse OR specular]> ALL light bounces TO [lights OR mesh/glow objects]

You can now understand each of the parts above and how specifying the right tokens (or even simple swapping them out) can give you the results you need for compositing a frame after making adjustments.

The above LPE can be used to output not only the beauty, but can be used to output something like the beauty of a particular light group, this is a very common "ask" by artists. Below we'll dig deeper into more advanced workflows.

Per Light LPE

For artists rendering complex stills, it might be important to separate lights and light groups to change contribution later instead of re-rendering or creating many wedge tests. For animation, per-light AOVs are much less common as complex VFX composites already have many layers on top of AOVs for those layers. Splitting this further into selected light passes can further multiply the number of passes a compositor will handle to adjust the beauty. This is possible and should your pipeline handle this extra set of data, LPE can provide the control you need.

In RenderMan for Maya we handle this using the lights drop down menu in the AOVs tab where you define your LPE Display Channels. But other software may require you manually insert the light groups.

First, you must specify which lights belong to which groups. This is done at the light shader level. You notice a string (text) field in the light parameters for an LPE Group. This is where you define your groups in plain text. For example, in the classic three-point lighting setup you have three lights or groups: key, fill, and rim lighting. You can specify this in the light shaders and then call these groups using the LPE syntax of a name in single quotes, like 'key' or 'fill'.

Code Block
lpe:C<[RT][DS]>*[<L.'key'>O]


Shorthand
lpe:C<..>*[<L.'key'>O]

The above LPE will render a beauty of the scene lit by the lights tagged as "key". Replacing 'key' with another group would render the other group as specified like 'rim' or maybe you need the HDRI as 'environment' separated into an AOV.

If you needed more than a single group, you could use the pipe to say "or" another group or groups.

Code Block
lpe:C<[RT][DS]>*[<L.('key'|'fill')>O]


Shorthand
lpe:C<..>*[<L.('key'|'fill')>O]

Of course you can also ask for other data from a path to a light group like indirect diffuse reflection (usually known as indirect lighting) for later scaling in compositing.

Code Block
lpe:C<RD>+[<L.('key'|'fill')>O]

Now you can output whatever you need based on light groups!

Per Object LPE

You can also render specific objects and effects. This is similar to the light groups but this is often found on a transform of an object, this LPE group tags these objects or collections for separation.

Imagine you have a particular thing you're trying to capture, you can do that with an LPE. You notice that in all the LPE we've been writing it looks like it can be done in 3 parts:

Code Block
[What I'm Rendering] [Light Bounce Paths] [Lights I'm Using]

So now let's render something specific. In the Cornell Box example we have a tall subsurface scatter rectangle in the back. I'll render it by itself.

Code Block
lpe:C<[RT][DS]'scatterCube'>.*[<L.>O]




Shorthand
lpe:C<..'scatterCube'>.*[<L.>O]

What I'm rendering is the tall rectangle and all the light that lands on it.

Image AddedImage Added

Now, let's render it and only the influence of light off the green wall to the right.

Code Block
lpe:C<[RT][DS]'scatterCube'>+<[RT][DS]'rightWall'>[<L.>O]


Shorthand
lpe:C<..'scatterCube'>+<..'rightWall'>[<L.>O]

So we're rendering the same cube but this time the light path has to exclusively include all the light bouncing off of and through the rightWall object. So our result is a very green object since we captured just the green wall's bounce light. You can see now how to separate light paths to get what you need to adjust for later compositing. I'm rendering the tall rectangle and all the light that lands on it after leaving the green wall.

Image AddedImage Added


Of course I can also exclude just the green wall. Maybe the green wall is generating noise, I can avoid those light paths by using the caret and a simple tweak of my LPE

Code Block
lpe:C<[RT][DS]'scatterCube'>+<[RT][DS][^'rightWall']>[<L.>O]


Shorthand
lpe:C<..'scatterCube'>+<..[^'rightWall']>[<L.>O]

Image AddedImage Added


The Importance of Naming

Naming your channels is important not just for pipeline reasons and readability, but because the Denoiser utility requires that you follow a naming convention in order to be denoised. Since the tool isn't psychic, it needs a hint as to what is inside the framebuffer/AOV and it uses the name to decide this. There are two main ways the Denoiser filters results, and the way triggered by a "diffuse" keyword is that the albedo is divided out before denoising happens, this is done to prevent texture smearing. So when naming your AOVs, keep that in mind knowing that you'll most likely want your results to be denoised. Below are the acceptable prefixes given again.


The pass images can be named anything else, but must have color channels named/prefixed as one of:

  • diffuse
  • specular
  • directdiffuse
  • directspecular
  • directDiffuse
  • directSpecular
  • indirectdiffuse
  • indirectspecular
  • indirectDiffuse
  • indirectSpecular

LPE Prefixes Explained

You may see other areas where another prefix is added to the LPE. This is typically for special handling and data.

  • unoccluded – returns unoccluded or unshadowed result. Using this before your LPE will result in no shadowing.
  • noclamp – returns unclamped result.
  • nothruput – does not apply thruput (throughput is the accumulative albedo of the objects hit by rays). Your results could be attenuated based on throughput of the light path. Using this means the full value is retained, useful for masks.
  • shadows – returns collected shadows. This relies on the shadow sample filters and additional buffers from the Holdout Workflow.
  • holdouts – returns only holdout light paths (light paths with one or more holdout events)
  • overwrite – instead of outputting the accumulated result, overwrite it. One example of using this is for the albedo output where we do not want an accumulated result. Otherwise your values may continue to accumulate light and be incorrect, for example, a pure red of 1,0,0 can become 6,0,0 and be incorrect.
  • noinfinitecheck – do not do any infinite check.

User Lobes

By default you've been seeing us use Diffuse and Specular lobes, but a User lobe can be built into a material for data purposes. These lobes are evaluated with the material but not output to a beauty as a lighting result. These lobes must be specified in an LPE to work, shorthand assumes only Diffuse or Specular substitutions. A useful example are the User Color and Position lobes of PxrSurface.