Skip to content

Cycles Light and Shadow Linking

Data Layout

Emissive objects are assigned a Collection of light receivers and shadow blockers. The relation goes in this direction to make it easy to add light linking in shots with their own lights, without having to override the objects or materials in the scene. USD uses a similar data layout, which should make future interop easier. Note that this is different than the previous "light groups" in Blender Internal where the relation was in the other direction, and part of materials.

As part of Blender dependency graph building, this relation is inverted and converted to bitmasks for efficient rendering. Each unique set of lights or shadow blockers used by a receiver is assigned a bit. Every light and shadow blocker is then given a bitmask indicating which sets it is part of. These bitmask are exported to Cycles, and at render this then means a simple bitmask test can determine if one object should influence another.

Light Linking

The naive implementation of light linking would just be to sample lights as usual, and then accept or reject samples. However such rejection sampling is noisy.

For the light tree, a specialized light tree is built for every light set, containing just the lights in the set. For reduced memory usage and faster build times, mesh instances and identical subtrees are shared between light trees.

Shadow Linking

For shadow linking, a subset of objects should be skipped as part of shadow ray intersection with a bitmask test. For next event estimation this can simply be done as part of the filter for shadow ray intersection.

However for multiple importance sampling with BSDF samples it is more complicated. In Cycles the indirect light ray is used both for indirect light and forward direct light estimation, reducing the number of rays to be traced. However with shadow linking the set of objects to intersect is not the same, and for that reason an additional shadow ray is traced. It works as follows:

  • shade_surface kernel samples the BSDF and sets up an indirect light ray.
  • If shadow linking is used for the object, the intersect_dedicated_light kernel is run to find an intersection with a light along the ray direction. If multiple are found, one is light is picked at random.
  • If an intersection is found, shade_dedicated_light evaluates the light shader and creates a new shadow path state.
  • The shadow path is then evaluated just like one generated by next event estimation.