Page MenuHome

[Proof of Concept] Cycles: add support for light path expressions
Needs ReviewPublic

Authored by Kévin Dietrich (kevindietrich) on Sep 14 2022, 4:38 PM.
Tokens
"Like" token, awarded by 1D_Inc."Love" token, awarded by lordodin."Love" token, awarded by OcularEvolution."Burninate" token, awarded by ktdfly."Love" token, awarded by kursadk."Love" token, awarded by hadrien."Like" token, awarded by AlexeyAdamitsky."The World Burns" token, awarded by Peine_Perdue."Love" token, awarded by Jules."100" token, awarded by DerivedC."Love" token, awarded by mistaed."Love" token, awarded by LeoYfver."Party Time" token, awarded by irfan.
This revision needs review, but there are no reviewers specified.

Details

Reviewers
None
Summary
NOTE: this is uploaded only for reference and discussion.

This proof of concept attempts to add support for light path expressions (LPE)
for creating custom AOVs in Cycles.

On the Blender side, LPEs are defined as an extra AOV type, although they
could be separated in their own list. I am not attached to the idea, it was
just faster to implement.

On the Cycles side, LPEs are represented also as a specific AOV pass, although
they are semantically the same as color AOV passes for now.

Compilation

LPES are compiled using the OSL library. The automata is then converted and
stored into 3 DeviceScene arrays:

  • light_path_aovs which holds the active AOVs for a given state
  • light_path_states which holds the various states the automata can be in
  • light_path_transitions which holds the transitions between states

This conversion was originally to support LPE tags (e.g. `C.*<L'some_tag'>) so
that I didn't have to bother with strings in the kernel. Tags are then simply
converted to a unique integer. This effectively makes the code GPU friendly, I
could verify it all works with OptiX.

In order to convert the automata to device arrays, I had to copy the source
code from OSL so that I could add some accessors to some of the classes
(maybe we could use a patch instead). This code is in the cycles/lpe folder.

Automata update

Each ray keeps track of its light path state, via a new lpe_state field
in IntegratorState. Shadow rays also have a lpe_state which is inherited
from the parent ray. This ensures that direct light contribution is
properly added to the AOV at each bounce.

Initially, when creating the ray from the camera, a camera event is sent.
Then at each bounce, a proper event is sent based on the path label.
When BVH traversal ends on the background, or light, or emissive object,
a final event is sent.

For emitting an event at each bounce, I initially thought of doing it in
path_state_next as this centralizes some logic regarding bounces. However,
direct lighting contribution was missing. Apparently this was caused by the
light BSDF evaluation which happens before the surface BSDF evaluation. This
is not problematic on its own, except that the light BSDF evaluation routine
also directly sets up the shadow ray which is supposed to inherit the light
path state, but this state has not been updated yet based on the path label
as this needs the surface BSDF to be evaluated first. Therefore, the shadow
ray does not have a valid state, and we can not accumulate the light into
the right AOVs. I did a quick hack to fix this by moving the light
evaluation after the surface evalution. This breaks all the unit tests, but
the path state seems to be properly updated. This would need to be refactored
some way.

For SSS, a transmission diffuse (<TD.>) event is emitted. I am not really
sure where is the best place to do this, and at what time to emit such events.
This is done in subsurface_bounce at the moment. Indirect passes for this do
not work.

For volumes, events for scattering and emission are also emitted before
accumulating the render buffers.

For both SSS and volumes, this is mostly ad hoc.

Light accumulation

Every time we accumulate light contribution into the render buffers, we
iterate over the list of active AOVs for the current light path state.
I noticed that a "beauty" LPE pass (C.*) is brighter than the regular
combined pass. Either there is some overaccumulation, or I am missing
some clamping. This was noticed before the light evaluation hack explained
above.

All in all, I put the accumulation routines where I thought it would make
sense given my limited understanding of this code.

Light passes

LPEs can be used for some light passes. At least indirect transmission seems
to work. Although, compared to the vanilla indirect transmission pass, the
LPE one has anti-aliasing (see below). Other light passes might not really
be achievable (like diffuse direct) as LPEs also contain the albedo. As
OSL allows for extending the automata with custom events, I added one for
albedo (using 'A' like in Arnold), however, this is not used in the kernel
yet. We could also have custom events for the built-in light passes.

LPE tags

LPE tags are defined as a custom Cycles property and only work on objects
(including lights). We could use the object name, or the light group name,
or even the collection name instead. Effectively, tagging is a generalization
of light groups. Tags could also be used to discriminate rays hitting materials.
Some design would be needed here.

Tests

  • Light grouping (using LPE tags):
C.*<L'bleu'>C.*<L'orange'>C.*<L'spot'>Beauty C.*Beauty minus sum of the others

As the difference (last image) is black, I guess this works fine.

  • Indirect transmission pass
C<TS>.*TransInd

The LPE one looks a bit brighter, and has anti-aliasing.

  • A more complicated case, where refracted diffuse rays are put in the diffuse pass:
Direct Diffuse C<RD>[<L.>OB]Direct Diffuse + Refracted C<TS>*<RD>[<L.>OB]

The idea comes from: http://julius-ihle.de/?p=2619

  • Simple direct + indirect passes for diffuse reflection:
Dir C<RD>[LOB]Ind C<RD>[DGS].*Combined C<RD>.*Combined - (Dir + Ind)

The difference is not black, either the expression is off, or there is bug, or both.

TODOs (non-exhaustive)

  • properly handle alpha/transparency when writing to buffers
  • handle "straight" events
  • implement albedo event
  • allow writing to float only images
  • fix the light/surface evaluation order
  • use LPEs for light groups, and potentially other built-in AOVs
  • find a good approach for LPE tags
  • if possible, detect kernel features based on expressions
  • document the expressions, examples for common expressions

Some ideas from T72293: Refactor AOV writing in Cycles kernel seem related.

Diff Detail

Repository
rB Blender
Branch
cycles_lpe_wip (branched from master)
Build Status
Buildable 23759
Build 23759: arc lint + arc unit

Event Timeline

Kévin Dietrich (kevindietrich) requested review of this revision.Sep 14 2022, 4:38 PM
Kévin Dietrich (kevindietrich) created this revision.