Light Path Expressions for custom AOVs

Right now Cycles offers a fix small set of output light passes accessible in the View Layer tab. Our artists have expressed the need for more passes for complex compositing.
Do you plan to implement Light Path Expressions to handle arbitrary light passes ? Do you know if someone already started some development regarding this feature ?

Laurent, Ubisoft Animation Studio


Check this:

May be good to express this there, I think it’s related :slight_smile:


Thanks for the link !

It seems related indeed, however from what I understand of the description, it only handles AOVs defined by custom shading outputs in materials. I will try it to confirm that.

In the case of LPEs, an AOV would be defined by a regular expression identifying a subset of light paths, like CD+L identifying all diffuse-only paths. More information here:

I’m quite new to Cycles development but I no dev is planned or have been done for LPEs I might go for the dev myself, depending if our artists really need the feature for the production.
I already implemented it in our in-house renderer using LPE parsing utilities from OSL, but it was a CPU renderer only, I wonder how hard (and efficient) it would be to have LPEs in a GPU backend :confused:


I’m familiar with LPE’s from the old days with iRay :slight_smile: , they are super powerful, they are a bit hard to use for the artist because it requires some expression learning (obviously… :slight_smile: ) but they can be made more user friendly if we could have some useful presets ready to be used, and the option to configure custom expressions of course.

Regarding the GPU backend, according to the iRay devs in the old days, it was an efficient way to separate components for iRay since it was GPU only at first.

Could be awesome if you implement this with both, CPU and GPU, I think @brecht is the right person to talk to.

1 Like

There is no concrete plan or roadmap for adding LPE support to Cycles currently, but I think it would be useful functionality to have.

In my experience LPEs can be implemented quite efficiently and in a way that works well on the GPU. The state machine can be compiled on the CPU. The kernel just has to track the active state number, and update it following the state machine on every event. Whenever you accumulate light or albedo, you would then loop over an array of active AOVs for the current state.

Parsing of the expression into a state machine can be done with OSL, which can then be converted to a representation that works on the GPU.

If implemented well this can actually simplify the kernel side render pass code a bit, and handle light groups with the same logic.


Thank you for the insight to implement it on GPU :slight_smile: I will look deeper into Cycles source code in order to have a clear idea on how to integrate LPEs to it, I might come back here with questions.


did you find all information and were able to implement Light Path Expressions to handle arbitrary light passes ?


The problem with LPE’s IMO is they are super useful for developers (or say TD level users). Most artists don’t use them. Coming up with a nice UI to make them useful is another matter.

Not trying to say they SHOULDN’t be implemented, but it would be it might not be useful enough to many users to justify without the right UI

Agree they are most useful for technical users, but that’s reason enough for having them I think.

1 Like

It doesn’t look like anyone’s stated this explicitly, and I don’t know how long you’ve been using Blender, so maybe you don’t already know (apologies if you do). Cycles can use OSL, but only on the CPU. So you might be able to port your existing OSL code over to Cycles while you work on a more permanent solution.

Also, it might help you to look at the Light Linking patch produced by Tangent Animation way back in 2016. It isn’t exactly what you asked about but it is tangentially related.

Also, it’s so cool that Ubisoft is adopting Open Source software. Good luck with this!


Yes I noticed OSL can only be enabled for the CPU Kernel. However the LPE API of OSL is quite independent from the shading language compilation/execution part. As @brecht mentionned, the LPE state machine could be built on CPU before rendering and used on the GPU or CPU during rendering.

Thank you for the link to the patch by Tangent Animation, I will take a look. It’s not totally related but seeing how people integrate new features in the existing code base helps a lot :slight_smile:


I’m still getting used to the code base, but yeah I think I have enough information to start this kind of dev. I will work on an implementation during the next weeks.


I think this is a pretty neat feature, and I’m sure we can achieve a good UI to make it useful even for nont-techie users, like giving them some presets with the most common used AOV’s or similar things, but this may come after the feature is in place :slight_smile:

1 Like

Hey @c2ba how is this going? any news? :smiley:

No progress on my side with that, I was pretty busy with other unrelated things recently. I hope I’ll be able to dedicate some time to it soon.


No pressure :slight_smile: I just wanted to know the status.


1 Like

Hey @c2ba ow is this going? any news? :smiley:

Hi @Pipeliner :slight_smile:
Not a lot of progress since it is still not sure that we will need LPEs at Ubisoft Animation Studio, so I cannot really dedicate office hours to it :confused:

However I started working on it today on my free time, starting from this differential ⚙ D4837 Cycles: Add support for adding custom AOV render passes since it touches similar things.

For now I have extracted LPEs parsing/evaluation source code from OSL and removed its dependencies to other parts of OSL and OIIO (see here GitHub - Celeborn2BeAlive/LightPathExpressions: Light Path Expressions Library).

My next step is to experiment with it inside Cycles, using it for already existing passes (beauty, diffuse_direct, etc) to identify which parts of the source code I have to change and to check if the automata data structure should be changed to fit in Cycles.

After experiments my roadmap for the clean integration will be:

  • In the UI, add a panel “LPE” in the view layer tab from the properties editor (like the AOV panel added D4837), allowing to add LPEs with a name associated to it to define a new render pass. I think I will have to look at the compositing graph part also to have LPE passes as output of the Render Layers node.
  • Send user defined LPEs to Cycles and build the automata
  • Adapt the structure PathRadiance to store accumulations for each LPE
  • Use the automata during rendering to accumulate contributions based on LPE state during path tracing
  • Write accumulations to framebuffer
  • Check everything works correctly on the GPU and adapt the automata data structure if it’s not GPU friendly

Things I have to investigate:

  • Where to store LPEs and pass names ? I guess its in DNA but I need to get more familiar with the system.
  • Denoise of passes ? Is it done automatically for all passes of the framebuffer or should I do something ?
  • Provide the python API to add LPEs (maybe this will come naturally when I’ll look at the UI part)
  • About the LPE library code extracting from OSL, where should I put it ? “extern” directory with a C API ?
  • Should LPE automata also be used for already existing passes (diffuse_direct, diffuse_indirect, etc) or just for user defined LPEs ? It can simplify the source code, but maybe decrease performance, so I think profiling will be needed to take a decision on that.
  • LPEs (as defined by the OSL convention) support the usage of “tags” inside token. For example <‘L’.[‘light_1’|‘light_2’]> would match some event ending on a light with tag light_1 or light_2. The question is what to use to define the tags ? The obvious answer would be to use the name of the entity that is found during path tracing for a specific event. But maybe another properties added to objects would be better (something like “LpeTag”). It would permit to group some objects under a given LpeTag. But using names also allows to define groups by just using the ‘|’ operator. However I guess it might increase the size of the automata since more transitions are required. Maybe an hybrid solution is the best: Name by default, LpeTag if it exists on the object.

Awesome, at the very least you already started with it :slight_smile:

If you want something that you WILL NEED in Ubi Animation Studio FOR SURE it’s persistent data, to save up render time (if you will use Cycles) :grin:

1 Like

wow thank you very much for your detailed post! :blush: