Shadow catcher
A shadow catcher is stand-in geometry for a surface in the live-action plate (a floor, a table, a wall). It is never in the final image itself. It gathers what the CG does to the plate: shadows, bounce light, reflections and the light of CG lamps. Moray writes those as raw passes for Nuke, following Arnold, RenderMan and V-Ray conventions, and with Film Transparent it also holds the catcher out of Combined, as Cycles does.
Set up
- Model the stand-in geometry and give it a material close to the plate surface (a rough diffuse for a floor, glossy or mirror for a reflective one).
- Object Properties > Moray > Shadow Catcher. An object already marked as a shadow catcher in Cycles is honoured too.
- Decide which lights are already in the plate. A light with Plate Light (Shadow Catcher) on (Object Properties > Moray on the light) is part of the plate: its shadows are what the passes measure. Blender ticks this on new lights. Untick it for CG-only lights, such as a lamp that exists only in CG; their light on the catcher goes to the CGLight pass instead of into the shadow. The World is always a plate light. Emissive meshes are always CG.
- Optional, next to Shadow Catcher (scene-wide):
- Catch Indirect (on): CG bounce and reflections of CG objects go into the held-out Combined, as in Cycles.
- Indirect Shadows (on): CG objects also block bounce light between catcher surfaces and what a glossy or mirror catcher reflects (RenderMan / V-Ray style). It costs a few percent on catcher pixels.
- Turn on Film Transparent if you want Combined held out (see below). Moray does not show
Blender's Film panel yet: tick Render Properties > Film > Transparent while the scene is on
Cycles or EEVEE, or run
bpy.context.scene.render.film_transparent = Truein the Python console.
The passes are written only for view layers that contain a catcher.
Passes
All passes are raw scene-linear, like every Moray AOV.
| Pass | What it holds | Use |
|---|---|---|
| ShadowCatcherMask | Catcher coverage | Matte for the catcher area |
| ShadowCatcherShadow | Shadow density per channel: mask * (1 - Lit / Unoccluded) | Coloured shadow matte |
| ShadowCatcherLit | Plate light on the catcher, with CG shadows | Shadow ratio (numerator) |
| ShadowCatcherUnoccluded | Plate light on the catcher, without CG shadows | Shadow ratio (denominator) |
| ...LitDiffuse / ...UnoccludedDiffuse | Diffuse part of the pair | Grade the ground shadow |
| ...LitSpecular / ...UnoccludedSpecular | Glossy part of the pair | Grade the reflection occlusion |
ShadowCatcherLit_<group> / Unoccluded_<group> | One pair per light group | Shadow per light |
| ShadowCatcherLitIndirect / UnoccludedIndirect | Plate light bounced off another catcher surface | Bounce shadows (Indirect Shadows) |
| ShadowCatcherLitReflection / UnoccludedReflection | Plate seen in a glossy or mirror catcher | Reflection shadows (Indirect Shadows) |
| ShadowCatcherCGLight | Direct light of CG lights and emitters on the catcher | Add over the plate |
| ShadowCatcherIndirectCG | Bounce light from CG surfaces onto the catcher | Add over the plate |
| ShadowCatcherReflectionCG | Reflections of CG objects in the catcher | Add over the plate |
| ShadowCatcherIndirect | All bounce light on the catcher | Reference |
| ShadowCatcherReflection | All indirect reflection on the catcher | Reference |
| ShadowCatcher | Visibility of plate light samples | Simple shadow matte |
| ShadowDiff | Unoccluded - Lit | Arnold-style subtractive shadow |
With Indirect Shadows on, the Indirect and Reflection pairs are folded into the shadow ratio, ShadowCatcherShadow, ShadowDiff and the held-out alpha. The per-group pairs stay direct light only.
Light AOVs and light groups do not include the catcher's own shading: they add up to the held-out Combined minus the captured CG light.
Held-out Combined (Film Transparent)
With Film Transparent on, Combined is ready to go over the plate:
rgb = rgb * (1 - mask) + CGLight [+ IndirectCG + ReflectionCG with Catch Indirect]
alpha = alpha * (1 - mask) + mask * (1 - luminance(Lit / Unoccluded))
It is premultiplied, and on catcher pixels alpha carries only the shadow (Arnold's convention). F12 and the renderer's EXR both get it, so farm renders match. With Film Transparent off, Combined is left alone and only the passes are written.
Nuke recipes
Over (Cycles / Arnold style)
Combined over plate
The catcher pixels carry the shadow in alpha and the CG light in RGB. To grade the shadow, use ShadowCatcherShadow, or rebuild alpha from Lit / Unoccluded.
Multiply (RenderMan style), with a held-out or a plain beauty
plate * (1 - mask + mask * Lit / Unoccluded) + CGLight + ReflectionCG + IndirectCG
then the CG beauty over it.
- Divide per channel: Lit / Unoccluded keeps the shadow's colour (a blue sky fill under a yellow sun).
- The CG passes are already weighted by coverage. Do not multiply them by the mask.
- The held-out Combined already contains CGLight (and IndirectCG + ReflectionCG with Catch Indirect). If you merge it, add only the passes it lacks.
- Grade the ground and its reflection separately with the Diffuse and Specular pairs, or each
light with the
_<group>pairs.
Subtract (Arnold shadow_diff)
plate - ShadowDiff * k
A quick, gradeable darkening. ShadowDiff can go slightly negative in noise; clamp if needed.
Holdouts
Holdouts cut CG out of the image without a catcher: Blender's object Holdout (Object Properties > Visibility > Mask), the collection Holdout toggle in the Outliner, and the Holdout shader node. A held-out object is transparent to the camera (alpha 0) but still casts shadows, bounces light and shows in reflections. Holdouts work on the CPU and the GPU.
Limits
- Indirect Shadows covers one bounce off a catcher surface; light reaching the catcher by two or more catcher bounces is in neither half of the ratio.
- Bounce shadows do not pass through partly transparent surfaces, volumes or subsurface objects; a holdout counts as CG there.