Inverted Normal Studio

Sharp Stencil Shadows

Documentation for Sharp Stencil Shadows, a URP renderer feature for hard, pixel-exact stencil shadow volumes.

Performance

Home › Guides

Volume generation backends

Performance > Backend chooses where shadow volumes are generated:

Backend Behavior
Auto (default) GPU per caster where supported. Each unsupported caster falls back to CPU on its own.
CPU Burst jobs for every caster. No GPU volume state is kept.
GPU Same as Auto, and intended for inspecting fallback reasons. Unsupported casters still render on the CPU.

Both backends produce identical shadows and can run side by side. The GPU backend regenerates every changed volume in one batched dispatch, so its cost grows with the amount of changed geometry rather than the number of casters.

StencilShadowRendererFeature.FindActive()?.SetBackendMode(ShadowVolumeBackendMode.Cpu);

GPU fallback

A caster falls back to the CPU backend for one of these reasons, counted in debug statistics:

Reason Cause
ComputeUnsupported, IndirectUnsupported The device lacks compute shaders, vertex-shader buffer reads, or indirect drawing. OpenGL ES always uses the CPU backend.
ComputeShaderUnavailable The feature's compute shader is not assigned. Run the installer.
InvalidTopology The mesh has no usable topology.
BufferCapacityExceeded The combined GPU buffers would exceed the device's maximum buffer size.
MissingPositionAttribute, UnsupportedPositionLayout, VertexCountMismatch The vertex buffer layout can't be read on the GPU.
SourceBufferUnavailable The skinned or deformed vertex buffer isn't available this frame.
BufferAllocationFailed A GPU buffer could not be allocated.
OutputOverflow A guarded output overflow was detected (see below).

With Diagnostics on, a throttled asynchronous readback checks GPU output for overflow. An overflowing caster moves to the CPU and retries the GPU after a wait that doubles each time it overflows again.

What drives cost

  • Static casters and lights cost no generation. Only their volumes are drawn.
  • Moving, skinned, and GPU-deformed casters, and moving lights, regenerate their volumes each frame, once per light.
  • Screen coverage: stencil fill grows with the screen area volumes cover. Each caster's work is scissored to its screen area within the URP asset's Max Distance, which keeps distant casters from filling the screen when the light shines away from the camera.
  • Triangle count: volume size grows with caster triangles and silhouette edges. LOD Groups and meshes with Mesh LOD cast from the level each camera draws, so distant casters cost their simpler level's triangles (see LOD groups).
  • URP Lighting adds a depth prepass and a stencil pass per shadowed light. See Lights and Lighting Modes.
  • Transparent casters: Off is free, Uniform Opacity adds a few passes per caster, and Textured redraws the caster atlas each frame.
  • Discovery scans the scene every Discovery Refresh Interval seconds, the only regular source of managed allocations for static scenes.

Optimization guide

  • Casters: exclude objects that don't need shadows with Caster Layers or Cast Shadows > Off. Prefer low-poly, closed meshes for casters.
  • Backend: keep Auto unless profiling shows the GPU is the bottleneck. Many skinned or moving casters are usually cheaper on the GPU.
  • Shadow distance: lower the URP asset's Shadows > Max Distance to the range that needs shadows.
  • Lights: lower Max Shadowed Lights and limit Light Layers to the lights that need shadows.
  • Transparent casters: use Uniform Opacity or Off when textured shadows aren't needed. In Textured mode, see tuning the atlas.
  • Discovery: raise Discovery Refresh Interval and call ShadowCasterDiscovery.RequestRefresh() after spawning casters.

Mobile

Start from the Mobile Forward sample asset: Overlay mode, 80% render scale, main light only. Prefer Uniform Opacity or Off for transparent casters, and keep caster counts, screen coverage, and Max Distance modest. Devices without compute shaders use the CPU backend automatically.

Keep Local Light Transmittance off on mobile unless a scene needs it. Each point or spot light with transparent casters in reach renders its own screen-sized target and copies the part of the screen it reaches, which is memory-bandwidth heavy: on a Pixel 3, five such lights added about 18 ms per frame.

Profiler markers

All markers are under Sharp Stencil Shadows/:

Marker Work
Discovery Scene scans for casters
Record Per-camera main-thread preparation
Classify Per-camera classification of caster materials, while Transparent Casters Mode is not Off
CPU Bake, CPU Generate, CPU Upload CPU backend skinned baking, volume generation, and mesh upload
GPU Generate Batched GPU volume generation
Caster Atlas Depth, Coverage, Transmittance Caster atlas drawing, with Local Caster Atlas versions for point and spot lights
Caster Atlas Receivers, Local Caster Atlas Receivers Receiver sizing measurement
Stencil Raster Volume and composite drawing

Runtime statistics

StencilShadowRendererFeature.DebugStats reports caster counts per backend, GPU fallbacks by reason, generated vertices, atlas usage, and shadowed light counts. The demo scenes show these live. See Scripting API.